Mercurial > libedl
changeset 8:0c98b46eaf73 v2.0
*: update API to 2.0, big changes
all APIs now use pointers to an EDL object. it is up to the
user to make sure that the pointer is valid.
additionally, many things have been separated into new files
to make it easier to digest
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Sun, 03 Mar 2024 17:56:58 -0500 |
parents | fee08fa622e1 |
children | 21aad49ed2c9 |
files | Makefile.am README.md configure.ac include/datatypes.h include/edl.h include/str.h include/util.h src/datatypes.c src/edl.c src/str.c src/util.c |
diffstat | 11 files changed, 480 insertions(+), 307 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile.am Mon Jan 15 06:42:30 2024 -0500 +++ b/Makefile.am Sun Mar 03 17:56:58 2024 -0500 @@ -1,6 +1,17 @@ lib_LTLIBRARIES = libedl.la -libedl_la_SOURCES = src/edl.c src/str.c + +noinst_HEADERS = \ + include/datatypes.h \ + include/str.h \ + include/util.h + include_HEADERS = include/edl.h +libedl_la_SOURCES = \ + src/edl.c \ + src/str.c \ + src/datatypes.c \ + src/util.c + AM_CPPFLAGS = -I$(srcdir)/include ACLOCAL_AMFLAGS = -I m4
--- a/README.md Mon Jan 15 06:42:30 2024 -0500 +++ b/README.md Sun Mar 03 17:56:58 2024 -0500 @@ -11,44 +11,65 @@ $ sudo make install ``` -## Usage +## Example ```c #include <stdio.h> #include <stdlib.h> -#include "edl.h" + +#include <edl.h> -int main() { +int file_get_contents(const char* file, char** contents, long* size) { /* open the file */ - FILE* file = fopen("MyProject.TXT", "rb"); + FILE* file = fopen(file, "rb"); if (!file) return 1; /* get filesize */ fseek(file, 0L, SEEK_END); - long fsize = ftell(file); + *size = ftell(file); fseek(file, 0L, SEEK_SET); /* grab the contents */ - char* data = malloc(fsize + 1); - if (!data) + *contents = malloc(*size + 1); + if (!*contents) return 1; - fread(data, fsize, 1, file); + /* hope and pray that `char` is 8-bit */ + fread(*contents, *size, 1, file); - data[fsize] = '\0'; + data[*size] = '\0'; fclose(file); +} - /* pass it to libedl */ - EDL edl = EDL_parse(data, fsize + 1); +int main(int argc, char** argv) { + char* data = NULL; + long size = 0; + EDL edl = {0}; + + if (argc != 2) + return 1; + + if (file_get_contents(argv[1], &data, &size)) + return 1; - /* dump the EDL to a string */ - char* edl_str = EDL_dump(edl); + /* if you know the amount of lines beforehand, + * you can preallocate the memory for libedl to use */ + EDL_reallocate(&edl, 1024); + + /* pass the file data to libedl + * + * it is also perfectly valid to use mmap() or + * variations of it (ex MapViewOfFile()) here... */ + EDL_parse(&edl, data, fsize + 1); + + /* dump the data to a valid EDL string */ + char* edl_str = EDL_dump(&edl); printf("%s\n", edl_str); free(edl_str); - /* free our memory */ - EDL_free(edl); + /* free our used memory; libedl allocates on the heap */ + EDL_free(&edl); free(data); return 0;
--- a/configure.ac Mon Jan 15 06:42:30 2024 -0500 +++ b/configure.ac Sun Mar 03 17:56:58 2024 -0500 @@ -1,4 +1,4 @@ -AC_INIT([libedl], [1.0]) +AC_INIT([libedl], [2.0]) AC_CONFIG_SRCDIR([src/edl.c]) AC_CONFIG_AUX_DIR([build-aux])
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/datatypes.h Sun Mar 03 17:56:58 2024 -0500 @@ -0,0 +1,18 @@ +#ifndef __edl__internal__datatypes_h +#define __edl__internal__datatypes_h + +#include <stddef.h> +#include "edl.h" /* EDL_media_type_t */ + +size_t EDL_internal_parse_int(const char* input, size_t offset, size_t length, int* int_return); +size_t EDL_internal_parse_double(const char* input, size_t offset, size_t length, double* double_return); +size_t EDL_internal_parse_bool(const char* input, size_t offset, size_t length, bool* bool_return); +size_t EDL_internal_parse_media_type(const char* input, size_t offset, size_t length, EDL_media_type_t* media_return); +size_t EDL_internal_parse_string(const char* input, size_t offset, size_t length, char** string_return); + +char* EDL_internal_integer_to_string(int value); +char* EDL_internal_double_to_string(double value); +char* EDL_internal_bool_to_string(bool value); +char* EDL_internal_media_type_to_string(EDL_media_type_t value); + +#endif /* __edl__internal__datatypes_h */
--- a/include/edl.h Mon Jan 15 06:42:30 2024 -0500 +++ b/include/edl.h Sun Mar 03 17:56:58 2024 -0500 @@ -12,7 +12,12 @@ MEDIATYPE_VIDEO, MEDIATYPE_AUDIO, MEDIATYPE_UNKNOWN -} MediaType; +} EDL_media_type_t; + +typedef enum { + EDL_PARSE_ERROR_SUCCESS = 0, + EDL_PARSE_ERROR_OUT_OF_MEMORY +} EDL_parse_error_t; typedef struct { int id; @@ -25,7 +30,7 @@ int stretch_method; bool looped; bool on_ruler; - MediaType media_type; + EDL_media_type_t media_type; char* filename; int stream; double stream_start; @@ -53,10 +58,10 @@ size_t size; } EDL; -EDL EDL_parse(const char* text, size_t length); +EDL_parse_error_t EDL_parse(EDL* edl, const char* text, size_t length); int EDL_reallocate(EDL* edl, size_t new_capacity); -char* EDL_dump(EDL edl); -void EDL_free(EDL edl); +char* EDL_dump(const EDL* edl); +void EDL_free(EDL* edl); #ifdef __cplusplus }
--- a/include/str.h Mon Jan 15 06:42:30 2024 -0500 +++ b/include/str.h Sun Mar 03 17:56:58 2024 -0500 @@ -14,4 +14,4 @@ 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 +#endif /* __edl__internal__str_h */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/util.h Sun Mar 03 17:56:58 2024 -0500 @@ -0,0 +1,10 @@ +#ifndef __edl__internal__util_h +#define __edl__internal__util_h + +#include <stddef.h> + +size_t EDL_internal_strnlen(const char* s, size_t maxlen); +char* EDL_internal_strnchr(const char* haystack, char needle, size_t length); +char* EDL_internal_strdup(const char* s); + +#endif /* __edl__internal__util_h */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/datatypes.c Sun Mar 03 17:56:58 2024 -0500 @@ -0,0 +1,130 @@ +#include "datatypes.h" +#include "util.h" + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +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; +} + +size_t EDL_internal_parse_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); +} + +size_t EDL_internal_parse_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); +} + +size_t EDL_internal_parse_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); +} + +size_t EDL_internal_parse_media_type(const char* input, size_t offset, size_t length, EDL_media_type_t* 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; + else + *media_return = MEDIATYPE_UNKNOWN; + + return EDL_internal_append_offset(input, offset, length); +} + +size_t EDL_internal_parse_string(const char* input, size_t offset, size_t length, char** string_return) { + size_t start, s_length; + + /* will most definitely break on good filesystems */ + if (offset > length) + return 0; + + start = strchr(&input[offset], '\"') - &input[offset] + 1; + if (start + offset > length) + return 0; + + 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); +} + +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 EDL_internal_strdup(out); +} + +char* EDL_internal_double_to_string(double value) { + char out[256] = {0}; + snprintf(out, 256, "%.6f", value); + out[255] = '\0'; + return EDL_internal_strdup(out); +} + +char* EDL_internal_bool_to_string(bool value) { + return EDL_internal_strdup(value ? "TRUE" : "FALSE"); +} + +char* EDL_internal_media_type_to_string(EDL_media_type_t value) { + switch (value) { + case MEDIATYPE_AUDIO: + return EDL_internal_strdup("AUDIO"); + case MEDIATYPE_VIDEO: + case MEDIATYPE_UNKNOWN: + default: + return EDL_internal_strdup("VIDEO"); + } +}
--- a/src/edl.c Mon Jan 15 06:42:30 2024 -0500 +++ b/src/edl.c Sun Mar 03 17:56:58 2024 -0500 @@ -3,273 +3,229 @@ #include <stdio.h> #include <stdlib.h> #include <stdint.h> + #include "edl.h" #include "str.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; +#include "datatypes.h" +#include "util.h" +/* CRC32 hashes of EDL headers */ +#define EDL_HEADER_ID 0x1541c503 +#define EDL_HEADER_TRACK 0x4b211812 +#define EDL_HEADER_STARTTIME 0xbb46516f +#define EDL_HEADER_LENGTH 0xaeac5df7 +#define EDL_HEADER_PLAYRATE 0x03834606 +#define EDL_HEADER_LOCKED 0x0c2083d3 +#define EDL_HEADER_NORMALIZED 0xe60c8b1d +#define EDL_HEADER_STRETCHMETHOD 0xbe5802c9 +#define EDL_HEADER_LOOPED 0x4ec8be4c +#define EDL_HEADER_ONRULER 0xe6cb84d1 +#define EDL_HEADER_MEDIATYPE 0x035f84c2 +#define EDL_HEADER_FILENAME 0x379d32c5 +#define EDL_HEADER_STREAM 0x9f334738 +#define EDL_HEADER_STREAMSTART 0x07b4e0e7 +#define EDL_HEADER_STREAMLENGTH 0x8f16c7b8 +#define EDL_HEADER_FADETIMEIN 0xd2edd7e4 +#define EDL_HEADER_FADETIMEOUT 0x792e8c40 +#define EDL_HEADER_SUSTAINGAIN 0x98374657 +#define EDL_HEADER_CURVEIN 0x3e998b1f +#define EDL_HEADER_GAININ 0x82fb09c4 +#define EDL_HEADER_CURVEOUT 0x53add388 +#define EDL_HEADER_GAINOUT 0x4210ba56 +#define EDL_HEADER_LAYER 0x89c4df6c +#define EDL_HEADER_COLOR 0xadf2f1a3 +#define EDL_HEADER_CURVEINR 0xa56b43e1 +#define EDL_HEADER_CURVEOUTR 0xcb6d715e +#define EDL_HEADER_PLAYPITCH 0x9da1b9ed +#define EDL_HEADER_LOCKPITCH 0x2bda6ed4 +#define EDL_HEADER_FIRSTCHANNEL 0x3071a4c6 +#define EDL_HEADER_CHANNELS 0xe94981a4 + +/* use a CRC32 hash function to process the headers */ +static uint32_t EDL_internal_crcn32b(const unsigned char* message, size_t length) { + uint32_t crc = 0xffffffff; size_t i; + for (i = 0; i < length && message[i]; i++) { + size_t j; + crc = crc ^ message[i]; - size_t j; for (j = 0; j < 8; j++) - crc = (crc >> 1) ^ (0xEDB88320 & -(crc & 1)); + 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 size_t EDL_internal_size_t_min(size_t a, size_t b) { + return (a < b) ? a : b; +} + +/* This parses the header 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; +static uint32_t* EDL_internal_parse_header(const char* data, size_t* length) { + /* */ + const size_t newline = EDL_internal_size_t_min(strchr(data, '\n') - data, strchr(data, '\r') - data); + + size_t current_hash = 0, hashes_size = 32; uint32_t* hashes = malloc(hashes_size * sizeof(uint32_t)); - 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) + /* overall iterates over the entire line, + * column stores the length of the current column */ + size_t overall, column; + + for (overall = 0, column = 0; overall <= newline; overall++) { + if (data[overall] == ';' || data[overall] == ':') { + /* process the current column */ + if (hashes_size < current_hash) 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 - } + + hashes[current_hash++] = EDL_internal_crcn32b((const unsigned char*)&data[overall - column], column); + column = 0; /* reset */ + } else column++; } - *length = current_hash; // wtf? + *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) +int EDL_reallocate(EDL* edl, size_t new_capacity) { + edl->arr = realloc(edl->arr, new_capacity * sizeof(EDL_line)); + if (!edl->arr) 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; - else - *media_return = MEDIATYPE_UNKNOWN; - - 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; + if (new_capacity > edl->capacity) + memset(&edl->arr[edl->capacity], 0, (new_capacity - edl->capacity) * sizeof(EDL_line)); - 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 */ - -int EDL_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) * sizeof(EDL_line)); - - input->capacity = new_capacity; + edl->capacity = new_capacity; return 1; } -/* the important function */ -EDL EDL_parse(const char* data, size_t length) { - EDL edl = {0}; - if (!EDL_reallocate(&edl, 16)) - return edl; +int EDL_append(EDL* edl, EDL_line line) { + if (edl->size + 1 < edl->capacity && !EDL_reallocate(edl, edl->capacity)) + return 0; + edl->arr[++edl->size] = line; + return 1; +} + +/* the big important function */ +EDL_parse_error_t EDL_parse(EDL* edl, const char* data, size_t length) { size_t order_size = 0; - uint32_t* order = EDL_internal_parse_first_line(data, &order_size); - + uint32_t* order = NULL; 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 + + if (!EDL_reallocate(edl, 16)) + return EDL_PARSE_ERROR_OUT_OF_MEMORY; + + order = EDL_internal_parse_header(data, &order_size); + while ((offset = EDL_internal_strnchr(&data[offset], '\n', length - offset) - data + 1) < length) { + size_t local_offset = offset; /* original offset stays intact */ bool ok = true; + int i; - for (int i = 0; i < order_size; i++) { + for (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); \ + 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); + case EDL_HEADER_ID: + ADD_TO_OFFSET(id, EDL_internal_parse_int); break; - case 0x4b211812: /* Track */ - ADD_TO_OFFSET(track, EDL_internal_get_int); + case EDL_HEADER_TRACK: + ADD_TO_OFFSET(track, EDL_internal_parse_int); break; - case 0xbb46516f: /* StartTime */ - ADD_TO_OFFSET(start_time, EDL_internal_get_double); + case EDL_HEADER_STARTTIME: + ADD_TO_OFFSET(start_time, EDL_internal_parse_double); break; - case 0xaeac5df7: /* Length */ - ADD_TO_OFFSET(length, EDL_internal_get_double); + case EDL_HEADER_LENGTH: + ADD_TO_OFFSET(length, EDL_internal_parse_double); break; - case 0x03834606: /* PlayRate */ - ADD_TO_OFFSET(play_rate, EDL_internal_get_double); + case EDL_HEADER_PLAYRATE: + ADD_TO_OFFSET(play_rate, EDL_internal_parse_double); break; - case 0x0c2083d3: /* Locked */ - ADD_TO_OFFSET(locked, EDL_internal_get_bool); + case EDL_HEADER_LOCKED: + ADD_TO_OFFSET(locked, EDL_internal_parse_bool); break; - case 0xe60c8b1d: /* Normalized */ - ADD_TO_OFFSET(normalized, EDL_internal_get_bool); + case EDL_HEADER_NORMALIZED: + ADD_TO_OFFSET(normalized, EDL_internal_parse_bool); break; - case 0xbe5802c9: /* StretchMethod */ - ADD_TO_OFFSET(stretch_method, EDL_internal_get_int); + case EDL_HEADER_STRETCHMETHOD: + ADD_TO_OFFSET(stretch_method, EDL_internal_parse_int); break; - case 0x4ec8be4c: /* Looped */ - ADD_TO_OFFSET(looped, EDL_internal_get_bool); + case EDL_HEADER_LOOPED: + ADD_TO_OFFSET(looped, EDL_internal_parse_bool); break; - case 0xe6cb84d1: /* OnRuler */ - ADD_TO_OFFSET(on_ruler, EDL_internal_get_bool); + case EDL_HEADER_ONRULER: + ADD_TO_OFFSET(on_ruler, EDL_internal_parse_bool); break; - case 0x035f84c2: /* MediaType */ - ADD_TO_OFFSET(media_type, EDL_internal_get_media_type); + case EDL_HEADER_MEDIATYPE: + ADD_TO_OFFSET(media_type, EDL_internal_parse_media_type); break; - case 0x379d32c5: /* FileName */ - ADD_TO_OFFSET(filename, EDL_internal_get_string); + case EDL_HEADER_FILENAME: + ADD_TO_OFFSET(filename, EDL_internal_parse_string); break; - case 0x9f334738: /* Stream */ - ADD_TO_OFFSET(stream, EDL_internal_get_int); + case EDL_HEADER_STREAM: + ADD_TO_OFFSET(stream, EDL_internal_parse_int); break; - case 0x07b4e0e7: /* StreamStart */ - ADD_TO_OFFSET(stream_start, EDL_internal_get_double); + case EDL_HEADER_STREAMSTART: + ADD_TO_OFFSET(stream_start, EDL_internal_parse_double); break; - case 0x8f16c7b8: /* StreamLength */ - ADD_TO_OFFSET(stream_length, EDL_internal_get_double); + case EDL_HEADER_STREAMLENGTH: + ADD_TO_OFFSET(stream_length, EDL_internal_parse_double); break; - case 0xd2edd7e4: /* FadeTimeIn */ - ADD_TO_OFFSET(fade_time_in, EDL_internal_get_double); + case EDL_HEADER_FADETIMEIN: + ADD_TO_OFFSET(fade_time_in, EDL_internal_parse_double); break; - case 0x792e8c40: /* FadeTimeOut */ - ADD_TO_OFFSET(fade_time_out, EDL_internal_get_double); + case EDL_HEADER_FADETIMEOUT: + ADD_TO_OFFSET(fade_time_out, EDL_internal_parse_double); break; - case 0x98374657: /* SustainGain */ - ADD_TO_OFFSET(sustain_gain, EDL_internal_get_double); + case EDL_HEADER_SUSTAINGAIN: + ADD_TO_OFFSET(sustain_gain, EDL_internal_parse_double); break; - case 0x3e998b1f: /* CurveIn */ - ADD_TO_OFFSET(curve_in, EDL_internal_get_int); + case EDL_HEADER_CURVEIN: + ADD_TO_OFFSET(curve_in, EDL_internal_parse_int); break; - case 0x82fb09c4: /* GainIn */ - ADD_TO_OFFSET(gain_in, EDL_internal_get_double); + case EDL_HEADER_GAININ: + ADD_TO_OFFSET(gain_in, EDL_internal_parse_double); break; - case 0x53add388: /* CurveOut */ - ADD_TO_OFFSET(curve_out, EDL_internal_get_int); + case EDL_HEADER_CURVEOUT: + ADD_TO_OFFSET(curve_out, EDL_internal_parse_int); break; - case 0x4210ba56: /* GainOut */ - ADD_TO_OFFSET(gain_out, EDL_internal_get_double); + case EDL_HEADER_GAINOUT: + ADD_TO_OFFSET(gain_out, EDL_internal_parse_double); break; - case 0x89c4df6c: /* Layer */ - ADD_TO_OFFSET(layer, EDL_internal_get_int); + case EDL_HEADER_LAYER: + ADD_TO_OFFSET(layer, EDL_internal_parse_int); break; - case 0xadf2f1a3: /* Color */ - ADD_TO_OFFSET(color, EDL_internal_get_int); + case EDL_HEADER_COLOR: + ADD_TO_OFFSET(color, EDL_internal_parse_int); break; - case 0xa56b43e1: /* CurveInR */ - ADD_TO_OFFSET(curve_in_r, EDL_internal_get_int); + case EDL_HEADER_CURVEINR: + ADD_TO_OFFSET(curve_in_r, EDL_internal_parse_int); break; - case 0xcb6d715e: /* CurveOutR */ - ADD_TO_OFFSET(curve_out_r, EDL_internal_get_int); + case EDL_HEADER_CURVEOUTR: + ADD_TO_OFFSET(curve_out_r, EDL_internal_parse_int); break; - case 0x9da1b9ed: /* PlayPitch */ - ADD_TO_OFFSET(play_pitch, EDL_internal_get_double); + case EDL_HEADER_PLAYPITCH: + ADD_TO_OFFSET(play_pitch, EDL_internal_parse_double); break; - case 0x2bda6ed4: /* LockPitch */ - ADD_TO_OFFSET(lock_pitch, EDL_internal_get_bool); + case EDL_HEADER_LOCKPITCH: + ADD_TO_OFFSET(lock_pitch, EDL_internal_parse_bool); break; - case 0x3071a4c6: /* FirstChannel */ - ADD_TO_OFFSET(first_channel, EDL_internal_get_int); + case EDL_HEADER_FIRSTCHANNEL: + ADD_TO_OFFSET(first_channel, EDL_internal_parse_int); break; - case 0xe94981a4: /* Channels */ - ADD_TO_OFFSET(channels, EDL_internal_get_int); + case EDL_HEADER_CHANNELS: + ADD_TO_OFFSET(channels, EDL_internal_parse_int); break; default: /* ... what */ @@ -281,145 +237,119 @@ if (!ok) break; - if (++edl.size >= edl.capacity) - EDL_reallocate(&edl, edl.capacity * 2); + if (++edl->size >= edl->capacity) + EDL_reallocate(edl, edl->capacity * 2); } - EDL_reallocate(&edl, edl.size); + /* put on the shrinkwrap */ + EDL_reallocate(edl, edl->size); free(order); - return edl; -} - -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); + return EDL_PARSE_ERROR_SUCCESS; } -static char* EDL_internal_bool_to_string(bool value) { - return strdup(value ? "TRUE" : "FALSE"); -} +static void EDL_dump_line(EDL_internal_string* str, const EDL_line* line, const uint32_t* order, const size_t order_len) { + size_t i; -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++) { + for (i = 0; i < order_len; i++) { switch (order[i]) { #define APPEND_ITEM(a, x) \ { \ - char* tstr = x(line.a); \ + char* tstr = x(line->a); \ EDL_internal_string_append(str, tstr, strlen(tstr)); \ free(tstr); \ } - case 0x1541c503: /* ID */ + case EDL_HEADER_ID: APPEND_ITEM(id, EDL_internal_integer_to_string); break; - case 0x4b211812: /* Track */ + case EDL_HEADER_TRACK: APPEND_ITEM(track, EDL_internal_integer_to_string); break; - case 0xbb46516f: /* StartTime */ + case EDL_HEADER_STARTTIME: APPEND_ITEM(start_time, EDL_internal_double_to_string); break; - case 0xaeac5df7: /* Length */ + case EDL_HEADER_LENGTH: APPEND_ITEM(length, EDL_internal_double_to_string); break; - case 0x03834606: /* PlayRate */ + case EDL_HEADER_PLAYRATE: APPEND_ITEM(play_rate, EDL_internal_double_to_string); break; - case 0x0c2083d3: /* Locked */ + case EDL_HEADER_LOCKED: APPEND_ITEM(locked, EDL_internal_bool_to_string); break; - case 0xe60c8b1d: /* Normalized */ + case EDL_HEADER_NORMALIZED: APPEND_ITEM(normalized, EDL_internal_bool_to_string); break; - case 0xbe5802c9: /* StretchMethod */ + case EDL_HEADER_STRETCHMETHOD: APPEND_ITEM(stretch_method, EDL_internal_integer_to_string); break; - case 0x4ec8be4c: /* Looped */ + case EDL_HEADER_LOOPED: APPEND_ITEM(looped, EDL_internal_bool_to_string); break; - case 0xe6cb84d1: /* OnRuler */ + case EDL_HEADER_ONRULER: APPEND_ITEM(on_ruler, EDL_internal_bool_to_string); break; - case 0x035f84c2: /* MediaType */ + case EDL_HEADER_MEDIATYPE: APPEND_ITEM(media_type, EDL_internal_media_type_to_string); break; - case 0x379d32c5: /* FileName */ + case EDL_HEADER_FILENAME: EDL_internal_string_append(str, "\"", 1); - EDL_internal_string_append(str, line.filename, strlen(line.filename)); + EDL_internal_string_append(str, line->filename, strlen(line->filename)); EDL_internal_string_append(str, "\"", 1); break; - case 0x9f334738: /* Stream */ + case EDL_HEADER_STREAM: APPEND_ITEM(stream, EDL_internal_integer_to_string); break; - case 0x07b4e0e7: /* StreamStart */ + case EDL_HEADER_STREAMSTART: APPEND_ITEM(stream_start, EDL_internal_double_to_string); break; - case 0x8f16c7b8: /* StreamLength */ + case EDL_HEADER_STREAMLENGTH: APPEND_ITEM(stream_length, EDL_internal_double_to_string); break; - case 0xd2edd7e4: /* FadeTimeIn */ + case EDL_HEADER_FADETIMEIN: APPEND_ITEM(fade_time_in, EDL_internal_double_to_string); break; - case 0x792e8c40: /* FadeTimeOut */ + case EDL_HEADER_FADETIMEOUT: APPEND_ITEM(fade_time_out, EDL_internal_double_to_string); break; - case 0x98374657: /* SustainGain */ + case EDL_HEADER_SUSTAINGAIN: APPEND_ITEM(sustain_gain, EDL_internal_double_to_string); break; - case 0x3e998b1f: /* CurveIn */ + case EDL_HEADER_CURVEIN: APPEND_ITEM(curve_in, EDL_internal_integer_to_string); break; - case 0x82fb09c4: /* GainIn */ + case EDL_HEADER_GAININ: APPEND_ITEM(gain_in, EDL_internal_double_to_string); break; - case 0x53add388: /* CurveOut */ + case EDL_HEADER_CURVEOUT: APPEND_ITEM(curve_out, EDL_internal_integer_to_string); break; - case 0x4210ba56: /* GainOut */ + case EDL_HEADER_GAINOUT: APPEND_ITEM(gain_out, EDL_internal_double_to_string); break; - case 0x89c4df6c: /* Layer */ + case EDL_HEADER_LAYER: APPEND_ITEM(layer, EDL_internal_integer_to_string); break; - case 0xadf2f1a3: /* Color */ + case EDL_HEADER_COLOR: APPEND_ITEM(color, EDL_internal_integer_to_string); break; - case 0xa56b43e1: /* CurveInR */ + case EDL_HEADER_CURVEINR: APPEND_ITEM(curve_in_r, EDL_internal_integer_to_string); break; - case 0xcb6d715e: /* CurveOutR */ + case EDL_HEADER_CURVEOUTR: APPEND_ITEM(curve_out_r, EDL_internal_integer_to_string); break; - case 0x9da1b9ed: /* PlayPitch */ + case EDL_HEADER_PLAYPITCH: APPEND_ITEM(play_pitch, EDL_internal_double_to_string); break; - case 0x2bda6ed4: /* LockPitch */ + case EDL_HEADER_LOCKPITCH: APPEND_ITEM(lock_pitch, EDL_internal_bool_to_string); break; - case 0x3071a4c6: /* FirstChannel */ + case EDL_HEADER_FIRSTCHANNEL: APPEND_ITEM(first_channel, EDL_internal_integer_to_string); break; - case 0xe94981a4: /* Channels */ + case EDL_HEADER_CHANNELS: APPEND_ITEM(channels, EDL_internal_integer_to_string); break; default: @@ -437,32 +367,38 @@ EDL_internal_string_append(str, "\n", 1); } -char* EDL_dump(EDL edl) { +/* this gets progressively slower and slower... oops */ +char* EDL_dump(const EDL* edl) { + 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 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 order_len; + uint32_t* order = EDL_internal_parse_header(order_str, &order_len); - size_t i; - for (i = 0; i < edl.size; i++) - EDL_dump_line(&ret, edl.arr[i], order, order_len); + size_t i; + 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); + free(order); + } return ret.data; } -void EDL_free(EDL edl) { +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); + for (i = 0; i < edl->size; i++) { + if (edl->arr[i].filename) + free(edl->arr[i].filename); } - free(edl.arr); + free(edl->arr); }
--- a/src/str.c Mon Jan 15 06:42:30 2024 -0500 +++ b/src/str.c Sun Mar 03 17:56:58 2024 -0500 @@ -1,6 +1,11 @@ +#include "str.h" + #include <stdlib.h> #include <string.h> -#include "str.h" + +/* rudimentary string functions so the code in edl.c isn't + * as painful to read +*/ int EDL_internal_string_init(EDL_internal_string* str) { if (!str) @@ -14,14 +19,14 @@ int EDL_internal_string_allocate(EDL_internal_string* str, size_t new_capacity) { if (new_capacity == str->capacity) - return 1; // nothing to do + 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)); + //if (new_capacity > str->capacity) + // memset(&str->data[str->capacity], 0, (new_capacity - str->capacity) * sizeof(char)); str->capacity = new_capacity; @@ -29,19 +34,23 @@ } int EDL_internal_string_append(EDL_internal_string* str, const char* data, const size_t length) { - { + if (str->capacity == 0) + if (!EDL_internal_string_allocate(str, 1)) + return 0; + + if (str->size + length + 1 >= str->capacity) { size_t capacity = 1; while (capacity < (str->size + length + 1)) capacity *= 2; - if (capacity < str->capacity || !EDL_internal_string_allocate(str, capacity)) + if (!EDL_internal_string_allocate(str, capacity)) return 0; } strncat(str->data, data, length); str->size += length; - return 1; + return length; } void EDL_internal_string_free(EDL_internal_string* str) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/util.c Sun Mar 03 17:56:58 2024 -0500 @@ -0,0 +1,33 @@ +#include "util.h" + +#include <stdlib.h> +#include <string.h> + +/* reimplementations of non-portable stdlib functions */ + +size_t EDL_internal_strnlen(const char* s, size_t maxlen) { + size_t len; + + for (len = 0; len < maxlen; len++, s++) { + if (!*s) + break; + } + + return len; +} + +char* EDL_internal_strnchr(const char* haystack, char needle, size_t length) { + for (; length && *haystack != needle; haystack++, length--); + + return length ? haystack : NULL; +} + +char* EDL_internal_strdup(const char* s) { + const size_t len = strlen(s); + + char* d = malloc((len + 1) * sizeof(char)); + memcpy(d, s, len * sizeof(char)); + d[len] = '\0'; + + return d; +}