Complete writer interface

This commit is contained in:
Mid 2025-01-04 10:44:33 +02:00
parent 251adf906b
commit 1476dbdd57
3 changed files with 59 additions and 9 deletions

View File

@ -2,6 +2,7 @@
#define EEBIE_H #define EEBIE_H
#include<stdint.h> #include<stdint.h>
#include<stddef.h>
typedef enum EBMLElementType { typedef enum EBMLElementType {
EBML_SIGNED_INTEGER, EBML_SIGNED_INTEGER,
@ -15,13 +16,18 @@ typedef enum EBMLElementType {
EBML_BINARY, EBML_BINARY,
} EBMLElementType; } EBMLElementType;
typedef struct EBMLBinary {
uint8_t *ptr;
size_t length;
} EBMLBinary;
typedef union EBMLPrimitive { typedef union EBMLPrimitive {
int64_t sInt; int64_t sInt;
uint64_t uInt; uint64_t uInt;
float flt4; float flt4;
double flt8; double flt8;
const char *string; const char *string;
const uint8_t *binary; const EBMLBinary binary;
uint64_t date; uint64_t date;
} EBMLPrimitive; } EBMLPrimitive;

View File

@ -2,7 +2,8 @@
#include<string.h> #include<string.h>
#include<endian.h> #include<endian.h>
#include<stdlib.h> #include<stddef.h>
#include<assert.h>
static uint64_t VARINT_MASKS[] = {0, 0x80L, 0xC000L, 0xE00000L, 0xF0000000L, 0xF800000000L, 0xFC0000000000L, 0xFE000000000000L, 0L}; 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) { static void add(EBMLWriter *this, const void *data, size_t length) {
if(this->bufferLen + length > this->bufferCapacity) { 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); 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) { void ebml_writer_init(EBMLWriter *this) {
memset(this, 0, sizeof(EBMLWriter)); memset(this, 0, sizeof(EBMLWriter));
}
this->buffer = calloc(this->bufferCapacity = 1024, 1); 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);
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) { 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) { 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) { 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; len = 8;
} else if(type == EBML_STRING) { } else if(type == EBML_STRING) {
len = strlen(primitive.string); len = strlen(primitive.string);
} else if(type == EBML_BINARY) {
len = primitive.binary.length;
} else if(type == EBML_DATE) { } else if(type == EBML_DATE) {
len = 8; len = 8;
} else abort(); } else assert(0);
add_varint(this, encode_int(len)); 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); add(this, (uint8_t*) &primitive.uInt + 8 - len, len);
} else if(type == EBML_FLOAT4) { } else if(type == EBML_FLOAT4) {
uint32_t fl = *(uint32_t*) &primitive.flt4; uint32_t fl = *(uint32_t*) &primitive.flt4;
fl = htobe32(fl);
add(this, &fl, 4); add(this, &fl, 4);
} else if(type == EBML_FLOAT8) { } else if(type == EBML_FLOAT8) {
uint64_t fl = *(uint64_t*) &primitive.flt8; uint64_t fl = *(uint64_t*) &primitive.flt8;
fl = htobe64(fl);
add(this, &fl, 8); add(this, &fl, 8);
} else if(type == EBML_STRING) { } else if(type == EBML_STRING) {
add(this, primitive.string, len); add(this, primitive.string, len);
} else if(type == EBML_BINARY) {
add(this, primitive.binary.ptr, primitive.binary.length);
} else if(type == EBML_DATE) { } else if(type == EBML_DATE) {
add(this, &primitive.date, 8); add(this, &primitive.date, 8);
} else abort(); } else assert(0);
} }

View File

@ -4,16 +4,21 @@
#include"ebml.h" #include"ebml.h"
#include<stddef.h> #include<stddef.h>
#include<stdbool.h>
#define EBML_WRITE_MAXIMUM_DEPTH 128 #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; int currentDepth;
uint64_t stack[EBML_WRITE_MAXIMUM_DEPTH]; uint64_t stack[EBML_WRITE_MAXIMUM_DEPTH];
EBMLWriteCallback callbackWrite; EBMLEventWrite eventWrite;
EBMLEventAlloc eventAlloc;
uint8_t *buffer; uint8_t *buffer;
size_t bufferLen; size_t bufferLen;
@ -23,10 +28,14 @@ typedef struct {
} EBMLWriter; } EBMLWriter;
void ebml_writer_init(EBMLWriter *this); 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_push(EBMLWriter *this, uint64_t id);
void ebml_writer_pop(EBMLWriter *this); 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); void ebml_writer_put(EBMLWriter *this, uint64_t id, EBMLElementType type, EBMLPrimitive primitive);
#endif #endif