diff --git a/eebie/ebml.h b/eebie/ebml.h index 5b764e1..a429f9d 100644 --- a/eebie/ebml.h +++ b/eebie/ebml.h @@ -2,6 +2,7 @@ #define EEBIE_H #include +#include typedef enum EBMLElementType { EBML_SIGNED_INTEGER, @@ -15,13 +16,18 @@ typedef enum EBMLElementType { EBML_BINARY, } EBMLElementType; +typedef struct EBMLBinary { + uint8_t *ptr; + size_t length; +} EBMLBinary; + typedef union EBMLPrimitive { int64_t sInt; uint64_t uInt; float flt4; double flt8; const char *string; - const uint8_t *binary; + const EBMLBinary binary; uint64_t date; } EBMLPrimitive; diff --git a/eebie/writer.c b/eebie/writer.c index 660fbfd..17a5a28 100644 --- a/eebie/writer.c +++ b/eebie/writer.c @@ -2,7 +2,8 @@ #include #include -#include +#include +#include static uint64_t VARINT_MASKS[] = {0, 0x80L, 0xC000L, 0xE00000L, 0xF0000000L, 0xF800000000L, 0xFC0000000000L, 0xFE000000000000L, 0L}; @@ -41,7 +42,7 @@ static void advance(EBMLWriter *this, uint64_t amount) { static void add(EBMLWriter *this, const void *data, size_t length) { if(this->bufferLen + length > this->bufferCapacity) { - this->buffer = realloc(this->buffer, (this->bufferLen + length + 1023) & ~1023); + this->buffer = this->eventAlloc(this, this->buffer, (this->bufferLen + length + 1023) & ~1023); } memcpy(this->buffer + this->bufferLen, data, length); @@ -61,8 +62,18 @@ static void add_varint(EBMLWriter *this, uint64_t i) { void ebml_writer_init(EBMLWriter *this) { memset(this, 0, sizeof(EBMLWriter)); +} + +void ebml_writer_free(EBMLWriter *this) { + this->eventAlloc(this, this->buffer, 0); +} + +void ebml_writer_push_ind(EBMLWriter *this, uint64_t id) { + add_varint(this, id); - this->buffer = calloc(this->bufferCapacity = 1024, 1); + add(this, &(uint64_t) {htobe64(0x01FFFFFFFFFFFFFFL)}, sizeof(uint64_t)); // UNKNOWN-SIZED ELEMENT + + while(!ebml_writer_flush(this)); } void ebml_writer_push(EBMLWriter *this, uint64_t id) { @@ -74,6 +85,24 @@ void ebml_writer_push(EBMLWriter *this, uint64_t id) { } void ebml_writer_pop(EBMLWriter *this) { + this->currentDepth--; + + uint64_t newSize = this->stack[this->currentDepth]; + uint64_t *s = (uint64_t*) &this->buffer[this->bufferLen - newSize - 8]; + *s = htobe64(0x0100000000000000L | newSize); + + if(this->currentDepth == 0) { + while(!ebml_writer_flush(this)); + } +} + +bool ebml_writer_flush(EBMLWriter *this) { + size_t written = this->eventWrite(this, this->buffer, this->bufferLen); + + memmove(this->buffer, this->buffer + written, this->bufferLen - written); + this->bufferLen -= written; + + return this->bufferLen == 0; } void ebml_writer_put(EBMLWriter *this, uint64_t id, EBMLElementType type, EBMLPrimitive primitive) { @@ -89,9 +118,11 @@ void ebml_writer_put(EBMLWriter *this, uint64_t id, EBMLElementType type, EBMLPr len = 8; } else if(type == EBML_STRING) { len = strlen(primitive.string); + } else if(type == EBML_BINARY) { + len = primitive.binary.length; } else if(type == EBML_DATE) { len = 8; - } else abort(); + } else assert(0); add_varint(this, encode_int(len)); @@ -100,13 +131,17 @@ void ebml_writer_put(EBMLWriter *this, uint64_t id, EBMLElementType type, EBMLPr add(this, (uint8_t*) &primitive.uInt + 8 - len, len); } else if(type == EBML_FLOAT4) { uint32_t fl = *(uint32_t*) &primitive.flt4; + fl = htobe32(fl); add(this, &fl, 4); } else if(type == EBML_FLOAT8) { uint64_t fl = *(uint64_t*) &primitive.flt8; + fl = htobe64(fl); add(this, &fl, 8); } else if(type == EBML_STRING) { add(this, primitive.string, len); + } else if(type == EBML_BINARY) { + add(this, primitive.binary.ptr, primitive.binary.length); } else if(type == EBML_DATE) { add(this, &primitive.date, 8); - } else abort(); + } else assert(0); } diff --git a/eebie/writer.h b/eebie/writer.h index bb99fec..6470e7b 100644 --- a/eebie/writer.h +++ b/eebie/writer.h @@ -4,16 +4,21 @@ #include"ebml.h" #include +#include #define EBML_WRITE_MAXIMUM_DEPTH 128 -typedef size_t(*EBMLWriteCallback)(void *ud, const void *data, size_t length); +struct EBMLWriter; -typedef struct { +typedef size_t(*EBMLEventWrite)(struct EBMLWriter*, const void *data, size_t length); +typedef void*(*EBMLEventAlloc)(struct EBMLWriter*, void *data, size_t length); + +typedef struct EBMLWriter { int currentDepth; uint64_t stack[EBML_WRITE_MAXIMUM_DEPTH]; - EBMLWriteCallback callbackWrite; + EBMLEventWrite eventWrite; + EBMLEventAlloc eventAlloc; uint8_t *buffer; size_t bufferLen; @@ -23,10 +28,14 @@ typedef struct { } EBMLWriter; void ebml_writer_init(EBMLWriter *this); +void ebml_writer_free(EBMLWriter *this); +void ebml_writer_push_ind(EBMLWriter *this, uint64_t id); void ebml_writer_push(EBMLWriter *this, uint64_t id); void ebml_writer_pop(EBMLWriter *this); +bool ebml_writer_flush(EBMLWriter *this); + void ebml_writer_put(EBMLWriter *this, uint64_t id, EBMLElementType type, EBMLPrimitive primitive); #endif