Mercurial > libedl
diff src/main.c @ 2:d00bc412900e
*: fix up lots of stuff and make the thing actually usable
author | Paper <mrpapersonic@gmail.com> |
---|---|
date | Sun, 24 Dec 2023 20:01:30 -0500 |
parents | 0ea1ec2da443 |
children |
line wrap: on
line diff
--- a/src/main.c Tue Jul 04 22:50:26 2023 -0400 +++ b/src/main.c Sun Dec 24 20:01:30 2023 -0500 @@ -5,221 +5,301 @@ #include <stdint.h> #include "edl.h" -int strings_amt = -1; +#define strnchr(haystack, needle, length) memchr(haystack, needle, strnlen(haystack, length)) -/* CRC32 hash function */ -uint32_t crc32b(unsigned char* restrict message) { - int32_t i, j; - uint32_t byte, crc, mask; +static uint32_t EDL_internal_crcn32b(const unsigned char* restrict message, size_t length) { + uint32_t crc = 0xFFFFFFFF; - crc = 0xFFFFFFFF; - for (i = 0; message[i] != 0; i++) { - byte = message[i]; // Get next byte. - crc = crc ^ byte; - for (j = 7; j >= 0; j--) { // Do eight times. - mask = -(crc & 1); - crc = (crc >> 1) ^ (0xEDB88320 & mask); - } + 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. */ -uint32_t* parse_first_line(char* first_line) { - uint32_t* hashes = calloc(32, sizeof(uint32_t)); - int i = 0; - char* token; - hashes[i++] = crc32b(strtok_r(first_line, ";", &token)); - for (;;i++) { - char* token = strtok_r(NULL, ";", &token); - if (token == NULL) - break; - hashes[i] = crc32b(token); + * 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 + } } - strings_amt = i; - free(first_line); + + *length = current_hash; + return hashes; } /* -- Functions to extract different datatypes -- */ -char* get_int(char* input, int* int_return) { - char* ptr_return; - *int_return = strtol(input, &ptr_return, 10); - return ptr_return + 2; +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; } -char* get_double(char* input, double* double_return) { - char* ptr_return; - *double_return = strtod(input, &ptr_return); - return ptr_return + 2; +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); } -char* get_bool(char* input, bool* bool_return) { - switch (input[0]) { - case 'T': - *bool_return = true; - return input + 6; - case 'F': - *bool_return = false; - return input + 7; - default: - /* what */ - return NULL; +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); } -char* get_media_type(char* input, MediaType* media_return) { - switch (input[0]) { - case 'V': - *media_return = video; - return input + 7; - case 'A': - *media_return = audio; - return input + 7; - default: - /* what */ - return NULL; - } +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); } -/* lenptr is optional */ -char* cut_string_at_match(char* input, char* match, int* lenptr) { - int length = strcspn(&input[1], match); - char* string = calloc(length+1, sizeof(char)); - memcpy(string, &input[1], length); - string[length] = '\0'; - if (lenptr != NULL) - *lenptr = length; - return string; -} - -char* get_string(char* input, char** string_return) { +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. */ - int length; - char* string = cut_string_at_match(input, "\"", &length); - *string_return = string; - return input + length + 4; + 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); } -/* The memory manager for EDL_file. */ -void allocate_memory(EDL_file* input) { - if (input->size == 0) input->size = 16; - input->edl = realloc(input->edl, (input->size*2) * sizeof(EDL_line)); - input->size *= 2; +/* 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); } -/* This is the important function */ -EDL_file* parse_EDL(char* text) { - EDL_file edl; - memset(&edl, '\0', sizeof(edl)); - allocate_memory(&edl); - uint32_t* order = parse_first_line(strtok_r(text, "\n", NULL)); - char* line = strtok(text, "\n"); - while ((line = strtok(NULL, "\n")) != NULL) { - char* tmp_ptr = line; - for (int i = 0; i < strings_amt; i++) { +/* 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 */ - tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].id); + ADD_TO_OFFSET(id, EDL_internal_get_int); break; case 0x4b211812: /* Track */ - tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].track); + ADD_TO_OFFSET(track, EDL_internal_get_int); break; case 0xbb46516f: /* StartTime */ - tmp_ptr = get_double(tmp_ptr, &edl.edl[edl.current].start_time); + ADD_TO_OFFSET(start_time, EDL_internal_get_double); break; case 0xaeac5df7: /* Length */ - tmp_ptr = get_double(tmp_ptr, &edl.edl[edl.current].length); + ADD_TO_OFFSET(length, EDL_internal_get_double); break; case 0x03834606: /* PlayRate */ - tmp_ptr = get_double(tmp_ptr, &edl.edl[edl.current].play_rate); + ADD_TO_OFFSET(play_rate, EDL_internal_get_double); break; case 0x0c2083d3: /* Locked */ - tmp_ptr = get_bool(tmp_ptr, &edl.edl[edl.current].locked); + ADD_TO_OFFSET(locked, EDL_internal_get_bool); break; case 0xe60c8b1d: /* Normalized */ - tmp_ptr = get_bool(tmp_ptr, &edl.edl[edl.current].normalized); + ADD_TO_OFFSET(normalized, EDL_internal_get_bool); break; case 0xbe5802c9: /* StretchMethod */ - tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].stretch_method); + ADD_TO_OFFSET(stretch_method, EDL_internal_get_int); break; case 0x4ec8be4c: /* Looped */ - tmp_ptr = get_bool(tmp_ptr, &edl.edl[edl.current].looped); + ADD_TO_OFFSET(looped, EDL_internal_get_bool); break; case 0xe6cb84d1: /* OnRuler */ - tmp_ptr = get_bool(tmp_ptr, &edl.edl[edl.current].on_ruler); + ADD_TO_OFFSET(on_ruler, EDL_internal_get_bool); break; case 0x035f84c2: /* MediaType */ - tmp_ptr = get_media_type(tmp_ptr, &edl.edl[edl.current].media_type); + ADD_TO_OFFSET(media_type, EDL_internal_get_media_type); break; case 0x379d32c5: /* FileName */ - tmp_ptr = get_string(tmp_ptr, &edl.edl[edl.current].file_name); + ADD_TO_OFFSET(filename, EDL_internal_get_string); break; case 0x9f334738: /* Stream */ - tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].stream); + ADD_TO_OFFSET(stream, EDL_internal_get_int); break; case 0x07b4e0e7: /* StreamStart */ - tmp_ptr = get_double(tmp_ptr, &edl.edl[edl.current].stream_start); + ADD_TO_OFFSET(stream_start, EDL_internal_get_double); break; case 0x8f16c7b8: /* StreamLength */ - tmp_ptr = get_double(tmp_ptr, &edl.edl[edl.current].stream_length); + ADD_TO_OFFSET(stream_length, EDL_internal_get_double); break; case 0xd2edd7e4: /* FadeTimeIn */ - tmp_ptr = get_double(tmp_ptr, &edl.edl[edl.current].fade_time_in); + ADD_TO_OFFSET(fade_time_in, EDL_internal_get_double); break; case 0x792e8c40: /* FadeTimeOut */ - tmp_ptr = get_double(tmp_ptr, &edl.edl[edl.current].fade_time_out); + ADD_TO_OFFSET(fade_time_out, EDL_internal_get_double); break; case 0x98374657: /* SustainGain */ - tmp_ptr = get_double(tmp_ptr, &edl.edl[edl.current].sustain_gain); + ADD_TO_OFFSET(sustain_gain, EDL_internal_get_double); break; case 0x3e998b1f: /* CurveIn */ - tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].curve_in); + ADD_TO_OFFSET(curve_in, EDL_internal_get_int); break; case 0x82fb09c4: /* GainIn */ - tmp_ptr = get_double(tmp_ptr, &edl.edl[edl.current].gain_in); + ADD_TO_OFFSET(gain_in, EDL_internal_get_double); break; case 0x53add388: /* CurveOut */ - tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].curve_out); + ADD_TO_OFFSET(curve_out, EDL_internal_get_int); break; case 0x4210ba56: /* GainOut */ - tmp_ptr = get_double(tmp_ptr, &edl.edl[edl.current].gain_out); + ADD_TO_OFFSET(gain_out, EDL_internal_get_double); break; case 0x89c4df6c: /* Layer */ - tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].layer); + ADD_TO_OFFSET(layer, EDL_internal_get_int); break; case 0xadf2f1a3: /* Color */ - tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].color); + ADD_TO_OFFSET(color, EDL_internal_get_int); break; case 0xa56b43e1: /* CurveInR */ - tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].curve_in_r); + ADD_TO_OFFSET(curve_in_r, EDL_internal_get_int); break; case 0xcb6d715e: /* CurveOutR */ - tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].curve_out_r); + ADD_TO_OFFSET(curve_out_r, EDL_internal_get_int); break; case 0x9da1b9ed: /* PlayPitch */ - tmp_ptr = get_double(tmp_ptr, &edl.edl[edl.current].play_pitch); + ADD_TO_OFFSET(play_pitch, EDL_internal_get_double); break; case 0x2bda6ed4: /* LockPitch */ - tmp_ptr = get_bool(tmp_ptr, &edl.edl[edl.current].lock_pitch); + ADD_TO_OFFSET(lock_pitch, EDL_internal_get_bool); break; case 0x3071a4c6: /* FirstChannel */ - tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].first_channel); + ADD_TO_OFFSET(first_channel, EDL_internal_get_int); break; case 0x7de1bd40: /* Channels */ - tmp_ptr = get_int(tmp_ptr, &edl.edl[edl.current].channels); + ADD_TO_OFFSET(channels, EDL_internal_get_int); break; default: /* ... what */ break; } } - edl.current++; - if (edl.current >= edl.size) - allocate_memory(&edl); + + 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); +}