eebie/README.md

174 lines
4.9 KiB
Markdown
Raw Permalink Normal View History

2024-07-25 10:52:24 +03:00
# Eebie
Eebie is a very small C99 library for reading and writing EBML files, namely Matroska & WebM.
The library is meant to be embedded directly into another project.
## Reading example
#include"eebie/reader.h"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
static EBMLElementType on_enter_element(EBMLReader *reader, uint64_t id, uint64_t length) {
printf("Found element %lX of size %lu at depth %u\n", id, length, reader->currentDepth);
if(id == 0x2468AC || id == 0x1A45DFA3) {
// Delve deeper.
return EBML_TREE;
}
// Don't delve deeper, just get the data.
// Important: the only distinction here is between EBML_TREE and not EBML_TREE.
return EBML_BINARY;
}
static uint8_t *accumulationBuffer;
static size_t accumulationBufferLength = 0;
static void on_data_chunk(EBMLReader *reader, const uint8_t *data, size_t length) {
// Add new data into our accumulation buffer.
accumulationBuffer = realloc(accumulationBuffer, accumulationBufferLength + length);
memcpy(accumulationBuffer + accumulationBufferLength, data, length);
accumulationBufferLength += length;
}
static void on_exit_element(EBMLReader *reader) {
// If needed, the current element ID can be found at `reader->inside.id`.
// Use accumulated buffer here.
free(accumulationBuffer);
accumulationBuffer = NULL;
accumulationBufferLength = 0;
}
int main() {
EBMLReader reader;
ebml_reader_init(&reader);
// Set userdata here.
reader.ud = NULL;
// eventEnterElement is the only mandatory event handler.
// It must specify whether an EBML element is a master or a primitive value.
reader.eventEnterElement = on_enter_element;
// eventDataChunk is called for every *CHUNK* of data of the element that has been read.
// Once the element is exited, the accumulated buffer may be decoded fully.
reader.eventDataChunk = on_data_chunk;
// eventExitElement is called for every element finished parsing, including masters or primitive values.
reader.eventExitElement = on_exit_element;
FILE *f = fopen("test.mkv", "rb");
size_t i = 0;
uint8_t buffer[4096];
while(1) {
// Fill up buffer
size_t readBytes = fread(buffer + i, 1, sizeof(buffer) - i, f);
i += readBytes;
// Use buffer
size_t fedBytes = ebml_reader_feed(&reader, buffer, i);
// Shift buffer by used amount
memmove(buffer, buffer + fedBytes, sizeof(buffer) - fedBytes);
i -= fedBytes;
if(readBytes == 0 && fedBytes == 0) {
// Give up.
break;
}
}
}
## Writing example
TBA
## `schemagen`
Given an EBML schema, `schemagen` generates a specialized header-only parser that uses `EBMLReader` to call handlers for each defined element, decoding them all to their correct types. It does not yet perform validation such as enums or ranges.
Example using the [Matroska schema](https://github.com/ietf-wg-cellar/matroska-specification/blob/master/ebml_matroska.xml):
cd schemagen
make
./schemagen /path/to/the/ebml_matroska.xml Mkv > mkv.h
The first argument is the path to the schema file. The second argument is the prefix to use in CamelCase. After this, `mkv.h` may be used similarly to EBMLReader:
#define MKV_PARSER_IMPLEMENTATION
#include"mkv.h"
#include<stdio.h>
static void on_segment(MkvParser *parser) {
printf("Entered new segment.\n");
}
static void on_cluster(MkvParser *parser) {
printf("Entered new cluster.\n");
}
static void on_timestamp(MkvParser *parser, uint64_t timestamp) {
printf("Cluster timestamp: %lu\n", timestamp);
}
int main() {
MkvParser parser;
mkv_parser_init(&parser);
parser.ud = NULL;
parser.OnSegment = on_segment;
parser.OnCluster = on_cluster;
parser.OnTimestamp = on_timestamp;
// Many more event handlers can be used.
FILE *f = fopen("test.mkv", "rb");
size_t i = 0;
uint8_t buffer[4096];
while(1) {
// Fill up buffer
size_t readBytes = fread(buffer + i, 1, sizeof(buffer) - i, f);
i += readBytes;
// Use buffer
size_t fedBytes = mkv_parser_feed(&parser, buffer, i);
// Shift buffer by used amount
memmove(buffer, buffer + fedBytes, sizeof(buffer) - fedBytes);
i -= fedBytes;
if(readBytes == 0 && fedBytes == 0) {
// Give up.
break;
}
}
}
## License
Eebie is licensed under the BSD 3-clause license (SPDX identifier "BSD-3-Clause").