// No copyright #include #include #include #include #define READ_CHUNK_SIZE 1024U static inline bool acg_stream_refill(struct acg_stream* s) { assert(NULL != s); FILE* fp = s->udata; assert(NULL != fp); uint8_t* const buf = s->buffer; uint64_t* const c = &s->cursor_bits; uint64_t* const size = &s->size_bytes; const uint64_t remain = *size - *c/8U; memmove(buf, &buf[*c/8U], remain); *c %= 8U; const uint64_t expect_size = READ_CHUNK_SIZE - remain; const uint64_t actual_size = fread(&buf[remain], 1U, expect_size, fp); *size = remain + actual_size; return true; } int main(int argc, char** argv) { if (argc != 2U) { fprintf(stderr, "invalid args\n"); return EXIT_FAILURE; } FILE* fp = fopen(argv[1], "rb"); if (NULL == fp) { fprintf(stderr, "failed to open: %s\n", argv[1]); return EXIT_FAILURE; } struct acg_stream s = { .buffer = (uint8_t[READ_CHUNK_SIZE]) {0U}, .udata = fp, }; uint64_t last_event_chunk_id = 0U; uint32_t indent = 0U; # define INDENT_PRINT(FMT, ...) \ printf("%*s" FMT "\n", indent, "" __VA_OPT__(,) __VA_ARGS__) while (true) { if (!acg_stream_refill(&s)) { fprintf(stderr, "failed to read: %s\n", argv[1]); return EXIT_FAILURE; } if (0U == s.size_bytes) { break; } uint64_t chunk_id; if (!acg_stream_read_uint(&s, &chunk_id, ACG_UNITBITS_CHUNK_ID)) { fprintf(stderr, "failed to read chunk id\n"); return EXIT_FAILURE; } const bool is_event_chunk = chunk_id >= ACG_CHUNK_BEGIN; if (is_event_chunk) { if (ACG_CHUNK_BEGIN == last_event_chunk_id) { ++indent; } else if (ACG_CHUNK_END == last_event_chunk_id) { --indent; } last_event_chunk_id = chunk_id; } switch (chunk_id) { case ACG_CHUNK_PAD: acg_stream_read_pad(&s); break; case ACG_CHUNK_BLOB: { uint64_t size; uint8_t* buf; if (!acg_stream_read_blob(&s, &size, &buf)) { fprintf(stderr, "failed to read BLOB in BLOB chunk\n"); return EXIT_FAILURE; } INDENT_PRINT("-BLOB: %.*s", (int) size, (const char*) buf); } break; case ACG_CHUNK_CTX: { uint64_t time; if (!acg_stream_read_uint(&s, &time, 64U)) { fprintf(stderr, "failed to read TIME in CTX chunk\n"); return EXIT_FAILURE; } uint64_t tid; if (!acg_stream_read_uint(&s, &tid, 16U)) { fprintf(stderr, "failed to read TID in CTX chunk\n"); return EXIT_FAILURE; } INDENT_PRINT("-CTX: TIME=%" PRIu64 " / TID=%" PRIx64, time, tid); } break; case ACG_CHUNK_LOC: { uint64_t size; uint8_t* buf; if (!acg_stream_read_blob(&s, &size, &buf)) { fprintf(stderr, "failed to read BLOB in BLOB chunk\n"); return EXIT_FAILURE; } INDENT_PRINT("-LOC: %.*s", (int) size, (const char*) buf); } break; case ACG_CHUNK_BEGIN: INDENT_PRINT("BEGIN:"); break; case ACG_CHUNK_END: if (0U == indent) { fprintf(stderr, "too many END chunk\n"); return EXIT_FAILURE; } INDENT_PRINT("END:"); break; case ACG_CHUNK_CHECK: INDENT_PRINT("CHECK:"); break; default: fprintf(stderr, "unknown chunk id: %" PRIu64 "\n", chunk_id); return EXIT_FAILURE; } } fclose(fp); return EXIT_SUCCESS; }