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.
TODO: signed integer writing
## Reading example
#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) {
// 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.

View File

@@ -9,6 +9,8 @@
#include"reader.h"
#define is_max(u) ((u) == 0xFFFFFFFFFFFFFFFFUL)
void ebml_reader_init(EBMLReader *this) {
memset(this, 0, sizeof(*this));
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) {
*result &= ~VARINT_MASKS[ret];
if(*result == (1UL << (ret * 7)) - 1) {
*result = 0xFFFFFFFFFFFFFFFFUL;
}
}
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->stack[this->currentDepth] = elLength + status;
this->stack[this->currentDepth] = is_max(elLength) ? elLength : elLength + status;
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++) {
this->stack[i] -= eaten;
if(!is_max(this->stack[i])) {
this->stack[i] -= eaten;
}
}
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;
}
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"
#ifdef __cplusplus
extern "C" {
#endif
#include<stddef.h>
#include<stdint.h>
@@ -42,7 +46,16 @@ typedef struct EBMLReader {
void *ud;
} EBMLReader;
void ebml_reader_init(EBMLReader *this);
int ebml_reader_feed(EBMLReader *this, const uint8_t *data, size_t length);
void ebml_reader_init(EBMLReader*);
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

View File

@@ -5,7 +5,7 @@
#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[] = {0x0UL, 0x80UL, 0x4000UL, 0x200000UL, 0x10000000UL, 0x0800000000UL, 0x040000000000UL, 0x02000000000000UL, 0x0100000000000000UL};
static int byte_length(uint64_t i) {
if(i == 0) return 1;
@@ -15,6 +15,7 @@ static int byte_length(uint64_t i) {
i >>= 8;
n++;
}
return n;
}
@@ -31,7 +32,8 @@ static int bit_length(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) {
@@ -42,7 +44,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 = 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);
@@ -71,7 +73,7 @@ void ebml_writer_free(EBMLWriter *this) {
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
add(this, &(uint64_t) {htobe64(0x01FFFFFFFFFFFFFFUL)}, sizeof(uint64_t)); // UNKNOWN-SIZED ELEMENT
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) {
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;
}
@@ -89,7 +91,7 @@ void ebml_writer_pop(EBMLWriter *this) {
uint64_t newSize = this->stack[this->currentDepth];
uint64_t *s = (uint64_t*) &this->buffer[this->bufferLen - newSize - 8];
*s = htobe64(0x0100000000000000L | newSize);
*s = htobe64(0x0100000000000000UL | newSize);
if(this->currentDepth == 0) {
while(!ebml_writer_flush(this));

View File

@@ -6,6 +6,10 @@
#include<stddef.h>
#include<stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
#define EBML_WRITE_MAXIMUM_DEPTH 128
struct EBMLWriter;
@@ -27,15 +31,19 @@ typedef struct EBMLWriter {
void *ud;
} EBMLWriter;
void ebml_writer_init(EBMLWriter *this);
void ebml_writer_free(EBMLWriter *this);
void ebml_writer_init(EBMLWriter*);
void ebml_writer_free(EBMLWriter*);
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);
void ebml_writer_push_ind(EBMLWriter*, uint64_t id);
void ebml_writer_push(EBMLWriter*, uint64_t id);
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