# HG changeset patch # User Paper # Date 1711561110 14400 # Node ID 0cc2555db371178716cdb0d2f2ec059c24d5d9a2 # Parent a0bd92c4c0e8ff9fe1e4f1fde22a77584b41eaa8 *: make our string functions not stupid strncat() made everything slow! new addition internally: an EDL_header structure to make things not stupid. if we were using C++ it wouldn't really be necessary, but alas :) diff -r a0bd92c4c0e8 -r 0cc2555db371 README.md --- a/README.md Fri Mar 22 20:51:46 2024 -0400 +++ b/README.md Wed Mar 27 13:38:30 2024 -0400 @@ -18,9 +18,9 @@ #include -int file_get_contents(const char* file, char** contents, long* size) { +int file_get_contents(const char* f, char** contents, long* size) { /* open the file */ - FILE* file = fopen(file, "rb"); + FILE* file = fopen(f, "rb"); if (!file) return 1; @@ -37,7 +37,7 @@ /* hope and pray that `char` is 8-bit */ fread(*contents, *size, 1, file); - data[*size] = '\0'; + (*contents)[*size] = '\0'; fclose(file); } @@ -61,7 +61,7 @@ * * it is also perfectly valid to use mmap() or * variations of it (ex MapViewOfFile()) here... */ - EDL_parse(&edl, data, fsize + 1); + EDL_parse(&edl, data, size + 1); /* dump the data to a valid EDL string */ char* edl_str = EDL_dump(&edl); diff -r a0bd92c4c0e8 -r 0cc2555db371 include/datatypes.h --- a/include/datatypes.h Fri Mar 22 20:51:46 2024 -0400 +++ b/include/datatypes.h Wed Mar 27 13:38:30 2024 -0400 @@ -3,6 +3,7 @@ #include #include "edl.h" /* EDL_media_type_t */ +#include "str.h" 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); @@ -10,9 +11,9 @@ 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); +int EDL_internal_append_integer_to_string(EDL_internal_string* str, int value); +int EDL_internal_append_double_to_string(EDL_internal_string* str, double value); +int EDL_internal_append_bool_to_string(EDL_internal_string* str, bool value); +int EDL_internal_append_media_type_to_string(EDL_internal_string* str, EDL_media_type_t value); #endif /* __edl__internal__datatypes_h */ diff -r a0bd92c4c0e8 -r 0cc2555db371 include/edl.h --- a/include/edl.h Fri Mar 22 20:51:46 2024 -0400 +++ b/include/edl.h Wed Mar 27 13:38:30 2024 -0400 @@ -16,7 +16,8 @@ typedef enum { EDL_PARSE_ERROR_SUCCESS = 0, - EDL_PARSE_ERROR_OUT_OF_MEMORY + EDL_PARSE_ERROR_OUT_OF_MEMORY, + EDL_PARSE_ERROR_HEADER } EDL_parse_error_t; typedef struct { diff -r a0bd92c4c0e8 -r 0cc2555db371 src/datatypes.c --- a/src/datatypes.c Fri Mar 22 20:51:46 2024 -0400 +++ b/src/datatypes.c Wed Mar 27 13:38:30 2024 -0400 @@ -1,5 +1,6 @@ #include "datatypes.h" #include "util.h" +#include "str.h" #include #include @@ -100,31 +101,33 @@ 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); +int EDL_internal_append_integer_to_string(EDL_internal_string* str, int value) { + char out[32] = {0}; /* this ought to be enough. */ + int c = snprintf(out, 32, "%d", value); + return EDL_internal_string_append(str, out, (c < 32) ? c : 32); +} + +int EDL_internal_append_double_to_string(EDL_internal_string* str, double value) { + char out[128] = {0}; + int c = snprintf(out, 128, "%.6f", value); + return EDL_internal_string_append(str, out, (c < 128) ? c : 128); } -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); +int EDL_internal_append_bool_to_string(EDL_internal_string* str, bool value) { + if (value) { + EDL_internal_string_append(str, "TRUE", 4); + } else { + EDL_internal_string_append(str, "FALSE", 5); + } } -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) { +int EDL_internal_append_media_type_to_string(EDL_internal_string* str, EDL_media_type_t value) { switch (value) { case MEDIATYPE_AUDIO: - return EDL_internal_strdup("AUDIO"); + return EDL_internal_string_append(str, "AUDIO", 5); case MEDIATYPE_VIDEO: case MEDIATYPE_UNKNOWN: default: - return EDL_internal_strdup("VIDEO"); + return EDL_internal_string_append(str, "VIDEO", 5); } } diff -r a0bd92c4c0e8 -r 0cc2555db371 src/edl.c --- a/src/edl.c Fri Mar 22 20:51:46 2024 -0400 +++ b/src/edl.c Wed Mar 27 13:38:30 2024 -0400 @@ -41,6 +41,12 @@ #define EDL_HEADER_FIRSTCHANNEL 0x3071a4c6 #define EDL_HEADER_CHANNELS 0xe94981a4 +typedef struct { + uint32_t* order; + size_t size; + size_t capacity; +} EDL_header; + /* 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; @@ -61,47 +67,69 @@ 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_header(const char* data, size_t* length) { - /* */ - const size_t newline = EDL_internal_size_t_min(strchr(data, '\n') - data, strchr(data, '\r') - data); +static int EDL_internal_header_reallocate(EDL_header* header, size_t new_capacity) { + header->order = realloc(header->order, new_capacity * sizeof(*header->order)); + if (!header->order) + return -1; + + if (new_capacity > header->capacity) + memset(&header->order[header->capacity], 0, (new_capacity - header->capacity) * sizeof(*header->order)); + + header->capacity = new_capacity; - size_t current_hash = 0, hashes_size = 32; - uint32_t* hashes = malloc(hashes_size * sizeof(uint32_t)); + return header->capacity; +} + +static int EDL_internal_parse_header_item(EDL_header* header, const char* data, size_t offset, size_t length) { + if (header->capacity <= header->size) + if (EDL_internal_header_reallocate(header, header->capacity * 2) < 0) + return -1; + + header->order[header->size++] = EDL_internal_crcn32b((const unsigned char*)&data[offset], length); - /* overall iterates over the entire line, - * column stores the length of the current column */ - size_t overall, column; + return header->size; +} + +/* EDL_header MUST be zero-initialized. */ +static int EDL_internal_parse_header(EDL_header* header, const char* data, size_t offset, size_t length) { + size_t newline = 0, overall = 0, column = 0; + { + const char* ln = memchr(&data[offset], '\n', length - offset); + if (!ln) + return -1; - 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)); + newline = ln - &data[offset]; + } + + EDL_internal_header_reallocate(header, 32); - hashes[current_hash++] = EDL_internal_crcn32b((const unsigned char*)&data[overall - column], column); + for (; overall <= newline; overall++) { + if (data[offset + overall] == ';' || data[offset + overall] == ':') { + if (EDL_internal_parse_header_item(header, data, overall - column, column) < 0) + return -1; + column = 0; /* reset */ } else column++; } - *length = current_hash; + return overall; +} - return hashes; +static int EDL_internal_free_header(EDL_header* header) { + free(header->order); } int EDL_reallocate(EDL* edl, size_t new_capacity) { edl->arr = realloc(edl->arr, new_capacity * sizeof(EDL_line)); if (!edl->arr) - return 0; + return -1; if (new_capacity > edl->capacity) memset(&edl->arr[edl->capacity], 0, (new_capacity - edl->capacity) * sizeof(EDL_line)); edl->capacity = new_capacity; - return 1; + return edl->capacity; } int EDL_append(EDL* edl, EDL_line line) { @@ -114,21 +142,21 @@ /* 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 = NULL; size_t offset = 0; + EDL_header header = {0}; - if (!EDL_reallocate(edl, 16)) + if (EDL_reallocate(edl, 16) < 0) return EDL_PARSE_ERROR_OUT_OF_MEMORY; - order = EDL_internal_parse_header(data, &order_size); + if (EDL_internal_parse_header(&header, data, offset, length) < 0) + return EDL_PARSE_ERROR_HEADER; - while ((offset = EDL_internal_strnchr(&data[offset], '\n', length - offset) - data + 1) < length) { + while ((offset = (const char*)memchr(&data[offset], '\n', length - offset) - data + 1) < length) { size_t local_offset = offset; /* original offset stays intact */ bool ok = true; int i; - for (i = 0; i < order_size; i++) { + for (i = 0; i < header.size; i++) { #define ADD_TO_OFFSET(x, a) \ { \ size_t o = a(data, local_offset, length, &edl->arr[edl->size].x); \ @@ -136,7 +164,7 @@ ok = false; \ local_offset += o; \ } - switch (order[i]) { + switch (header.order[i]) { case EDL_HEADER_ID: ADD_TO_OFFSET(id, EDL_internal_parse_int); break; @@ -238,60 +266,56 @@ break; if (++edl->size >= edl->capacity) - EDL_reallocate(edl, edl->capacity * 2); + if (EDL_reallocate(edl, edl->capacity * 2) < 0) + return EDL_PARSE_ERROR_OUT_OF_MEMORY; } + EDL_internal_free_header(&header); + /* put on the shrinkwrap */ - EDL_reallocate(edl, edl->size); - - free(order); + if (EDL_reallocate(edl, edl->size) < 0) + return EDL_PARSE_ERROR_OUT_OF_MEMORY; return EDL_PARSE_ERROR_SUCCESS; } -static void EDL_dump_line(EDL_internal_string* str, const EDL_line* line, const uint32_t* order, const size_t order_len) { +static void EDL_dump_line(EDL_internal_string* str, const EDL_line* line, const EDL_header* header) { size_t i; - for (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); \ -} + for (i = 0; i < header->size; i++) { + switch (header->order[i]) { case EDL_HEADER_ID: - APPEND_ITEM(id, EDL_internal_integer_to_string); + EDL_internal_append_integer_to_string(str, line->id); break; case EDL_HEADER_TRACK: - APPEND_ITEM(track, EDL_internal_integer_to_string); + EDL_internal_append_integer_to_string(str, line->track); break; case EDL_HEADER_STARTTIME: - APPEND_ITEM(start_time, EDL_internal_double_to_string); + EDL_internal_append_double_to_string(str, line->start_time); break; case EDL_HEADER_LENGTH: - APPEND_ITEM(length, EDL_internal_double_to_string); + EDL_internal_append_double_to_string(str, line->length); break; case EDL_HEADER_PLAYRATE: - APPEND_ITEM(play_rate, EDL_internal_double_to_string); + EDL_internal_append_double_to_string(str, line->play_rate); break; case EDL_HEADER_LOCKED: - APPEND_ITEM(locked, EDL_internal_bool_to_string); + EDL_internal_append_bool_to_string(str, line->locked); break; case EDL_HEADER_NORMALIZED: - APPEND_ITEM(normalized, EDL_internal_bool_to_string); + EDL_internal_append_bool_to_string(str, line->normalized); break; case EDL_HEADER_STRETCHMETHOD: - APPEND_ITEM(stretch_method, EDL_internal_integer_to_string); + EDL_internal_append_integer_to_string(str, line->stretch_method); break; case EDL_HEADER_LOOPED: - APPEND_ITEM(looped, EDL_internal_bool_to_string); + EDL_internal_append_bool_to_string(str, line->looped); break; case EDL_HEADER_ONRULER: - APPEND_ITEM(on_ruler, EDL_internal_bool_to_string); + EDL_internal_append_bool_to_string(str, line->on_ruler); break; case EDL_HEADER_MEDIATYPE: - APPEND_ITEM(media_type, EDL_internal_media_type_to_string); + EDL_internal_append_media_type_to_string(str, line->media_type); break; case EDL_HEADER_FILENAME: EDL_internal_string_append(str, "\"", 1); @@ -299,66 +323,65 @@ EDL_internal_string_append(str, "\"", 1); break; case EDL_HEADER_STREAM: - APPEND_ITEM(stream, EDL_internal_integer_to_string); + EDL_internal_append_integer_to_string(str, line->stream); break; case EDL_HEADER_STREAMSTART: - APPEND_ITEM(stream_start, EDL_internal_double_to_string); + EDL_internal_append_double_to_string(str, line->stream_start); break; case EDL_HEADER_STREAMLENGTH: - APPEND_ITEM(stream_length, EDL_internal_double_to_string); + EDL_internal_append_double_to_string(str, line->stream_length); break; case EDL_HEADER_FADETIMEIN: - APPEND_ITEM(fade_time_in, EDL_internal_double_to_string); + EDL_internal_append_double_to_string(str, line->fade_time_in); break; case EDL_HEADER_FADETIMEOUT: - APPEND_ITEM(fade_time_out, EDL_internal_double_to_string); + EDL_internal_append_double_to_string(str, line->fade_time_out); break; case EDL_HEADER_SUSTAINGAIN: - APPEND_ITEM(sustain_gain, EDL_internal_double_to_string); + EDL_internal_append_double_to_string(str, line->sustain_gain); break; case EDL_HEADER_CURVEIN: - APPEND_ITEM(curve_in, EDL_internal_integer_to_string); + EDL_internal_append_integer_to_string(str, line->curve_in); break; case EDL_HEADER_GAININ: - APPEND_ITEM(gain_in, EDL_internal_double_to_string); + EDL_internal_append_double_to_string(str, line->gain_in); break; case EDL_HEADER_CURVEOUT: - APPEND_ITEM(curve_out, EDL_internal_integer_to_string); + EDL_internal_append_integer_to_string(str, line->curve_out); break; case EDL_HEADER_GAINOUT: - APPEND_ITEM(gain_out, EDL_internal_double_to_string); + EDL_internal_append_double_to_string(str, line->gain_out); break; case EDL_HEADER_LAYER: - APPEND_ITEM(layer, EDL_internal_integer_to_string); + EDL_internal_append_integer_to_string(str, line->layer); break; case EDL_HEADER_COLOR: - APPEND_ITEM(color, EDL_internal_integer_to_string); + EDL_internal_append_integer_to_string(str, line->color); break; case EDL_HEADER_CURVEINR: - APPEND_ITEM(curve_in_r, EDL_internal_integer_to_string); + EDL_internal_append_integer_to_string(str, line->curve_in_r); break; case EDL_HEADER_CURVEOUTR: - APPEND_ITEM(curve_out_r, EDL_internal_integer_to_string); + EDL_internal_append_integer_to_string(str, line->curve_out_r); break; case EDL_HEADER_PLAYPITCH: - APPEND_ITEM(play_pitch, EDL_internal_double_to_string); + EDL_internal_append_double_to_string(str, line->play_pitch); break; case EDL_HEADER_LOCKPITCH: - APPEND_ITEM(lock_pitch, EDL_internal_bool_to_string); + EDL_internal_append_bool_to_string(str, line->lock_pitch); break; case EDL_HEADER_FIRSTCHANNEL: - APPEND_ITEM(first_channel, EDL_internal_integer_to_string); + EDL_internal_append_integer_to_string(str, line->first_channel); break; case EDL_HEADER_CHANNELS: - APPEND_ITEM(channels, EDL_internal_integer_to_string); + EDL_internal_append_integer_to_string(str, line->channels); break; default: /* ... what */ break; -#undef APPEND_ITEM } - if (i < order_len - 1) + if (i < header->size - 1) EDL_internal_string_append(str, ";\t", 2); else EDL_internal_string_append(str, ";", 1); @@ -381,14 +404,16 @@ EDL_internal_string_append(&ret, order_str, strlen(order_str)); { - size_t order_len; - uint32_t* order = EDL_internal_parse_header(order_str, &order_len); + /* how? */ + EDL_header header = {0}; + if (EDL_internal_parse_header(&header, order_str, 0, strlen(order_str)) < 0) + return NULL; size_t i; for (i = 0; i < edl->size; i++) - EDL_dump_line(&ret, &edl->arr[i], order, order_len); + EDL_dump_line(&ret, &edl->arr[i], &header); - free(order); + EDL_internal_free_header(&header); } return ret.data; diff -r a0bd92c4c0e8 -r 0cc2555db371 src/str.c --- a/src/str.c Fri Mar 22 20:51:46 2024 -0400 +++ b/src/str.c Wed Mar 27 13:38:30 2024 -0400 @@ -25,8 +25,8 @@ 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; @@ -38,6 +38,7 @@ if (!EDL_internal_string_allocate(str, 1)) return 0; + /* increase capacity if needed */ if (str->size + length + 1 >= str->capacity) { size_t capacity = 1; while (capacity < (str->size + length + 1)) @@ -47,7 +48,7 @@ return 0; } - strncat(str->data, data, length); + memcpy(&str->data[str->size], data, length); str->size += length; return length;