Mercurial > libedl
view 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 source
#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); }