Mercurial > libedl
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 } |