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