Compare commits
7 Commits
fb97037243
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0716abc81 | ||
|
|
8b0fbfdcf7 | ||
|
|
75c0ac1997 | ||
|
|
cca8f02870 | ||
|
|
d0ccaff719 | ||
|
|
75d2efbe4c | ||
|
|
629a8fdf55 |
7
Makefile
Normal file
7
Makefile
Normal 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
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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,8 +162,10 @@ int ebml_reader_feed(EBMLReader *this, const uint8_t *data, size_t length) {
|
||||
}
|
||||
|
||||
for(int i = 0; i < this->currentDepth; i++) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user