136 lines
3.4 KiB
C
136 lines
3.4 KiB
C
// No copyright
|
|
#include <inttypes.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <allcing.h>
|
|
|
|
|
|
#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;
|
|
}
|