# HG changeset patch # User Paper # Date 1703539456 18000 # Node ID c2408abb258acec3b1e6d7613b51c5840e60124f # Parent bd99b6549eb460d47531c07801166e4fcde20441 *: add dumping to string, rename EDL_file to EDL diff -r bd99b6549eb4 -r c2408abb258a Makefile.am --- a/Makefile.am Sun Dec 24 20:22:54 2023 -0500 +++ b/Makefile.am Mon Dec 25 16:24:16 2023 -0500 @@ -1,6 +1,6 @@ lib_LTLIBRARIES = libedl.la -libedl_la_SOURCES = src/edl.c -include_HEADERS = include/edl.h +libedl_la_SOURCES = src/edl.c src/str.c +include_HEADERS = include/edl.h include/str.h AM_CPPFLAGS = -I$(srcdir)/include ACLOCAL_AMFLAGS = -I m4 diff -r bd99b6549eb4 -r c2408abb258a README.md --- a/README.md Sun Dec 24 20:22:54 2023 -0500 +++ b/README.md Mon Dec 25 16:24:16 2023 -0500 @@ -1,8 +1,6 @@ # 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 @@ -19,9 +17,9 @@ #include #include "edl.h" -int main(){ +int main() { /* open the file */ - FILE* file = fopen("MyProject.txt", "rb"); + FILE* file = fopen("intensive care unit.TXT", "rb"); if (!file) return 1; @@ -37,15 +35,17 @@ fread(data, fsize, 1, file); + data[fsize] = '\0'; + fclose(file); /* pass it to libedl */ - EDL_file edl = EDL_parse(data, fsize + 1); + EDL edl = EDL_parse(data, fsize + 1); - /* do what we have to do with it */ - for (int i = 0; i < edl.size; i++) { - printf("%s\n", edl.arr[i].filename); - } + /* dump the EDL to */ + char* edl_str = EDL_dump(edl); + printf("%s\n", edl_str); + free(edl_str); /* free our memory */ EDL_free(edl); diff -r bd99b6549eb4 -r c2408abb258a include/edl.h --- a/include/edl.h Sun Dec 24 20:22:54 2023 -0500 +++ b/include/edl.h Mon Dec 25 16:24:16 2023 -0500 @@ -10,7 +10,8 @@ typedef enum { MEDIATYPE_VIDEO, - MEDIATYPE_AUDIO + MEDIATYPE_AUDIO, + MEDIATYPE_UNKNOWN } MediaType; typedef struct { @@ -50,10 +51,11 @@ EDL_line* arr; int capacity; int size; -} EDL_file; +} EDL; -EDL_file EDL_parse(const char* text, size_t length); -void EDL_free(EDL_file file); +EDL EDL_parse(const char* text, size_t length); +char* EDL_dump(EDL edl); +void EDL_free(EDL edl); #ifdef __cplusplus } diff -r bd99b6549eb4 -r c2408abb258a include/str.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/str.h Mon Dec 25 16:24:16 2023 -0500 @@ -0,0 +1,17 @@ +#ifndef __edl__internal__str_h +#define __edl__internal__str_h + +#include + +typedef struct { + size_t size; + size_t capacity; + char* data; +} EDL_internal_string; + +int EDL_internal_string_init(EDL_internal_string* str); +int EDL_internal_string_allocate(EDL_internal_string* str, size_t new_capacity); +int EDL_internal_string_append(EDL_internal_string* str, const char* data, const size_t length); +void EDL_internal_string_free(EDL_internal_string* str); + +#endif // __edl__internal__str_h diff -r bd99b6549eb4 -r c2408abb258a src/edl.c --- a/src/edl.c Sun Dec 24 20:22:54 2023 -0500 +++ b/src/edl.c Mon Dec 25 16:24:16 2023 -0500 @@ -4,6 +4,7 @@ #include #include #include "edl.h" +#include "str.h" #define strnchr(haystack, needle, length) (char*)memchr(haystack, needle, strnlen(haystack, length)) @@ -29,9 +30,10 @@ 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] == ';') { + size_t len_until_newline = strchr(data, '\n') - data, len_until_cr = strchr(data, '\r') - data; + size_t i, b; + for (i = 0, b = 0; i <= len_until_newline && i <= len_until_cr; i++, b++) { + if (data[i] == ';' || data[i] == ':' || data[i] == '\r' || data[i] == '\n') { 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); @@ -39,7 +41,7 @@ } } - *length = current_hash; + *length = current_hash; // wtf? return hashes; } @@ -94,9 +96,9 @@ if (offset > length) return 0; - if (strncmp((input + offset), "TRUE", 4)) + if (!strncmp(&input[offset], "TRUE", 4)) *bool_return = true; - else if (strncmp((input + offset), "FALSE", 5)) + else if (!strncmp(&input[offset], "FALSE", 5)) *bool_return = false; return EDL_internal_append_offset(input, offset, length); @@ -106,10 +108,12 @@ if (offset > length) return 0; - if (strncmp(input + offset, "VIDEO", 5)) + if (!strncmp(&input[offset], "VIDEO", 5)) *media_return = MEDIATYPE_VIDEO; - else if (strncmp(input + offset, "AUDIO", 5)) + else if (!strncmp(&input[offset], "AUDIO", 5)) *media_return = MEDIATYPE_AUDIO; + else + *media_return = MEDIATYPE_UNKNOWN; return EDL_internal_append_offset(input, offset, length); } @@ -140,38 +144,30 @@ /* memory management routines */ -static int EDL_internal_reallocate(EDL_file* input, size_t new_capacity) { +static int EDL_internal_reallocate(EDL* 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); + memset(&input->arr[input->capacity], 0, (new_capacity - input->capacity) * sizeof(EDL_line)); 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)) +EDL EDL_parse(const char* data, size_t length) { + EDL edl = {0}; + if (!EDL_internal_reallocate(&edl, 16)) 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 offset = 0; + 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; @@ -272,12 +268,13 @@ case 0x3071a4c6: /* FirstChannel */ ADD_TO_OFFSET(first_channel, EDL_internal_get_int); break; - case 0x7de1bd40: /* Channels */ + case 0xe94981a4: /* Channels */ ADD_TO_OFFSET(channels, EDL_internal_get_int); break; default: /* ... what */ break; +#undef ADD_TO_OFFSET } } @@ -285,21 +282,187 @@ break; if (++edl.size >= edl.capacity) - EDL_internal_allocate_memory(&edl); + EDL_internal_reallocate(&edl, edl.capacity * 2); } - EDL_internal_shrink_memory_to_fit(&edl); + EDL_internal_reallocate(&edl, edl.size); free(order); return edl; } -void EDL_free(EDL_file file) { +static char* EDL_internal_integer_to_string(int value) { + char out[256] = {0}; // this ought to be enough. + snprintf(out, 256, "%d", value); + out[255] = '\0'; + return strdup(out); +} + +static char* EDL_internal_double_to_string(double value) { + char out[256] = {0}; + snprintf(out, 256, "%.6f", value); + out[255] = '\0'; + return strdup(out); +} + +static char* EDL_internal_bool_to_string(bool value) { + return strdup(value ? "TRUE" : "FALSE"); +} + +static char* EDL_internal_media_type_to_string(MediaType value) { + switch (value) { + case MEDIATYPE_AUDIO: + return strdup("AUDIO"); + case MEDIATYPE_VIDEO: + case MEDIATYPE_UNKNOWN: + default: + return strdup("VIDEO"); + } +} + +static void EDL_dump_line(EDL_internal_string* str, EDL_line line, const uint32_t* order, const size_t order_len) { + for (size_t i = 0; i < order_len; i++) { + switch (order[i]) { +#define APPEND_ITEM(a, x) \ +{ \ + char* tstr = x(line.a); \ + EDL_internal_string_append(str, tstr, strlen(tstr)); \ + free(tstr); \ +} + case 0x1541c503: /* ID */ + APPEND_ITEM(id, EDL_internal_integer_to_string); + break; + case 0x4b211812: /* Track */ + APPEND_ITEM(track, EDL_internal_integer_to_string); + break; + case 0xbb46516f: /* StartTime */ + APPEND_ITEM(start_time, EDL_internal_double_to_string); + break; + case 0xaeac5df7: /* Length */ + APPEND_ITEM(length, EDL_internal_double_to_string); + break; + case 0x03834606: /* PlayRate */ + APPEND_ITEM(play_rate, EDL_internal_double_to_string); + break; + case 0x0c2083d3: /* Locked */ + APPEND_ITEM(locked, EDL_internal_bool_to_string); + break; + case 0xe60c8b1d: /* Normalized */ + APPEND_ITEM(normalized, EDL_internal_bool_to_string); + break; + case 0xbe5802c9: /* StretchMethod */ + APPEND_ITEM(stretch_method, EDL_internal_integer_to_string); + break; + case 0x4ec8be4c: /* Looped */ + APPEND_ITEM(looped, EDL_internal_bool_to_string); + break; + case 0xe6cb84d1: /* OnRuler */ + APPEND_ITEM(on_ruler, EDL_internal_bool_to_string); + break; + case 0x035f84c2: /* MediaType */ + APPEND_ITEM(media_type, EDL_internal_media_type_to_string); + break; + case 0x379d32c5: /* FileName */ + EDL_internal_string_append(str, "\"", 1); + EDL_internal_string_append(str, line.filename, strlen(line.filename)); + EDL_internal_string_append(str, "\"", 1); + break; + case 0x9f334738: /* Stream */ + APPEND_ITEM(stream, EDL_internal_integer_to_string); + break; + case 0x07b4e0e7: /* StreamStart */ + APPEND_ITEM(stream_start, EDL_internal_double_to_string); + break; + case 0x8f16c7b8: /* StreamLength */ + APPEND_ITEM(stream_length, EDL_internal_double_to_string); + break; + case 0xd2edd7e4: /* FadeTimeIn */ + APPEND_ITEM(fade_time_in, EDL_internal_double_to_string); + break; + case 0x792e8c40: /* FadeTimeOut */ + APPEND_ITEM(fade_time_out, EDL_internal_double_to_string); + break; + case 0x98374657: /* SustainGain */ + APPEND_ITEM(sustain_gain, EDL_internal_double_to_string); + break; + case 0x3e998b1f: /* CurveIn */ + APPEND_ITEM(curve_in, EDL_internal_integer_to_string); + break; + case 0x82fb09c4: /* GainIn */ + APPEND_ITEM(gain_in, EDL_internal_double_to_string); + break; + case 0x53add388: /* CurveOut */ + APPEND_ITEM(curve_out, EDL_internal_integer_to_string); + break; + case 0x4210ba56: /* GainOut */ + APPEND_ITEM(gain_out, EDL_internal_double_to_string); + break; + case 0x89c4df6c: /* Layer */ + APPEND_ITEM(layer, EDL_internal_integer_to_string); + break; + case 0xadf2f1a3: /* Color */ + APPEND_ITEM(color, EDL_internal_integer_to_string); + break; + case 0xa56b43e1: /* CurveInR */ + APPEND_ITEM(curve_in_r, EDL_internal_integer_to_string); + break; + case 0xcb6d715e: /* CurveOutR */ + APPEND_ITEM(curve_out_r, EDL_internal_integer_to_string); + break; + case 0x9da1b9ed: /* PlayPitch */ + APPEND_ITEM(play_pitch, EDL_internal_double_to_string); + break; + case 0x2bda6ed4: /* LockPitch */ + APPEND_ITEM(lock_pitch, EDL_internal_bool_to_string); + break; + case 0x3071a4c6: /* FirstChannel */ + APPEND_ITEM(first_channel, EDL_internal_integer_to_string); + break; + case 0xe94981a4: /* Channels */ + APPEND_ITEM(channels, EDL_internal_integer_to_string); + break; + default: + /* ... what */ + break; +#undef APPEND_ITEM + } + + if (i < order_len - 1) + EDL_internal_string_append(str, ";\t", 2); + else + EDL_internal_string_append(str, ";", 1); + } + + EDL_internal_string_append(str, "\n", 1); +} + +char* EDL_dump(EDL edl) { + EDL_internal_string ret; + EDL_internal_string_init(&ret); + + static const char order_str[] = "\"ID\";\"Track\";\"StartTime\";\"Length\";\"PlayRate\";\"Locked\";\"Normalized\";\"StretchMethod\";\"Looped\";\"OnRuler\";\"MediaType\";\"FileName\";\"Stream\";\"StreamStart\";\"StreamLength\";\"FadeTimeIn\";\"FadeTimeOut\";\"SustainGain\";\"CurveIn\";\"GainIn\";\"CurveOut\";\"GainOut\";\"Layer\";\"Color\";\"CurveInR\";\"CurveOutR\":\"PlayPitch\";\"LockPitch\";\"FirstChannel\";\"Channels\"\n"; + EDL_internal_string_append(&ret, order_str, strlen(order_str)); + + size_t order_len; + uint32_t* order = EDL_internal_parse_first_line(order_str, &order_len); + size_t i; - for (i = 0; i < file.size; i++) { - if (file.arr[i].filename) - free(file.arr[i].filename); + for (i = 0; i < edl.size; i++) + EDL_dump_line(&ret, edl.arr[i], order, order_len); + + free(order); + + EDL_internal_string_allocate(&ret, ret.size); + + return ret.data; +} + +void EDL_free(EDL edl) { + size_t i; + for (i = 0; i < edl.size; i++) { + if (edl.arr[i].filename) + free(edl.arr[i].filename); } - free(file.arr); + free(edl.arr); } diff -r bd99b6549eb4 -r c2408abb258a src/str.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/str.c Mon Dec 25 16:24:16 2023 -0500 @@ -0,0 +1,51 @@ +#include +#include +#include "str.h" + +int EDL_internal_string_init(EDL_internal_string* str) { + if (!str) + return 0; + + str->size = 0; + str->capacity = 0; + str->data = NULL; + return 1; +} + +int EDL_internal_string_allocate(EDL_internal_string* str, size_t new_capacity) { + if (new_capacity == str->capacity) + return 1; // nothing to do + + str->data = realloc(str->data, new_capacity * sizeof(char)); + if (!str->data) + return 0; + + if (new_capacity > str->capacity) + memset(&str->data[str->capacity], 0, (new_capacity - str->capacity) * sizeof(char)); + + str->capacity = new_capacity; + + return 1; +} + +int EDL_internal_string_append(EDL_internal_string* str, const char* data, const size_t length) { + /* this sucks, but I'm too lazy to write anything smarter. */ + { + size_t capacity = 1; + while (capacity < (str->size + length + 1)) + capacity *= 2; + + if (capacity < str->capacity || !EDL_internal_string_allocate(str, capacity)) + return 0; + } + + strncat(str->data, data, length); + str->size += length; + + return 1; +} + +void EDL_internal_string_free(EDL_internal_string* str) { + if (str->data) + free(str->data); +}