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