comparison src/edl.c @ 4:c2408abb258a

*: add dumping to string, rename EDL_file to EDL
author Paper <mrpapersonic@gmail.com>
date Mon, 25 Dec 2023 16:24:16 -0500
parents bd99b6549eb4
children 7137fbac0b85
comparison
equal deleted inserted replaced
3:bd99b6549eb4 4:c2408abb258a
2 #include <stdbool.h> 2 #include <stdbool.h>
3 #include <stdio.h> 3 #include <stdio.h>
4 #include <stdlib.h> 4 #include <stdlib.h>
5 #include <stdint.h> 5 #include <stdint.h>
6 #include "edl.h" 6 #include "edl.h"
7 #include "str.h"
7 8
8 #define strnchr(haystack, needle, length) (char*)memchr(haystack, needle, strnlen(haystack, length)) 9 #define strnchr(haystack, needle, length) (char*)memchr(haystack, needle, strnlen(haystack, length))
9 10
10 static uint32_t EDL_internal_crcn32b(const unsigned char* restrict message, size_t length) { 11 static uint32_t EDL_internal_crcn32b(const unsigned char* restrict message, size_t length) {
11 uint32_t crc = 0xFFFFFFFF; 12 uint32_t crc = 0xFFFFFFFF;
27 */ 28 */
28 static uint32_t* EDL_internal_parse_first_line(const char* data, size_t* restrict length) { 29 static uint32_t* EDL_internal_parse_first_line(const char* data, size_t* restrict length) {
29 size_t hashes_size = 32, current_hash = 0; 30 size_t hashes_size = 32, current_hash = 0;
30 uint32_t* hashes = malloc(hashes_size * sizeof(uint32_t)); 31 uint32_t* hashes = malloc(hashes_size * sizeof(uint32_t));
31 32
32 size_t len_until_newline = strchr(data, '\n') - data, i, b; 33 size_t len_until_newline = strchr(data, '\n') - data, len_until_cr = strchr(data, '\r') - data;
33 for (i = 0, b = 0; i < len_until_newline; i++, b++) { 34 size_t i, b;
34 if (data[i] == ';') { 35 for (i = 0, b = 0; i <= len_until_newline && i <= len_until_cr; i++, b++) {
36 if (data[i] == ';' || data[i] == ':' || data[i] == '\r' || data[i] == '\n') {
35 if (current_hash >= hashes_size) 37 if (current_hash >= hashes_size)
36 hashes = realloc(hashes, (hashes_size *= 2) * sizeof(uint32_t)); 38 hashes = realloc(hashes, (hashes_size *= 2) * sizeof(uint32_t));
37 hashes[current_hash++] = EDL_internal_crcn32b((const unsigned char*)&data[i - b], b); 39 hashes[current_hash++] = EDL_internal_crcn32b((const unsigned char*)&data[i - b], b);
38 b = -1; // ew 40 b = -1; // ew
39 } 41 }
40 } 42 }
41 43
42 *length = current_hash; 44 *length = current_hash; // wtf?
43 45
44 return hashes; 46 return hashes;
45 } 47 }
46 48
47 /* -- Functions to extract different datatypes -- */ 49 /* -- Functions to extract different datatypes -- */
92 94
93 static size_t EDL_internal_get_bool(const char* input, size_t offset, size_t length, bool* bool_return) { 95 static size_t EDL_internal_get_bool(const char* input, size_t offset, size_t length, bool* bool_return) {
94 if (offset > length) 96 if (offset > length)
95 return 0; 97 return 0;
96 98
97 if (strncmp((input + offset), "TRUE", 4)) 99 if (!strncmp(&input[offset], "TRUE", 4))
98 *bool_return = true; 100 *bool_return = true;
99 else if (strncmp((input + offset), "FALSE", 5)) 101 else if (!strncmp(&input[offset], "FALSE", 5))
100 *bool_return = false; 102 *bool_return = false;
101 103
102 return EDL_internal_append_offset(input, offset, length); 104 return EDL_internal_append_offset(input, offset, length);
103 } 105 }
104 106
105 static size_t EDL_internal_get_media_type(const char* input, size_t offset, size_t length, MediaType* media_return) { 107 static size_t EDL_internal_get_media_type(const char* input, size_t offset, size_t length, MediaType* media_return) {
106 if (offset > length) 108 if (offset > length)
107 return 0; 109 return 0;
108 110
109 if (strncmp(input + offset, "VIDEO", 5)) 111 if (!strncmp(&input[offset], "VIDEO", 5))
110 *media_return = MEDIATYPE_VIDEO; 112 *media_return = MEDIATYPE_VIDEO;
111 else if (strncmp(input + offset, "AUDIO", 5)) 113 else if (!strncmp(&input[offset], "AUDIO", 5))
112 *media_return = MEDIATYPE_AUDIO; 114 *media_return = MEDIATYPE_AUDIO;
115 else
116 *media_return = MEDIATYPE_UNKNOWN;
113 117
114 return EDL_internal_append_offset(input, offset, length); 118 return EDL_internal_append_offset(input, offset, length);
115 } 119 }
116 120
117 static size_t EDL_internal_get_string(const char* input, size_t offset, size_t length, char** string_return) { 121 static size_t EDL_internal_get_string(const char* input, size_t offset, size_t length, char** string_return) {
138 return EDL_internal_append_offset(input, offset, length); 142 return EDL_internal_append_offset(input, offset, length);
139 } 143 }
140 144
141 /* memory management routines */ 145 /* memory management routines */
142 146
143 static int EDL_internal_reallocate(EDL_file* input, size_t new_capacity) { 147 static int EDL_internal_reallocate(EDL* input, size_t new_capacity) {
144 input->arr = realloc(input->arr, new_capacity * sizeof(EDL_line)); 148 input->arr = realloc(input->arr, new_capacity * sizeof(EDL_line));
145 if (!input->arr) 149 if (!input->arr)
146 return 0; 150 return 0;
147 151
148 if (new_capacity > input->capacity) 152 if (new_capacity > input->capacity)
149 memset(input->arr + input->capacity, 0, new_capacity - input->capacity); 153 memset(&input->arr[input->capacity], 0, (new_capacity - input->capacity) * sizeof(EDL_line));
150 154
151 input->capacity = new_capacity; 155 input->capacity = new_capacity;
152 156
153 return 1; 157 return 1;
154 } 158 }
155 159
156 static int EDL_internal_allocate_memory(EDL_file* input) {
157 return EDL_internal_reallocate(input, input->capacity ? input->capacity * 2 : 16);
158 }
159
160 static int EDL_internal_shrink_memory_to_fit(EDL_file* input) {
161 return EDL_internal_reallocate(input, input->size);
162 }
163
164 /* the important function */ 160 /* the important function */
165 EDL_file EDL_parse(const char* data, size_t length) { 161 EDL EDL_parse(const char* data, size_t length) {
166 EDL_file edl = {0}; 162 EDL edl = {0};
167 if (!EDL_internal_allocate_memory(&edl)) 163 if (!EDL_internal_reallocate(&edl, 16))
168 return edl; 164 return edl;
169 165
170 size_t order_size = 0; 166 size_t order_size = 0;
171 uint32_t* order = EDL_internal_parse_first_line(data, &order_size); 167 uint32_t* order = EDL_internal_parse_first_line(data, &order_size);
172 168
173 size_t offset = strnchr(data, '\n', length) - data + 1; 169 size_t offset = 0;
174 while ((offset = strnchr(data + offset, '\n', length - offset) - data + 1) < length) { 170 while ((offset = strnchr(&data[offset], '\n', length - offset) - data + 1) < length) {
175 size_t local_offset = offset; // this is so our original offset stays intact 171 size_t local_offset = offset; // this is so our original offset stays intact
176 172
177 bool ok = true; 173 bool ok = true;
178 174
179 for (int i = 0; i < order_size; i++) { 175 for (int i = 0; i < order_size; i++) {
270 ADD_TO_OFFSET(lock_pitch, EDL_internal_get_bool); 266 ADD_TO_OFFSET(lock_pitch, EDL_internal_get_bool);
271 break; 267 break;
272 case 0x3071a4c6: /* FirstChannel */ 268 case 0x3071a4c6: /* FirstChannel */
273 ADD_TO_OFFSET(first_channel, EDL_internal_get_int); 269 ADD_TO_OFFSET(first_channel, EDL_internal_get_int);
274 break; 270 break;
275 case 0x7de1bd40: /* Channels */ 271 case 0xe94981a4: /* Channels */
276 ADD_TO_OFFSET(channels, EDL_internal_get_int); 272 ADD_TO_OFFSET(channels, EDL_internal_get_int);
277 break; 273 break;
278 default: 274 default:
279 /* ... what */ 275 /* ... what */
280 break; 276 break;
277 #undef ADD_TO_OFFSET
281 } 278 }
282 } 279 }
283 280
284 if (!ok) 281 if (!ok)
285 break; 282 break;
286 283
287 if (++edl.size >= edl.capacity) 284 if (++edl.size >= edl.capacity)
288 EDL_internal_allocate_memory(&edl); 285 EDL_internal_reallocate(&edl, edl.capacity * 2);
289 } 286 }
290 287
291 EDL_internal_shrink_memory_to_fit(&edl); 288 EDL_internal_reallocate(&edl, edl.size);
292 289
293 free(order); 290 free(order);
294 291
295 return edl; 292 return edl;
296 } 293 }
297 294
298 void EDL_free(EDL_file file) { 295 static char* EDL_internal_integer_to_string(int value) {
296 char out[256] = {0}; // this ought to be enough.
297 snprintf(out, 256, "%d", value);
298 out[255] = '\0';
299 return strdup(out);
300 }
301
302 static char* EDL_internal_double_to_string(double value) {
303 char out[256] = {0};
304 snprintf(out, 256, "%.6f", value);
305 out[255] = '\0';
306 return strdup(out);
307 }
308
309 static char* EDL_internal_bool_to_string(bool value) {
310 return strdup(value ? "TRUE" : "FALSE");
311 }
312
313 static char* EDL_internal_media_type_to_string(MediaType value) {
314 switch (value) {
315 case MEDIATYPE_AUDIO:
316 return strdup("AUDIO");
317 case MEDIATYPE_VIDEO:
318 case MEDIATYPE_UNKNOWN:
319 default:
320 return strdup("VIDEO");
321 }
322 }
323
324 static void EDL_dump_line(EDL_internal_string* str, EDL_line line, const uint32_t* order, const size_t order_len) {
325 for (size_t i = 0; i < order_len; i++) {
326 switch (order[i]) {
327 #define APPEND_ITEM(a, x) \
328 { \
329 char* tstr = x(line.a); \
330 EDL_internal_string_append(str, tstr, strlen(tstr)); \
331 free(tstr); \
332 }
333 case 0x1541c503: /* ID */
334 APPEND_ITEM(id, EDL_internal_integer_to_string);
335 break;
336 case 0x4b211812: /* Track */
337 APPEND_ITEM(track, EDL_internal_integer_to_string);
338 break;
339 case 0xbb46516f: /* StartTime */
340 APPEND_ITEM(start_time, EDL_internal_double_to_string);
341 break;
342 case 0xaeac5df7: /* Length */
343 APPEND_ITEM(length, EDL_internal_double_to_string);
344 break;
345 case 0x03834606: /* PlayRate */
346 APPEND_ITEM(play_rate, EDL_internal_double_to_string);
347 break;
348 case 0x0c2083d3: /* Locked */
349 APPEND_ITEM(locked, EDL_internal_bool_to_string);
350 break;
351 case 0xe60c8b1d: /* Normalized */
352 APPEND_ITEM(normalized, EDL_internal_bool_to_string);
353 break;
354 case 0xbe5802c9: /* StretchMethod */
355 APPEND_ITEM(stretch_method, EDL_internal_integer_to_string);
356 break;
357 case 0x4ec8be4c: /* Looped */
358 APPEND_ITEM(looped, EDL_internal_bool_to_string);
359 break;
360 case 0xe6cb84d1: /* OnRuler */
361 APPEND_ITEM(on_ruler, EDL_internal_bool_to_string);
362 break;
363 case 0x035f84c2: /* MediaType */
364 APPEND_ITEM(media_type, EDL_internal_media_type_to_string);
365 break;
366 case 0x379d32c5: /* FileName */
367 EDL_internal_string_append(str, "\"", 1);
368 EDL_internal_string_append(str, line.filename, strlen(line.filename));
369 EDL_internal_string_append(str, "\"", 1);
370 break;
371 case 0x9f334738: /* Stream */
372 APPEND_ITEM(stream, EDL_internal_integer_to_string);
373 break;
374 case 0x07b4e0e7: /* StreamStart */
375 APPEND_ITEM(stream_start, EDL_internal_double_to_string);
376 break;
377 case 0x8f16c7b8: /* StreamLength */
378 APPEND_ITEM(stream_length, EDL_internal_double_to_string);
379 break;
380 case 0xd2edd7e4: /* FadeTimeIn */
381 APPEND_ITEM(fade_time_in, EDL_internal_double_to_string);
382 break;
383 case 0x792e8c40: /* FadeTimeOut */
384 APPEND_ITEM(fade_time_out, EDL_internal_double_to_string);
385 break;
386 case 0x98374657: /* SustainGain */
387 APPEND_ITEM(sustain_gain, EDL_internal_double_to_string);
388 break;
389 case 0x3e998b1f: /* CurveIn */
390 APPEND_ITEM(curve_in, EDL_internal_integer_to_string);
391 break;
392 case 0x82fb09c4: /* GainIn */
393 APPEND_ITEM(gain_in, EDL_internal_double_to_string);
394 break;
395 case 0x53add388: /* CurveOut */
396 APPEND_ITEM(curve_out, EDL_internal_integer_to_string);
397 break;
398 case 0x4210ba56: /* GainOut */
399 APPEND_ITEM(gain_out, EDL_internal_double_to_string);
400 break;
401 case 0x89c4df6c: /* Layer */
402 APPEND_ITEM(layer, EDL_internal_integer_to_string);
403 break;
404 case 0xadf2f1a3: /* Color */
405 APPEND_ITEM(color, EDL_internal_integer_to_string);
406 break;
407 case 0xa56b43e1: /* CurveInR */
408 APPEND_ITEM(curve_in_r, EDL_internal_integer_to_string);
409 break;
410 case 0xcb6d715e: /* CurveOutR */
411 APPEND_ITEM(curve_out_r, EDL_internal_integer_to_string);
412 break;
413 case 0x9da1b9ed: /* PlayPitch */
414 APPEND_ITEM(play_pitch, EDL_internal_double_to_string);
415 break;
416 case 0x2bda6ed4: /* LockPitch */
417 APPEND_ITEM(lock_pitch, EDL_internal_bool_to_string);
418 break;
419 case 0x3071a4c6: /* FirstChannel */
420 APPEND_ITEM(first_channel, EDL_internal_integer_to_string);
421 break;
422 case 0xe94981a4: /* Channels */
423 APPEND_ITEM(channels, EDL_internal_integer_to_string);
424 break;
425 default:
426 /* ... what */
427 break;
428 #undef APPEND_ITEM
429 }
430
431 if (i < order_len - 1)
432 EDL_internal_string_append(str, ";\t", 2);
433 else
434 EDL_internal_string_append(str, ";", 1);
435 }
436
437 EDL_internal_string_append(str, "\n", 1);
438 }
439
440 char* EDL_dump(EDL edl) {
441 EDL_internal_string ret;
442 EDL_internal_string_init(&ret);
443
444 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";
445 EDL_internal_string_append(&ret, order_str, strlen(order_str));
446
447 size_t order_len;
448 uint32_t* order = EDL_internal_parse_first_line(order_str, &order_len);
449
299 size_t i; 450 size_t i;
300 for (i = 0; i < file.size; i++) { 451 for (i = 0; i < edl.size; i++)
301 if (file.arr[i].filename) 452 EDL_dump_line(&ret, edl.arr[i], order, order_len);
302 free(file.arr[i].filename); 453
303 } 454 free(order);
304 free(file.arr); 455
305 } 456 EDL_internal_string_allocate(&ret, ret.size);
457
458 return ret.data;
459 }
460
461 void EDL_free(EDL edl) {
462 size_t i;
463 for (i = 0; i < edl.size; i++) {
464 if (edl.arr[i].filename)
465 free(edl.arr[i].filename);
466 }
467 free(edl.arr);
468 }