Mercurial > libedl
changeset 3:bd99b6549eb4
*: expand in readme and rename src/main to src/edl
author | Paper <mrpapersonic@gmail.com> |
---|---|
date | Sun, 24 Dec 2023 20:22:54 -0500 |
parents | d00bc412900e |
children | c2408abb258a |
files | Makefile.am README.md configure.ac src/edl.c src/main.c |
diffstat | 5 files changed, 323 insertions(+), 310 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile.am Sun Dec 24 20:01:30 2023 -0500 +++ b/Makefile.am Sun Dec 24 20:22:54 2023 -0500 @@ -1,5 +1,5 @@ lib_LTLIBRARIES = libedl.la -libedl_la_SOURCES = src/main.c +libedl_la_SOURCES = src/edl.c include_HEADERS = include/edl.h AM_CPPFLAGS = -I$(srcdir)/include
--- a/README.md Sun Dec 24 20:01:30 2023 -0500 +++ b/README.md Sun Dec 24 20:22:54 2023 -0500 @@ -1,14 +1,27 @@ # libedl libedl is a library for parsing Vegas Pro EDL files and translating them into usable C structures. +Currently, writing EDL files is not supported by this library. + +## Build +```console +$ autoreconf -i +$ mkdir build +$ cd build +$ ../configure +$ make +$ sudo make install +``` + ## Usage ```c #include <stdio.h> +#include <stdlib.h> #include "edl.h" int main(){ /* open the file */ - FILE* file = fopen("MyProject.txt", "rb"); + FILE* file = fopen("MyProject.txt", "rb"); if (!file) return 1; @@ -31,13 +44,13 @@ /* do what we have to do with it */ for (int i = 0; i < edl.size; i++) { - printf("%s", edl.arr[i].filename); + printf("%s\n", edl.arr[i].filename); } /* free our memory */ EDL_free(edl); free(data); - return 0; + return 0; } ```
--- a/configure.ac Sun Dec 24 20:01:30 2023 -0500 +++ b/configure.ac Sun Dec 24 20:22:54 2023 -0500 @@ -1,6 +1,6 @@ AC_INIT([libedl], [1.0]) -AC_CONFIG_SRCDIR([src/main.c]) +AC_CONFIG_SRCDIR([src/edl.c]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIRS([m4])
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/edl.c Sun Dec 24 20:22:54 2023 -0500 @@ -0,0 +1,305 @@ +#include <string.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include "edl.h" + +#define strnchr(haystack, needle, length) (char*)memchr(haystack, needle, strnlen(haystack, length)) + +static uint32_t EDL_internal_crcn32b(const unsigned char* restrict message, size_t length) { + uint32_t crc = 0xFFFFFFFF; + + size_t i; + for (i = 0; i < length && message[i]; i++) { + crc = crc ^ message[i]; + size_t j; + for (j = 0; j < 8; j++) + crc = (crc >> 1) ^ (0xEDB88320 & -(crc & 1)); + } + + return ~crc; +} + +/* This parses the first line of the EDL and + * creates an array with CRC32 hashes in + * the order of the strings. +*/ +static uint32_t* EDL_internal_parse_first_line(const char* data, size_t* restrict length) { + size_t hashes_size = 32, current_hash = 0; + uint32_t* hashes = malloc(hashes_size * sizeof(uint32_t)); + + size_t len_until_newline = strchr(data, '\n') - data, i, b; + for (i = 0, b = 0; i < len_until_newline; i++, b++) { + if (data[i] == ';') { + if (current_hash >= hashes_size) + hashes = realloc(hashes, (hashes_size *= 2) * sizeof(uint32_t)); + hashes[current_hash++] = EDL_internal_crcn32b((const unsigned char*)&data[i - b], b); + b = -1; // ew + } + } + + *length = current_hash; + + return hashes; +} + +/* -- Functions to extract different datatypes -- */ + +static size_t EDL_internal_append_offset(const char* input, size_t offset, size_t length) { + size_t s = 0; + + s += strchr(&input[offset + s], ';') - &input[offset]; + if (s + offset > length) + return s; + + s += strspn(&input[offset + s], ";\t "); + if (s + offset > length) + return s; + + return s; +} + +static size_t EDL_internal_get_int(const char* input, size_t offset, size_t length, int* int_return) { + if (offset > length) + return 0; + + { + char* ptr_return; + *int_return = strtol(&input[offset], &ptr_return, 10); + + if (!ptr_return) + return 0; + } + + return EDL_internal_append_offset(input, offset, length); +} + +static size_t EDL_internal_get_double(const char* input, size_t offset, size_t length, double* double_return) { + if (offset > length) + return 0; + + { + char* ptr_return; + *double_return = strtod(&input[offset], &ptr_return); + + if (!ptr_return) + return 0; + } + + return EDL_internal_append_offset(input, offset, length); +} + +static size_t EDL_internal_get_bool(const char* input, size_t offset, size_t length, bool* bool_return) { + if (offset > length) + return 0; + + if (strncmp((input + offset), "TRUE", 4)) + *bool_return = true; + else if (strncmp((input + offset), "FALSE", 5)) + *bool_return = false; + + return EDL_internal_append_offset(input, offset, length); +} + +static size_t EDL_internal_get_media_type(const char* input, size_t offset, size_t length, MediaType* media_return) { + if (offset > length) + return 0; + + if (strncmp(input + offset, "VIDEO", 5)) + *media_return = MEDIATYPE_VIDEO; + else if (strncmp(input + offset, "AUDIO", 5)) + *media_return = MEDIATYPE_AUDIO; + + return EDL_internal_append_offset(input, offset, length); +} + +static size_t EDL_internal_get_string(const char* input, size_t offset, size_t length, char** string_return) { + /* Windows filenames will *NEVER* include double quotes. + This might break with EDL files created with Reaper on Linux. */ + if (offset > length) + return 0; + + size_t start = strchr(&input[offset], '\"') - &input[offset] + 1; + if (start + offset > length) + return 0; + + size_t s_length = strchr(&input[offset + start], '\"') - &input[offset] - start; + if (start + s_length + offset > length) + return 0; + + *string_return = malloc((s_length + 1) * sizeof(char)); + if (!*string_return) + return 0; + + memcpy(*string_return, &input[offset + start], s_length); + (*string_return)[s_length] = '\0'; + + return EDL_internal_append_offset(input, offset, length); +} + +/* memory management routines */ + +static int EDL_internal_reallocate(EDL_file* input, size_t new_capacity) { + input->arr = realloc(input->arr, new_capacity * sizeof(EDL_line)); + if (!input->arr) + return 0; + + if (new_capacity > input->capacity) + memset(input->arr + input->capacity, 0, new_capacity - input->capacity); + + input->capacity = new_capacity; + + return 1; +} + +static int EDL_internal_allocate_memory(EDL_file* input) { + return EDL_internal_reallocate(input, input->capacity ? input->capacity * 2 : 16); +} + +static int EDL_internal_shrink_memory_to_fit(EDL_file* input) { + return EDL_internal_reallocate(input, input->size); +} + +/* the important function */ +EDL_file EDL_parse(const char* data, size_t length) { + EDL_file edl = {0}; + if (!EDL_internal_allocate_memory(&edl)) + return edl; + + size_t order_size = 0; + uint32_t* order = EDL_internal_parse_first_line(data, &order_size); + + size_t offset = strnchr(data, '\n', length) - data + 1; + while ((offset = strnchr(data + offset, '\n', length - offset) - data + 1) < length) { + size_t local_offset = offset; // this is so our original offset stays intact + + bool ok = true; + + for (int i = 0; i < order_size; i++) { +#define ADD_TO_OFFSET(x, a) \ +{ \ + size_t o = a(data, local_offset, length, &edl.arr[edl.size].x); \ + if (!o) \ + ok = false; \ + local_offset += o; \ +} + switch (order[i]) { + case 0x1541c503: /* ID */ + ADD_TO_OFFSET(id, EDL_internal_get_int); + break; + case 0x4b211812: /* Track */ + ADD_TO_OFFSET(track, EDL_internal_get_int); + break; + case 0xbb46516f: /* StartTime */ + ADD_TO_OFFSET(start_time, EDL_internal_get_double); + break; + case 0xaeac5df7: /* Length */ + ADD_TO_OFFSET(length, EDL_internal_get_double); + break; + case 0x03834606: /* PlayRate */ + ADD_TO_OFFSET(play_rate, EDL_internal_get_double); + break; + case 0x0c2083d3: /* Locked */ + ADD_TO_OFFSET(locked, EDL_internal_get_bool); + break; + case 0xe60c8b1d: /* Normalized */ + ADD_TO_OFFSET(normalized, EDL_internal_get_bool); + break; + case 0xbe5802c9: /* StretchMethod */ + ADD_TO_OFFSET(stretch_method, EDL_internal_get_int); + break; + case 0x4ec8be4c: /* Looped */ + ADD_TO_OFFSET(looped, EDL_internal_get_bool); + break; + case 0xe6cb84d1: /* OnRuler */ + ADD_TO_OFFSET(on_ruler, EDL_internal_get_bool); + break; + case 0x035f84c2: /* MediaType */ + ADD_TO_OFFSET(media_type, EDL_internal_get_media_type); + break; + case 0x379d32c5: /* FileName */ + ADD_TO_OFFSET(filename, EDL_internal_get_string); + break; + case 0x9f334738: /* Stream */ + ADD_TO_OFFSET(stream, EDL_internal_get_int); + break; + case 0x07b4e0e7: /* StreamStart */ + ADD_TO_OFFSET(stream_start, EDL_internal_get_double); + break; + case 0x8f16c7b8: /* StreamLength */ + ADD_TO_OFFSET(stream_length, EDL_internal_get_double); + break; + case 0xd2edd7e4: /* FadeTimeIn */ + ADD_TO_OFFSET(fade_time_in, EDL_internal_get_double); + break; + case 0x792e8c40: /* FadeTimeOut */ + ADD_TO_OFFSET(fade_time_out, EDL_internal_get_double); + break; + case 0x98374657: /* SustainGain */ + ADD_TO_OFFSET(sustain_gain, EDL_internal_get_double); + break; + case 0x3e998b1f: /* CurveIn */ + ADD_TO_OFFSET(curve_in, EDL_internal_get_int); + break; + case 0x82fb09c4: /* GainIn */ + ADD_TO_OFFSET(gain_in, EDL_internal_get_double); + break; + case 0x53add388: /* CurveOut */ + ADD_TO_OFFSET(curve_out, EDL_internal_get_int); + break; + case 0x4210ba56: /* GainOut */ + ADD_TO_OFFSET(gain_out, EDL_internal_get_double); + break; + case 0x89c4df6c: /* Layer */ + ADD_TO_OFFSET(layer, EDL_internal_get_int); + break; + case 0xadf2f1a3: /* Color */ + ADD_TO_OFFSET(color, EDL_internal_get_int); + break; + case 0xa56b43e1: /* CurveInR */ + ADD_TO_OFFSET(curve_in_r, EDL_internal_get_int); + break; + case 0xcb6d715e: /* CurveOutR */ + ADD_TO_OFFSET(curve_out_r, EDL_internal_get_int); + break; + case 0x9da1b9ed: /* PlayPitch */ + ADD_TO_OFFSET(play_pitch, EDL_internal_get_double); + break; + case 0x2bda6ed4: /* LockPitch */ + ADD_TO_OFFSET(lock_pitch, EDL_internal_get_bool); + break; + case 0x3071a4c6: /* FirstChannel */ + ADD_TO_OFFSET(first_channel, EDL_internal_get_int); + break; + case 0x7de1bd40: /* Channels */ + ADD_TO_OFFSET(channels, EDL_internal_get_int); + break; + default: + /* ... what */ + break; + } + } + + if (!ok) + break; + + if (++edl.size >= edl.capacity) + EDL_internal_allocate_memory(&edl); + } + + EDL_internal_shrink_memory_to_fit(&edl); + + free(order); + + return edl; +} + +void EDL_free(EDL_file file) { + size_t i; + for (i = 0; i < file.size; i++) { + if (file.arr[i].filename) + free(file.arr[i].filename); + } + free(file.arr); +}
--- a/src/main.c Sun Dec 24 20:01:30 2023 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,305 +0,0 @@ -#include <string.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include "edl.h" - -#define strnchr(haystack, needle, length) memchr(haystack, needle, strnlen(haystack, length)) - -static uint32_t EDL_internal_crcn32b(const unsigned char* restrict message, size_t length) { - uint32_t crc = 0xFFFFFFFF; - - size_t i; - for (i = 0; i < length && message[i]; i++) { - crc = crc ^ message[i]; - size_t j; - for (j = 0; j < 8; j++) - crc = (crc >> 1) ^ (0xEDB88320 & -(crc & 1)); - } - - return ~crc; -} - -/* This parses the first line of the EDL and - * creates an array with CRC32 hashes in - * the order of the strings. -*/ -static uint32_t* EDL_internal_parse_first_line(const char* data, size_t* restrict length) { - size_t hashes_size = 32, current_hash = 0; - uint32_t* hashes = malloc(hashes_size * sizeof(uint32_t)); - - size_t len_until_newline = strchr(data, '\n') - data, i, b; - for (i = 0, b = 0; i < len_until_newline; i++, b++) { - if (data[i] == ';') { - if (current_hash >= hashes_size) - hashes = realloc(hashes, (hashes_size *= 2) * sizeof(uint32_t)); - hashes[current_hash++] = EDL_internal_crcn32b((const unsigned char*)&data[i - b], b); - b = -1; // ew - } - } - - *length = current_hash; - - return hashes; -} - -/* -- Functions to extract different datatypes -- */ - -static size_t EDL_internal_append_offset(const char* input, size_t offset, size_t length) { - size_t s = 0; - - s += strchr(&input[offset + s], ';') - &input[offset]; - if (s + offset > length) - return s; - - s += strspn(&input[offset + s], ";\t "); - if (s + offset > length) - return s; - - return s; -} - -static size_t EDL_internal_get_int(const char* input, size_t offset, size_t length, int* int_return) { - if (offset > length) - return 0; - - { - char* ptr_return; - *int_return = strtol(&input[offset], &ptr_return, 10); - - if (!ptr_return) - return 0; - } - - return EDL_internal_append_offset(input, offset, length); -} - -static size_t EDL_internal_get_double(const char* input, size_t offset, size_t length, double* double_return) { - if (offset > length) - return 0; - - { - char* ptr_return; - *double_return = strtod(&input[offset], &ptr_return); - - if (!ptr_return) - return 0; - } - - return EDL_internal_append_offset(input, offset, length); -} - -static size_t EDL_internal_get_bool(const char* input, size_t offset, size_t length, bool* bool_return) { - if (offset > length) - return 0; - - if (strncmp((input + offset), "TRUE", 4)) - *bool_return = true; - else if (strncmp((input + offset), "FALSE", 5)) - *bool_return = false; - - return EDL_internal_append_offset(input, offset, length); -} - -static size_t EDL_internal_get_media_type(const char* input, size_t offset, size_t length, MediaType* media_return) { - if (offset > length) - return 0; - - if (strncmp(input + offset, "VIDEO", 5)) - *media_return = MEDIATYPE_VIDEO; - else if (strncmp(input + offset, "AUDIO", 5)) - *media_return = MEDIATYPE_AUDIO; - - return EDL_internal_append_offset(input, offset, length); -} - -static size_t EDL_internal_get_string(const char* input, size_t offset, size_t length, char** string_return) { - /* Windows filenames will *NEVER* include double quotes. - This might break with EDL files created with Reaper on Linux. */ - if (offset > length) - return 0; - - size_t start = strchr(&input[offset], '\"') - &input[offset] + 1; - if (start + offset > length) - return 0; - - size_t s_length = strchr(&input[offset + start], '\"') - &input[offset] - start; - if (start + s_length + offset > length) - return 0; - - *string_return = malloc((s_length + 1) * sizeof(char)); - if (!*string_return) - return 0; - - memcpy(*string_return, &input[offset + start], s_length); - (*string_return)[s_length] = '\0'; - - return EDL_internal_append_offset(input, offset, length); -} - -/* memory management routines */ - -static int EDL_internal_reallocate(EDL_file* input, size_t new_capacity) { - input->arr = realloc(input->arr, new_capacity * sizeof(EDL_line)); - if (!input->arr) - return 0; - - if (new_capacity > input->capacity) - memset(input->arr + input->capacity, 0, new_capacity - input->capacity); - - input->capacity = new_capacity; - - return 1; -} - -static int EDL_internal_allocate_memory(EDL_file* input) { - return EDL_internal_reallocate(input, input->capacity ? input->capacity * 2 : 16); -} - -static int EDL_internal_shrink_memory_to_fit(EDL_file* input) { - return EDL_internal_reallocate(input, input->size); -} - -/* the important function */ -EDL_file EDL_parse(const char* data, size_t length) { - EDL_file edl = {0}; - if (!EDL_internal_allocate_memory(&edl)) - return edl; - - size_t order_size = 0; - uint32_t* order = EDL_internal_parse_first_line(data, &order_size); - - size_t offset = 0; - while ((offset = strnchr(data + offset + 1, '\n', length - offset) - (void*)data) < length) { - size_t local_offset = offset; // this is so our original offset stays intact - - bool ok = true; - - for (int i = 0; i < order_size; i++) { -#define ADD_TO_OFFSET(x, a) \ -{ \ - size_t o = a(data, local_offset, length, &edl.arr[edl.size].x); \ - if (!o) \ - ok = false; \ - local_offset += o; \ -} - switch (order[i]) { - case 0x1541c503: /* ID */ - ADD_TO_OFFSET(id, EDL_internal_get_int); - break; - case 0x4b211812: /* Track */ - ADD_TO_OFFSET(track, EDL_internal_get_int); - break; - case 0xbb46516f: /* StartTime */ - ADD_TO_OFFSET(start_time, EDL_internal_get_double); - break; - case 0xaeac5df7: /* Length */ - ADD_TO_OFFSET(length, EDL_internal_get_double); - break; - case 0x03834606: /* PlayRate */ - ADD_TO_OFFSET(play_rate, EDL_internal_get_double); - break; - case 0x0c2083d3: /* Locked */ - ADD_TO_OFFSET(locked, EDL_internal_get_bool); - break; - case 0xe60c8b1d: /* Normalized */ - ADD_TO_OFFSET(normalized, EDL_internal_get_bool); - break; - case 0xbe5802c9: /* StretchMethod */ - ADD_TO_OFFSET(stretch_method, EDL_internal_get_int); - break; - case 0x4ec8be4c: /* Looped */ - ADD_TO_OFFSET(looped, EDL_internal_get_bool); - break; - case 0xe6cb84d1: /* OnRuler */ - ADD_TO_OFFSET(on_ruler, EDL_internal_get_bool); - break; - case 0x035f84c2: /* MediaType */ - ADD_TO_OFFSET(media_type, EDL_internal_get_media_type); - break; - case 0x379d32c5: /* FileName */ - ADD_TO_OFFSET(filename, EDL_internal_get_string); - break; - case 0x9f334738: /* Stream */ - ADD_TO_OFFSET(stream, EDL_internal_get_int); - break; - case 0x07b4e0e7: /* StreamStart */ - ADD_TO_OFFSET(stream_start, EDL_internal_get_double); - break; - case 0x8f16c7b8: /* StreamLength */ - ADD_TO_OFFSET(stream_length, EDL_internal_get_double); - break; - case 0xd2edd7e4: /* FadeTimeIn */ - ADD_TO_OFFSET(fade_time_in, EDL_internal_get_double); - break; - case 0x792e8c40: /* FadeTimeOut */ - ADD_TO_OFFSET(fade_time_out, EDL_internal_get_double); - break; - case 0x98374657: /* SustainGain */ - ADD_TO_OFFSET(sustain_gain, EDL_internal_get_double); - break; - case 0x3e998b1f: /* CurveIn */ - ADD_TO_OFFSET(curve_in, EDL_internal_get_int); - break; - case 0x82fb09c4: /* GainIn */ - ADD_TO_OFFSET(gain_in, EDL_internal_get_double); - break; - case 0x53add388: /* CurveOut */ - ADD_TO_OFFSET(curve_out, EDL_internal_get_int); - break; - case 0x4210ba56: /* GainOut */ - ADD_TO_OFFSET(gain_out, EDL_internal_get_double); - break; - case 0x89c4df6c: /* Layer */ - ADD_TO_OFFSET(layer, EDL_internal_get_int); - break; - case 0xadf2f1a3: /* Color */ - ADD_TO_OFFSET(color, EDL_internal_get_int); - break; - case 0xa56b43e1: /* CurveInR */ - ADD_TO_OFFSET(curve_in_r, EDL_internal_get_int); - break; - case 0xcb6d715e: /* CurveOutR */ - ADD_TO_OFFSET(curve_out_r, EDL_internal_get_int); - break; - case 0x9da1b9ed: /* PlayPitch */ - ADD_TO_OFFSET(play_pitch, EDL_internal_get_double); - break; - case 0x2bda6ed4: /* LockPitch */ - ADD_TO_OFFSET(lock_pitch, EDL_internal_get_bool); - break; - case 0x3071a4c6: /* FirstChannel */ - ADD_TO_OFFSET(first_channel, EDL_internal_get_int); - break; - case 0x7de1bd40: /* Channels */ - ADD_TO_OFFSET(channels, EDL_internal_get_int); - break; - default: - /* ... what */ - break; - } - } - - if (!ok) - break; - - if (++edl.size >= edl.capacity) - EDL_internal_allocate_memory(&edl); - } - - EDL_internal_shrink_memory_to_fit(&edl); - - free(order); - - return edl; -} - -void EDL_free(EDL_file file) { - size_t i; - for (i = 0; i < file.size; i++) { - if (file.arr[i].filename) - free(file.arr[i].filename); - } - free(file.arr); -}