comparison src/edl.c @ 12:0cc2555db371

*: make our string functions not stupid strncat() made everything slow! new addition internally: an EDL_header structure to make things not stupid. if we were using C++ it wouldn't really be necessary, but alas :)
author Paper <paper@paper.us.eu.org>
date Wed, 27 Mar 2024 13:38:30 -0400
parents 0c98b46eaf73
children 41b74137e201
comparison
equal deleted inserted replaced
11:a0bd92c4c0e8 12:0cc2555db371
39 #define EDL_HEADER_PLAYPITCH 0x9da1b9ed 39 #define EDL_HEADER_PLAYPITCH 0x9da1b9ed
40 #define EDL_HEADER_LOCKPITCH 0x2bda6ed4 40 #define EDL_HEADER_LOCKPITCH 0x2bda6ed4
41 #define EDL_HEADER_FIRSTCHANNEL 0x3071a4c6 41 #define EDL_HEADER_FIRSTCHANNEL 0x3071a4c6
42 #define EDL_HEADER_CHANNELS 0xe94981a4 42 #define EDL_HEADER_CHANNELS 0xe94981a4
43 43
44 typedef struct {
45 uint32_t* order;
46 size_t size;
47 size_t capacity;
48 } EDL_header;
49
44 /* use a CRC32 hash function to process the headers */ 50 /* use a CRC32 hash function to process the headers */
45 static uint32_t EDL_internal_crcn32b(const unsigned char* message, size_t length) { 51 static uint32_t EDL_internal_crcn32b(const unsigned char* message, size_t length) {
46 uint32_t crc = 0xffffffff; 52 uint32_t crc = 0xffffffff;
47 size_t i; 53 size_t i;
48 54
59 65
60 static size_t EDL_internal_size_t_min(size_t a, size_t b) { 66 static size_t EDL_internal_size_t_min(size_t a, size_t b) {
61 return (a < b) ? a : b; 67 return (a < b) ? a : b;
62 } 68 }
63 69
64 /* This parses the header of the EDL and creates an array with CRC32 hashes 70 static int EDL_internal_header_reallocate(EDL_header* header, size_t new_capacity) {
65 * in the order of the strings. 71 header->order = realloc(header->order, new_capacity * sizeof(*header->order));
66 */ 72 if (!header->order)
67 static uint32_t* EDL_internal_parse_header(const char* data, size_t* length) { 73 return -1;
68 /* */ 74
69 const size_t newline = EDL_internal_size_t_min(strchr(data, '\n') - data, strchr(data, '\r') - data); 75 if (new_capacity > header->capacity)
70 76 memset(&header->order[header->capacity], 0, (new_capacity - header->capacity) * sizeof(*header->order));
71 size_t current_hash = 0, hashes_size = 32; 77
72 uint32_t* hashes = malloc(hashes_size * sizeof(uint32_t)); 78 header->capacity = new_capacity;
73 79
74 /* overall iterates over the entire line, 80 return header->capacity;
75 * column stores the length of the current column */ 81 }
76 size_t overall, column; 82
77 83 static int EDL_internal_parse_header_item(EDL_header* header, const char* data, size_t offset, size_t length) {
78 for (overall = 0, column = 0; overall <= newline; overall++) { 84 if (header->capacity <= header->size)
79 if (data[overall] == ';' || data[overall] == ':') { 85 if (EDL_internal_header_reallocate(header, header->capacity * 2) < 0)
80 /* process the current column */ 86 return -1;
81 if (hashes_size < current_hash) 87
82 hashes = realloc(hashes, (hashes_size *= 2) * sizeof(uint32_t)); 88 header->order[header->size++] = EDL_internal_crcn32b((const unsigned char*)&data[offset], length);
83 89
84 hashes[current_hash++] = EDL_internal_crcn32b((const unsigned char*)&data[overall - column], column); 90 return header->size;
91 }
92
93 /* EDL_header MUST be zero-initialized. */
94 static int EDL_internal_parse_header(EDL_header* header, const char* data, size_t offset, size_t length) {
95 size_t newline = 0, overall = 0, column = 0;
96 {
97 const char* ln = memchr(&data[offset], '\n', length - offset);
98 if (!ln)
99 return -1;
100
101 newline = ln - &data[offset];
102 }
103
104 EDL_internal_header_reallocate(header, 32);
105
106 for (; overall <= newline; overall++) {
107 if (data[offset + overall] == ';' || data[offset + overall] == ':') {
108 if (EDL_internal_parse_header_item(header, data, overall - column, column) < 0)
109 return -1;
110
85 column = 0; /* reset */ 111 column = 0; /* reset */
86 } else column++; 112 } else column++;
87 } 113 }
88 114
89 *length = current_hash; 115 return overall;
90 116 }
91 return hashes; 117
118 static int EDL_internal_free_header(EDL_header* header) {
119 free(header->order);
92 } 120 }
93 121
94 int EDL_reallocate(EDL* edl, size_t new_capacity) { 122 int EDL_reallocate(EDL* edl, size_t new_capacity) {
95 edl->arr = realloc(edl->arr, new_capacity * sizeof(EDL_line)); 123 edl->arr = realloc(edl->arr, new_capacity * sizeof(EDL_line));
96 if (!edl->arr) 124 if (!edl->arr)
97 return 0; 125 return -1;
98 126
99 if (new_capacity > edl->capacity) 127 if (new_capacity > edl->capacity)
100 memset(&edl->arr[edl->capacity], 0, (new_capacity - edl->capacity) * sizeof(EDL_line)); 128 memset(&edl->arr[edl->capacity], 0, (new_capacity - edl->capacity) * sizeof(EDL_line));
101 129
102 edl->capacity = new_capacity; 130 edl->capacity = new_capacity;
103 131
104 return 1; 132 return edl->capacity;
105 } 133 }
106 134
107 int EDL_append(EDL* edl, EDL_line line) { 135 int EDL_append(EDL* edl, EDL_line line) {
108 if (edl->size + 1 < edl->capacity && !EDL_reallocate(edl, edl->capacity)) 136 if (edl->size + 1 < edl->capacity && !EDL_reallocate(edl, edl->capacity))
109 return 0; 137 return 0;
112 return 1; 140 return 1;
113 } 141 }
114 142
115 /* the big important function */ 143 /* the big important function */
116 EDL_parse_error_t EDL_parse(EDL* edl, const char* data, size_t length) { 144 EDL_parse_error_t EDL_parse(EDL* edl, const char* data, size_t length) {
117 size_t order_size = 0;
118 uint32_t* order = NULL;
119 size_t offset = 0; 145 size_t offset = 0;
120 146 EDL_header header = {0};
121 if (!EDL_reallocate(edl, 16)) 147
148 if (EDL_reallocate(edl, 16) < 0)
122 return EDL_PARSE_ERROR_OUT_OF_MEMORY; 149 return EDL_PARSE_ERROR_OUT_OF_MEMORY;
123 150
124 order = EDL_internal_parse_header(data, &order_size); 151 if (EDL_internal_parse_header(&header, data, offset, length) < 0)
125 152 return EDL_PARSE_ERROR_HEADER;
126 while ((offset = EDL_internal_strnchr(&data[offset], '\n', length - offset) - data + 1) < length) { 153
154 while ((offset = (const char*)memchr(&data[offset], '\n', length - offset) - data + 1) < length) {
127 size_t local_offset = offset; /* original offset stays intact */ 155 size_t local_offset = offset; /* original offset stays intact */
128 bool ok = true; 156 bool ok = true;
129 int i; 157 int i;
130 158
131 for (i = 0; i < order_size; i++) { 159 for (i = 0; i < header.size; i++) {
132 #define ADD_TO_OFFSET(x, a) \ 160 #define ADD_TO_OFFSET(x, a) \
133 { \ 161 { \
134 size_t o = a(data, local_offset, length, &edl->arr[edl->size].x); \ 162 size_t o = a(data, local_offset, length, &edl->arr[edl->size].x); \
135 if (!o) \ 163 if (!o) \
136 ok = false; \ 164 ok = false; \
137 local_offset += o; \ 165 local_offset += o; \
138 } 166 }
139 switch (order[i]) { 167 switch (header.order[i]) {
140 case EDL_HEADER_ID: 168 case EDL_HEADER_ID:
141 ADD_TO_OFFSET(id, EDL_internal_parse_int); 169 ADD_TO_OFFSET(id, EDL_internal_parse_int);
142 break; 170 break;
143 case EDL_HEADER_TRACK: 171 case EDL_HEADER_TRACK:
144 ADD_TO_OFFSET(track, EDL_internal_parse_int); 172 ADD_TO_OFFSET(track, EDL_internal_parse_int);
236 264
237 if (!ok) 265 if (!ok)
238 break; 266 break;
239 267
240 if (++edl->size >= edl->capacity) 268 if (++edl->size >= edl->capacity)
241 EDL_reallocate(edl, edl->capacity * 2); 269 if (EDL_reallocate(edl, edl->capacity * 2) < 0)
242 } 270 return EDL_PARSE_ERROR_OUT_OF_MEMORY;
271 }
272
273 EDL_internal_free_header(&header);
243 274
244 /* put on the shrinkwrap */ 275 /* put on the shrinkwrap */
245 EDL_reallocate(edl, edl->size); 276 if (EDL_reallocate(edl, edl->size) < 0)
246 277 return EDL_PARSE_ERROR_OUT_OF_MEMORY;
247 free(order);
248 278
249 return EDL_PARSE_ERROR_SUCCESS; 279 return EDL_PARSE_ERROR_SUCCESS;
250 } 280 }
251 281
252 static void EDL_dump_line(EDL_internal_string* str, const EDL_line* line, const uint32_t* order, const size_t order_len) { 282 static void EDL_dump_line(EDL_internal_string* str, const EDL_line* line, const EDL_header* header) {
253 size_t i; 283 size_t i;
254 284
255 for (i = 0; i < order_len; i++) { 285 for (i = 0; i < header->size; i++) {
256 switch (order[i]) { 286 switch (header->order[i]) {
257 #define APPEND_ITEM(a, x) \
258 { \
259 char* tstr = x(line->a); \
260 EDL_internal_string_append(str, tstr, strlen(tstr)); \
261 free(tstr); \
262 }
263 case EDL_HEADER_ID: 287 case EDL_HEADER_ID:
264 APPEND_ITEM(id, EDL_internal_integer_to_string); 288 EDL_internal_append_integer_to_string(str, line->id);
265 break; 289 break;
266 case EDL_HEADER_TRACK: 290 case EDL_HEADER_TRACK:
267 APPEND_ITEM(track, EDL_internal_integer_to_string); 291 EDL_internal_append_integer_to_string(str, line->track);
268 break; 292 break;
269 case EDL_HEADER_STARTTIME: 293 case EDL_HEADER_STARTTIME:
270 APPEND_ITEM(start_time, EDL_internal_double_to_string); 294 EDL_internal_append_double_to_string(str, line->start_time);
271 break; 295 break;
272 case EDL_HEADER_LENGTH: 296 case EDL_HEADER_LENGTH:
273 APPEND_ITEM(length, EDL_internal_double_to_string); 297 EDL_internal_append_double_to_string(str, line->length);
274 break; 298 break;
275 case EDL_HEADER_PLAYRATE: 299 case EDL_HEADER_PLAYRATE:
276 APPEND_ITEM(play_rate, EDL_internal_double_to_string); 300 EDL_internal_append_double_to_string(str, line->play_rate);
277 break; 301 break;
278 case EDL_HEADER_LOCKED: 302 case EDL_HEADER_LOCKED:
279 APPEND_ITEM(locked, EDL_internal_bool_to_string); 303 EDL_internal_append_bool_to_string(str, line->locked);
280 break; 304 break;
281 case EDL_HEADER_NORMALIZED: 305 case EDL_HEADER_NORMALIZED:
282 APPEND_ITEM(normalized, EDL_internal_bool_to_string); 306 EDL_internal_append_bool_to_string(str, line->normalized);
283 break; 307 break;
284 case EDL_HEADER_STRETCHMETHOD: 308 case EDL_HEADER_STRETCHMETHOD:
285 APPEND_ITEM(stretch_method, EDL_internal_integer_to_string); 309 EDL_internal_append_integer_to_string(str, line->stretch_method);
286 break; 310 break;
287 case EDL_HEADER_LOOPED: 311 case EDL_HEADER_LOOPED:
288 APPEND_ITEM(looped, EDL_internal_bool_to_string); 312 EDL_internal_append_bool_to_string(str, line->looped);
289 break; 313 break;
290 case EDL_HEADER_ONRULER: 314 case EDL_HEADER_ONRULER:
291 APPEND_ITEM(on_ruler, EDL_internal_bool_to_string); 315 EDL_internal_append_bool_to_string(str, line->on_ruler);
292 break; 316 break;
293 case EDL_HEADER_MEDIATYPE: 317 case EDL_HEADER_MEDIATYPE:
294 APPEND_ITEM(media_type, EDL_internal_media_type_to_string); 318 EDL_internal_append_media_type_to_string(str, line->media_type);
295 break; 319 break;
296 case EDL_HEADER_FILENAME: 320 case EDL_HEADER_FILENAME:
297 EDL_internal_string_append(str, "\"", 1); 321 EDL_internal_string_append(str, "\"", 1);
298 EDL_internal_string_append(str, line->filename, strlen(line->filename)); 322 EDL_internal_string_append(str, line->filename, strlen(line->filename));
299 EDL_internal_string_append(str, "\"", 1); 323 EDL_internal_string_append(str, "\"", 1);
300 break; 324 break;
301 case EDL_HEADER_STREAM: 325 case EDL_HEADER_STREAM:
302 APPEND_ITEM(stream, EDL_internal_integer_to_string); 326 EDL_internal_append_integer_to_string(str, line->stream);
303 break; 327 break;
304 case EDL_HEADER_STREAMSTART: 328 case EDL_HEADER_STREAMSTART:
305 APPEND_ITEM(stream_start, EDL_internal_double_to_string); 329 EDL_internal_append_double_to_string(str, line->stream_start);
306 break; 330 break;
307 case EDL_HEADER_STREAMLENGTH: 331 case EDL_HEADER_STREAMLENGTH:
308 APPEND_ITEM(stream_length, EDL_internal_double_to_string); 332 EDL_internal_append_double_to_string(str, line->stream_length);
309 break; 333 break;
310 case EDL_HEADER_FADETIMEIN: 334 case EDL_HEADER_FADETIMEIN:
311 APPEND_ITEM(fade_time_in, EDL_internal_double_to_string); 335 EDL_internal_append_double_to_string(str, line->fade_time_in);
312 break; 336 break;
313 case EDL_HEADER_FADETIMEOUT: 337 case EDL_HEADER_FADETIMEOUT:
314 APPEND_ITEM(fade_time_out, EDL_internal_double_to_string); 338 EDL_internal_append_double_to_string(str, line->fade_time_out);
315 break; 339 break;
316 case EDL_HEADER_SUSTAINGAIN: 340 case EDL_HEADER_SUSTAINGAIN:
317 APPEND_ITEM(sustain_gain, EDL_internal_double_to_string); 341 EDL_internal_append_double_to_string(str, line->sustain_gain);
318 break; 342 break;
319 case EDL_HEADER_CURVEIN: 343 case EDL_HEADER_CURVEIN:
320 APPEND_ITEM(curve_in, EDL_internal_integer_to_string); 344 EDL_internal_append_integer_to_string(str, line->curve_in);
321 break; 345 break;
322 case EDL_HEADER_GAININ: 346 case EDL_HEADER_GAININ:
323 APPEND_ITEM(gain_in, EDL_internal_double_to_string); 347 EDL_internal_append_double_to_string(str, line->gain_in);
324 break; 348 break;
325 case EDL_HEADER_CURVEOUT: 349 case EDL_HEADER_CURVEOUT:
326 APPEND_ITEM(curve_out, EDL_internal_integer_to_string); 350 EDL_internal_append_integer_to_string(str, line->curve_out);
327 break; 351 break;
328 case EDL_HEADER_GAINOUT: 352 case EDL_HEADER_GAINOUT:
329 APPEND_ITEM(gain_out, EDL_internal_double_to_string); 353 EDL_internal_append_double_to_string(str, line->gain_out);
330 break; 354 break;
331 case EDL_HEADER_LAYER: 355 case EDL_HEADER_LAYER:
332 APPEND_ITEM(layer, EDL_internal_integer_to_string); 356 EDL_internal_append_integer_to_string(str, line->layer);
333 break; 357 break;
334 case EDL_HEADER_COLOR: 358 case EDL_HEADER_COLOR:
335 APPEND_ITEM(color, EDL_internal_integer_to_string); 359 EDL_internal_append_integer_to_string(str, line->color);
336 break; 360 break;
337 case EDL_HEADER_CURVEINR: 361 case EDL_HEADER_CURVEINR:
338 APPEND_ITEM(curve_in_r, EDL_internal_integer_to_string); 362 EDL_internal_append_integer_to_string(str, line->curve_in_r);
339 break; 363 break;
340 case EDL_HEADER_CURVEOUTR: 364 case EDL_HEADER_CURVEOUTR:
341 APPEND_ITEM(curve_out_r, EDL_internal_integer_to_string); 365 EDL_internal_append_integer_to_string(str, line->curve_out_r);
342 break; 366 break;
343 case EDL_HEADER_PLAYPITCH: 367 case EDL_HEADER_PLAYPITCH:
344 APPEND_ITEM(play_pitch, EDL_internal_double_to_string); 368 EDL_internal_append_double_to_string(str, line->play_pitch);
345 break; 369 break;
346 case EDL_HEADER_LOCKPITCH: 370 case EDL_HEADER_LOCKPITCH:
347 APPEND_ITEM(lock_pitch, EDL_internal_bool_to_string); 371 EDL_internal_append_bool_to_string(str, line->lock_pitch);
348 break; 372 break;
349 case EDL_HEADER_FIRSTCHANNEL: 373 case EDL_HEADER_FIRSTCHANNEL:
350 APPEND_ITEM(first_channel, EDL_internal_integer_to_string); 374 EDL_internal_append_integer_to_string(str, line->first_channel);
351 break; 375 break;
352 case EDL_HEADER_CHANNELS: 376 case EDL_HEADER_CHANNELS:
353 APPEND_ITEM(channels, EDL_internal_integer_to_string); 377 EDL_internal_append_integer_to_string(str, line->channels);
354 break; 378 break;
355 default: 379 default:
356 /* ... what */ 380 /* ... what */
357 break; 381 break;
358 #undef APPEND_ITEM
359 } 382 }
360 383
361 if (i < order_len - 1) 384 if (i < header->size - 1)
362 EDL_internal_string_append(str, ";\t", 2); 385 EDL_internal_string_append(str, ";\t", 2);
363 else 386 else
364 EDL_internal_string_append(str, ";", 1); 387 EDL_internal_string_append(str, ";", 1);
365 } 388 }
366 389
379 EDL_internal_string_init(&ret); 402 EDL_internal_string_init(&ret);
380 403
381 EDL_internal_string_append(&ret, order_str, strlen(order_str)); 404 EDL_internal_string_append(&ret, order_str, strlen(order_str));
382 405
383 { 406 {
384 size_t order_len; 407 /* how? */
385 uint32_t* order = EDL_internal_parse_header(order_str, &order_len); 408 EDL_header header = {0};
409 if (EDL_internal_parse_header(&header, order_str, 0, strlen(order_str)) < 0)
410 return NULL;
386 411
387 size_t i; 412 size_t i;
388 for (i = 0; i < edl->size; i++) 413 for (i = 0; i < edl->size; i++)
389 EDL_dump_line(&ret, &edl->arr[i], order, order_len); 414 EDL_dump_line(&ret, &edl->arr[i], &header);
390 415
391 free(order); 416 EDL_internal_free_header(&header);
392 } 417 }
393 418
394 return ret.data; 419 return ret.data;
395 } 420 }
396 421