Compare commits

...

7 Commits

Author SHA1 Message Date
Mid
e0716abc81 Handle indefinite elements 2025-10-07 12:27:21 +03:00
Mid
8b0fbfdcf7 Create Makefile.. finally 2025-10-07 11:00:39 +03:00
Mid
75c0ac1997 Bugfix 2025-10-07 10:57:38 +03:00
Mid
cca8f02870 Bug in README.md 2025-09-27 20:56:40 +03:00
Mid
d0ccaff719 C++-friendly headers 2025-09-27 20:56:05 +03:00
Mid
75d2efbe4c Bug fixes 2025-03-30 23:20:47 +03:00
Mid
629a8fdf55 Forgot something 2025-01-04 10:53:47 +02:00
6 changed files with 67 additions and 18 deletions

7
Makefile Normal file
View File

@@ -0,0 +1,7 @@
libeebie.so:
$(CC) -shared -g -O2 -o libeebie.so eebie/reader.c eebie/writer.c
install:
install -d /usr/local/include/eebie
install eebie/*.h /usr/local/include/eebie
install libeebie.so /usr/local/lib

View File

@@ -4,6 +4,8 @@ Eebie is a very small C99 library for reading and writing EBML files, namely Mat
The library is meant to be embedded directly into another project. The library is meant to be embedded directly into another project.
TODO: signed integer writing
## Reading example ## Reading example
#include"eebie/reader.h" #include"eebie/reader.h"
@@ -39,7 +41,7 @@ The library is meant to be embedded directly into another project.
} }
static void on_exit_element(EBMLReader *reader) { static void on_exit_element(EBMLReader *reader) {
// If needed, the current element ID can be found at `reader->inside.id`. // If needed, the exitee element ID can be found at `reader->idStack[reader->currentDepth - 1]`.
// Use accumulated buffer here. // Use accumulated buffer here.

View File

@@ -9,6 +9,8 @@
#include"reader.h" #include"reader.h"
#define is_max(u) ((u) == 0xFFFFFFFFFFFFFFFFUL)
void ebml_reader_init(EBMLReader *this) { void ebml_reader_init(EBMLReader *this) {
memset(this, 0, sizeof(*this)); memset(this, 0, sizeof(*this));
this->state = EBMLRS_WAITING_FOR_ELEMENT_ID; this->state = EBMLRS_WAITING_FOR_ELEMENT_ID;
@@ -89,6 +91,10 @@ static int get_varint(const uint8_t *data, size_t length, uint64_t *result) {
if(ret >= 0) { if(ret >= 0) {
*result &= ~VARINT_MASKS[ret]; *result &= ~VARINT_MASKS[ret];
if(*result == (1UL << (ret * 7)) - 1) {
*result = 0xFFFFFFFFFFFFFFFFUL;
}
} }
return ret; return ret;
@@ -137,7 +143,7 @@ int ebml_reader_feed(EBMLReader *this, const uint8_t *data, size_t length) {
} }
this->idStack[this->currentDepth] = this->inside.id; this->idStack[this->currentDepth] = this->inside.id;
this->stack[this->currentDepth] = elLength + status; this->stack[this->currentDepth] = is_max(elLength) ? elLength : elLength + status;
this->currentDepth++; this->currentDepth++;
@@ -156,7 +162,9 @@ int ebml_reader_feed(EBMLReader *this, const uint8_t *data, size_t length) {
} }
for(int i = 0; i < this->currentDepth; i++) { for(int i = 0; i < this->currentDepth; i++) {
this->stack[i] -= eaten; if(!is_max(this->stack[i])) {
this->stack[i] -= eaten;
}
} }
while(this->currentDepth > 0 && this->stack[this->currentDepth - 1] == 0) { while(this->currentDepth > 0 && this->stack[this->currentDepth - 1] == 0) {
@@ -173,3 +181,12 @@ int ebml_reader_feed(EBMLReader *this, const uint8_t *data, size_t length) {
return eaten; return eaten;
} }
void ebml_reader_leave(EBMLReader *this, uint64_t id) {
for(int i = 0; i < this->currentDepth; i++) {
if(this->idStack[i] == id) {
this->currentDepth = i;
return;
}
}
}

View File

@@ -5,6 +5,10 @@
#include"ebml.h" #include"ebml.h"
#ifdef __cplusplus
extern "C" {
#endif
#include<stddef.h> #include<stddef.h>
#include<stdint.h> #include<stdint.h>
@@ -42,7 +46,16 @@ typedef struct EBMLReader {
void *ud; void *ud;
} EBMLReader; } EBMLReader;
void ebml_reader_init(EBMLReader *this); void ebml_reader_init(EBMLReader*);
int ebml_reader_feed(EBMLReader *this, const uint8_t *data, size_t length); int ebml_reader_feed(EBMLReader*, const uint8_t *data, size_t length);
// Because Eebie is schemaless, it must be told when we have left an
// indefinite element, otherwise the stack may grow indefinitely and
// even overflow. The user may call this from eventEnterElement.
void ebml_reader_leave(EBMLReader*, uint64_t id);
#ifdef __cplusplus
}
#endif
#endif #endif

View File

@@ -5,7 +5,7 @@
#include<stddef.h> #include<stddef.h>
#include<assert.h> #include<assert.h>
static uint64_t VARINT_MASKS[] = {0, 0x80L, 0xC000L, 0xE00000L, 0xF0000000L, 0xF800000000L, 0xFC0000000000L, 0xFE000000000000L, 0L}; static uint64_t VARINT_MASKS[] = {0x0UL, 0x80UL, 0x4000UL, 0x200000UL, 0x10000000UL, 0x0800000000UL, 0x040000000000UL, 0x02000000000000UL, 0x0100000000000000UL};
static int byte_length(uint64_t i) { static int byte_length(uint64_t i) {
if(i == 0) return 1; if(i == 0) return 1;
@@ -15,6 +15,7 @@ static int byte_length(uint64_t i) {
i >>= 8; i >>= 8;
n++; n++;
} }
return n; return n;
} }
@@ -31,7 +32,8 @@ static int bit_length(uint64_t i) {
} }
static uint64_t encode_int(uint64_t i) { static uint64_t encode_int(uint64_t i) {
return i | VARINT_MASKS[(bit_length(i) + 6) / 7]; // bit_length(i + 1) over bit_length(i) because 0xFF... lengths are interpreted as indefinite
return i | VARINT_MASKS[(bit_length(i + 1) + 6) / 7];
} }
static void advance(EBMLWriter *this, uint64_t amount) { static void advance(EBMLWriter *this, uint64_t amount) {
@@ -42,7 +44,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 = this->eventAlloc(this, this->buffer, (this->bufferLen + length + 1023) & ~1023); this->buffer = this->eventAlloc(this, this->buffer, this->bufferCapacity = ((this->bufferLen + length + 1023) & ~1023));
} }
memcpy(this->buffer + this->bufferLen, data, length); memcpy(this->buffer + this->bufferLen, data, length);
@@ -71,7 +73,7 @@ void ebml_writer_free(EBMLWriter *this) {
void ebml_writer_push_ind(EBMLWriter *this, uint64_t id) { void ebml_writer_push_ind(EBMLWriter *this, uint64_t id) {
add_varint(this, id); add_varint(this, id);
add(this, &(uint64_t) {htobe64(0x01FFFFFFFFFFFFFFL)}, sizeof(uint64_t)); // UNKNOWN-SIZED ELEMENT add(this, &(uint64_t) {htobe64(0x01FFFFFFFFFFFFFFUL)}, sizeof(uint64_t)); // UNKNOWN-SIZED ELEMENT
while(!ebml_writer_flush(this)); while(!ebml_writer_flush(this));
} }
@@ -79,7 +81,7 @@ 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) {
add_varint(this, id); add_varint(this, id);
add(this, &(uint64_t) {htobe64(0x0100000000000000L)}, sizeof(uint64_t)); // LENGTH OF MAX SIZE (BECAUSE UNKNOWN) add(this, &(uint64_t) {htobe64(0x0100000000000000UL)}, sizeof(uint64_t)); // LENGTH OF MAX SIZE (BECAUSE UNKNOWN)
this->stack[this->currentDepth++] = 0; this->stack[this->currentDepth++] = 0;
} }
@@ -89,7 +91,7 @@ void ebml_writer_pop(EBMLWriter *this) {
uint64_t newSize = this->stack[this->currentDepth]; uint64_t newSize = this->stack[this->currentDepth];
uint64_t *s = (uint64_t*) &this->buffer[this->bufferLen - newSize - 8]; uint64_t *s = (uint64_t*) &this->buffer[this->bufferLen - newSize - 8];
*s = htobe64(0x0100000000000000L | newSize); *s = htobe64(0x0100000000000000UL | newSize);
if(this->currentDepth == 0) { if(this->currentDepth == 0) {
while(!ebml_writer_flush(this)); while(!ebml_writer_flush(this));

View File

@@ -6,6 +6,10 @@
#include<stddef.h> #include<stddef.h>
#include<stdbool.h> #include<stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
#define EBML_WRITE_MAXIMUM_DEPTH 128 #define EBML_WRITE_MAXIMUM_DEPTH 128
struct EBMLWriter; struct EBMLWriter;
@@ -27,15 +31,19 @@ typedef struct EBMLWriter {
void *ud; void *ud;
} EBMLWriter; } EBMLWriter;
void ebml_writer_init(EBMLWriter *this); void ebml_writer_init(EBMLWriter*);
void ebml_writer_free(EBMLWriter *this); void ebml_writer_free(EBMLWriter*);
void ebml_writer_push_ind(EBMLWriter *this, uint64_t id); void ebml_writer_push_ind(EBMLWriter*, uint64_t id);
void ebml_writer_push(EBMLWriter *this, uint64_t id); void ebml_writer_push(EBMLWriter*, uint64_t id);
void ebml_writer_pop(EBMLWriter *this); void ebml_writer_pop(EBMLWriter*);
bool ebml_writer_flush(EBMLWriter *this); bool ebml_writer_flush(EBMLWriter*);
void ebml_writer_put(EBMLWriter *this, uint64_t id, EBMLElementType type, EBMLPrimitive primitive); void ebml_writer_put(EBMLWriter*, uint64_t id, EBMLElementType type, EBMLPrimitive primitive);
#ifdef __cplusplus
}
#endif
#endif #endif