comparison src/edl.c @ 8:0c98b46eaf73 v2.0

*: update API to 2.0, big changes all APIs now use pointers to an EDL object. it is up to the user to make sure that the pointer is valid. additionally, many things have been separated into new files to make it easier to digest
author Paper <paper@paper.us.eu.org>
date Sun, 03 Mar 2024 17:56:58 -0500
parents 7137fbac0b85
children 0cc2555db371
comparison
equal deleted inserted replaced
7:fee08fa622e1 8:0c98b46eaf73
1 #include <string.h> 1 #include <string.h>
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
6 #include "edl.h" 7 #include "edl.h"
7 #include "str.h" 8 #include "str.h"
8 9 #include "datatypes.h"
9 #define strnchr(haystack, needle, length) (char*)memchr(haystack, needle, strnlen(haystack, length)) 10 #include "util.h"
10 11
11 static uint32_t EDL_internal_crcn32b(const unsigned char* restrict message, size_t length) { 12 /* CRC32 hashes of EDL headers */
12 uint32_t crc = 0xFFFFFFFF; 13 #define EDL_HEADER_ID 0x1541c503
13 14 #define EDL_HEADER_TRACK 0x4b211812
15 #define EDL_HEADER_STARTTIME 0xbb46516f
16 #define EDL_HEADER_LENGTH 0xaeac5df7
17 #define EDL_HEADER_PLAYRATE 0x03834606
18 #define EDL_HEADER_LOCKED 0x0c2083d3
19 #define EDL_HEADER_NORMALIZED 0xe60c8b1d
20 #define EDL_HEADER_STRETCHMETHOD 0xbe5802c9
21 #define EDL_HEADER_LOOPED 0x4ec8be4c
22 #define EDL_HEADER_ONRULER 0xe6cb84d1
23 #define EDL_HEADER_MEDIATYPE 0x035f84c2
24 #define EDL_HEADER_FILENAME 0x379d32c5
25 #define EDL_HEADER_STREAM 0x9f334738
26 #define EDL_HEADER_STREAMSTART 0x07b4e0e7
27 #define EDL_HEADER_STREAMLENGTH 0x8f16c7b8
28 #define EDL_HEADER_FADETIMEIN 0xd2edd7e4
29 #define EDL_HEADER_FADETIMEOUT 0x792e8c40
30 #define EDL_HEADER_SUSTAINGAIN 0x98374657
31 #define EDL_HEADER_CURVEIN 0x3e998b1f
32 #define EDL_HEADER_GAININ 0x82fb09c4
33 #define EDL_HEADER_CURVEOUT 0x53add388
34 #define EDL_HEADER_GAINOUT 0x4210ba56
35 #define EDL_HEADER_LAYER 0x89c4df6c
36 #define EDL_HEADER_COLOR 0xadf2f1a3
37 #define EDL_HEADER_CURVEINR 0xa56b43e1
38 #define EDL_HEADER_CURVEOUTR 0xcb6d715e
39 #define EDL_HEADER_PLAYPITCH 0x9da1b9ed
40 #define EDL_HEADER_LOCKPITCH 0x2bda6ed4
41 #define EDL_HEADER_FIRSTCHANNEL 0x3071a4c6
42 #define EDL_HEADER_CHANNELS 0xe94981a4
43
44 /* use a CRC32 hash function to process the headers */
45 static uint32_t EDL_internal_crcn32b(const unsigned char* message, size_t length) {
46 uint32_t crc = 0xffffffff;
14 size_t i; 47 size_t i;
48
15 for (i = 0; i < length && message[i]; i++) { 49 for (i = 0; i < length && message[i]; i++) {
50 size_t j;
51
16 crc = crc ^ message[i]; 52 crc = crc ^ message[i];
17 size_t j;
18 for (j = 0; j < 8; j++) 53 for (j = 0; j < 8; j++)
19 crc = (crc >> 1) ^ (0xEDB88320 & -(crc & 1)); 54 crc = (crc >> 1) ^ (0xedb88320 & -(crc & 1));
20 } 55 }
21 56
22 return ~crc; 57 return ~crc;
23 } 58 }
24 59
25 /* This parses the first line of the EDL and 60 static size_t EDL_internal_size_t_min(size_t a, size_t b) {
26 * creates an array with CRC32 hashes in 61 return (a < b) ? a : b;
27 * the order of the strings. 62 }
63
64 /* This parses the header of the EDL and creates an array with CRC32 hashes
65 * in the order of the strings.
28 */ 66 */
29 static uint32_t* EDL_internal_parse_first_line(const char* data, size_t* restrict length) { 67 static uint32_t* EDL_internal_parse_header(const char* data, size_t* length) {
30 size_t hashes_size = 32, current_hash = 0; 68 /* */
69 const size_t newline = EDL_internal_size_t_min(strchr(data, '\n') - data, strchr(data, '\r') - data);
70
71 size_t current_hash = 0, hashes_size = 32;
31 uint32_t* hashes = malloc(hashes_size * sizeof(uint32_t)); 72 uint32_t* hashes = malloc(hashes_size * sizeof(uint32_t));
32 73
33 size_t len_until_newline = strchr(data, '\n') - data, len_until_cr = strchr(data, '\r') - data; 74 /* overall iterates over the entire line,
34 size_t i, b; 75 * column stores the length of the current column */
35 for (i = 0, b = 0; i <= len_until_newline && i <= len_until_cr; i++, b++) { 76 size_t overall, column;
36 if (data[i] == ';' || data[i] == ':' || data[i] == '\r' || data[i] == '\n') { 77
37 if (current_hash >= hashes_size) 78 for (overall = 0, column = 0; overall <= newline; overall++) {
79 if (data[overall] == ';' || data[overall] == ':') {
80 /* process the current column */
81 if (hashes_size < current_hash)
38 hashes = realloc(hashes, (hashes_size *= 2) * sizeof(uint32_t)); 82 hashes = realloc(hashes, (hashes_size *= 2) * sizeof(uint32_t));
39 hashes[current_hash++] = EDL_internal_crcn32b((const unsigned char*)&data[i - b], b); 83
40 b = -1; // ew 84 hashes[current_hash++] = EDL_internal_crcn32b((const unsigned char*)&data[overall - column], column);
41 } 85 column = 0; /* reset */
42 } 86 } else column++;
43 87 }
44 *length = current_hash; // wtf? 88
89 *length = current_hash;
45 90
46 return hashes; 91 return hashes;
47 } 92 }
48 93
49 /* -- Functions to extract different datatypes -- */ 94 int EDL_reallocate(EDL* edl, size_t new_capacity) {
50 95 edl->arr = realloc(edl->arr, new_capacity * sizeof(EDL_line));
51 static size_t EDL_internal_append_offset(const char* input, size_t offset, size_t length) { 96 if (!edl->arr)
52 size_t s = 0;
53
54 s += strchr(&input[offset + s], ';') - &input[offset];
55 if (s + offset > length)
56 return s;
57
58 s += strspn(&input[offset + s], ";\t ");
59 if (s + offset > length)
60 return s;
61
62 return s;
63 }
64
65 static size_t EDL_internal_get_int(const char* input, size_t offset, size_t length, int* int_return) {
66 if (offset > length)
67 return 0; 97 return 0;
68 98
69 { 99 if (new_capacity > edl->capacity)
70 char* ptr_return; 100 memset(&edl->arr[edl->capacity], 0, (new_capacity - edl->capacity) * sizeof(EDL_line));
71 *int_return = strtol(&input[offset], &ptr_return, 10); 101
72 102 edl->capacity = new_capacity;
73 if (!ptr_return) 103
74 return 0; 104 return 1;
75 } 105 }
76 106
77 return EDL_internal_append_offset(input, offset, length); 107 int EDL_append(EDL* edl, EDL_line line) {
78 } 108 if (edl->size + 1 < edl->capacity && !EDL_reallocate(edl, edl->capacity))
79
80 static size_t EDL_internal_get_double(const char* input, size_t offset, size_t length, double* double_return) {
81 if (offset > length)
82 return 0; 109 return 0;
83 110
84 { 111 edl->arr[++edl->size] = line;
85 char* ptr_return;
86 *double_return = strtod(&input[offset], &ptr_return);
87
88 if (!ptr_return)
89 return 0;
90 }
91
92 return EDL_internal_append_offset(input, offset, length);
93 }
94
95 static size_t EDL_internal_get_bool(const char* input, size_t offset, size_t length, bool* bool_return) {
96 if (offset > length)
97 return 0;
98
99 if (!strncmp(&input[offset], "TRUE", 4))
100 *bool_return = true;
101 else if (!strncmp(&input[offset], "FALSE", 5))
102 *bool_return = false;
103
104 return EDL_internal_append_offset(input, offset, length);
105 }
106
107 static size_t EDL_internal_get_media_type(const char* input, size_t offset, size_t length, MediaType* media_return) {
108 if (offset > length)
109 return 0;
110
111 if (!strncmp(&input[offset], "VIDEO", 5))
112 *media_return = MEDIATYPE_VIDEO;
113 else if (!strncmp(&input[offset], "AUDIO", 5))
114 *media_return = MEDIATYPE_AUDIO;
115 else
116 *media_return = MEDIATYPE_UNKNOWN;
117
118 return EDL_internal_append_offset(input, offset, length);
119 }
120
121 static size_t EDL_internal_get_string(const char* input, size_t offset, size_t length, char** string_return) {
122 /* Windows filenames will *NEVER* include double quotes.
123 This might break with EDL files created with Reaper on Linux. */
124 if (offset > length)
125 return 0;
126
127 size_t start = strchr(&input[offset], '\"') - &input[offset] + 1;
128 if (start + offset > length)
129 return 0;
130
131 size_t s_length = strchr(&input[offset + start], '\"') - &input[offset] - start;
132 if (start + s_length + offset > length)
133 return 0;
134
135 *string_return = malloc((s_length + 1) * sizeof(char));
136 if (!*string_return)
137 return 0;
138
139 memcpy(*string_return, &input[offset + start], s_length);
140 (*string_return)[s_length] = '\0';
141
142 return EDL_internal_append_offset(input, offset, length);
143 }
144
145 /* memory management routines */
146
147 int EDL_reallocate(EDL* input, size_t new_capacity) {
148 input->arr = realloc(input->arr, new_capacity * sizeof(EDL_line));
149 if (!input->arr)
150 return 0;
151
152 if (new_capacity > input->capacity)
153 memset(&input->arr[input->capacity], 0, (new_capacity - input->capacity) * sizeof(EDL_line));
154
155 input->capacity = new_capacity;
156
157 return 1; 112 return 1;
158 } 113 }
159 114
160 /* the important function */ 115 /* the big important function */
161 EDL EDL_parse(const char* data, size_t length) { 116 EDL_parse_error_t EDL_parse(EDL* edl, const char* data, size_t length) {
162 EDL edl = {0};
163 if (!EDL_reallocate(&edl, 16))
164 return edl;
165
166 size_t order_size = 0; 117 size_t order_size = 0;
167 uint32_t* order = EDL_internal_parse_first_line(data, &order_size); 118 uint32_t* order = NULL;
168
169 size_t offset = 0; 119 size_t offset = 0;
170 while ((offset = strnchr(&data[offset], '\n', length - offset) - data + 1) < length) { 120
171 size_t local_offset = offset; // this is so our original offset stays intact 121 if (!EDL_reallocate(edl, 16))
172 122 return EDL_PARSE_ERROR_OUT_OF_MEMORY;
123
124 order = EDL_internal_parse_header(data, &order_size);
125
126 while ((offset = EDL_internal_strnchr(&data[offset], '\n', length - offset) - data + 1) < length) {
127 size_t local_offset = offset; /* original offset stays intact */
173 bool ok = true; 128 bool ok = true;
174 129 int i;
175 for (int i = 0; i < order_size; i++) { 130
131 for (i = 0; i < order_size; i++) {
176 #define ADD_TO_OFFSET(x, a) \ 132 #define ADD_TO_OFFSET(x, a) \
177 { \ 133 { \
178 size_t o = a(data, local_offset, length, &edl.arr[edl.size].x); \ 134 size_t o = a(data, local_offset, length, &edl->arr[edl->size].x); \
179 if (!o) \ 135 if (!o) \
180 ok = false; \ 136 ok = false; \
181 local_offset += o; \ 137 local_offset += o; \
182 } 138 }
183 switch (order[i]) { 139 switch (order[i]) {
184 case 0x1541c503: /* ID */ 140 case EDL_HEADER_ID:
185 ADD_TO_OFFSET(id, EDL_internal_get_int); 141 ADD_TO_OFFSET(id, EDL_internal_parse_int);
186 break; 142 break;
187 case 0x4b211812: /* Track */ 143 case EDL_HEADER_TRACK:
188 ADD_TO_OFFSET(track, EDL_internal_get_int); 144 ADD_TO_OFFSET(track, EDL_internal_parse_int);
189 break; 145 break;
190 case 0xbb46516f: /* StartTime */ 146 case EDL_HEADER_STARTTIME:
191 ADD_TO_OFFSET(start_time, EDL_internal_get_double); 147 ADD_TO_OFFSET(start_time, EDL_internal_parse_double);
192 break; 148 break;
193 case 0xaeac5df7: /* Length */ 149 case EDL_HEADER_LENGTH:
194 ADD_TO_OFFSET(length, EDL_internal_get_double); 150 ADD_TO_OFFSET(length, EDL_internal_parse_double);
195 break; 151 break;
196 case 0x03834606: /* PlayRate */ 152 case EDL_HEADER_PLAYRATE:
197 ADD_TO_OFFSET(play_rate, EDL_internal_get_double); 153 ADD_TO_OFFSET(play_rate, EDL_internal_parse_double);
198 break; 154 break;
199 case 0x0c2083d3: /* Locked */ 155 case EDL_HEADER_LOCKED:
200 ADD_TO_OFFSET(locked, EDL_internal_get_bool); 156 ADD_TO_OFFSET(locked, EDL_internal_parse_bool);
201 break; 157 break;
202 case 0xe60c8b1d: /* Normalized */ 158 case EDL_HEADER_NORMALIZED:
203 ADD_TO_OFFSET(normalized, EDL_internal_get_bool); 159 ADD_TO_OFFSET(normalized, EDL_internal_parse_bool);
204 break; 160 break;
205 case 0xbe5802c9: /* StretchMethod */ 161 case EDL_HEADER_STRETCHMETHOD:
206 ADD_TO_OFFSET(stretch_method, EDL_internal_get_int); 162 ADD_TO_OFFSET(stretch_method, EDL_internal_parse_int);
207 break; 163 break;
208 case 0x4ec8be4c: /* Looped */ 164 case EDL_HEADER_LOOPED:
209 ADD_TO_OFFSET(looped, EDL_internal_get_bool); 165 ADD_TO_OFFSET(looped, EDL_internal_parse_bool);
210 break; 166 break;
211 case 0xe6cb84d1: /* OnRuler */ 167 case EDL_HEADER_ONRULER:
212 ADD_TO_OFFSET(on_ruler, EDL_internal_get_bool); 168 ADD_TO_OFFSET(on_ruler, EDL_internal_parse_bool);
213 break; 169 break;
214 case 0x035f84c2: /* MediaType */ 170 case EDL_HEADER_MEDIATYPE:
215 ADD_TO_OFFSET(media_type, EDL_internal_get_media_type); 171 ADD_TO_OFFSET(media_type, EDL_internal_parse_media_type);
216 break; 172 break;
217 case 0x379d32c5: /* FileName */ 173 case EDL_HEADER_FILENAME:
218 ADD_TO_OFFSET(filename, EDL_internal_get_string); 174 ADD_TO_OFFSET(filename, EDL_internal_parse_string);
219 break; 175 break;
220 case 0x9f334738: /* Stream */ 176 case EDL_HEADER_STREAM:
221 ADD_TO_OFFSET(stream, EDL_internal_get_int); 177 ADD_TO_OFFSET(stream, EDL_internal_parse_int);
222 break; 178 break;
223 case 0x07b4e0e7: /* StreamStart */ 179 case EDL_HEADER_STREAMSTART:
224 ADD_TO_OFFSET(stream_start, EDL_internal_get_double); 180 ADD_TO_OFFSET(stream_start, EDL_internal_parse_double);
225 break; 181 break;
226 case 0x8f16c7b8: /* StreamLength */ 182 case EDL_HEADER_STREAMLENGTH:
227 ADD_TO_OFFSET(stream_length, EDL_internal_get_double); 183 ADD_TO_OFFSET(stream_length, EDL_internal_parse_double);
228 break; 184 break;
229 case 0xd2edd7e4: /* FadeTimeIn */ 185 case EDL_HEADER_FADETIMEIN:
230 ADD_TO_OFFSET(fade_time_in, EDL_internal_get_double); 186 ADD_TO_OFFSET(fade_time_in, EDL_internal_parse_double);
231 break; 187 break;
232 case 0x792e8c40: /* FadeTimeOut */ 188 case EDL_HEADER_FADETIMEOUT:
233 ADD_TO_OFFSET(fade_time_out, EDL_internal_get_double); 189 ADD_TO_OFFSET(fade_time_out, EDL_internal_parse_double);
234 break; 190 break;
235 case 0x98374657: /* SustainGain */ 191 case EDL_HEADER_SUSTAINGAIN:
236 ADD_TO_OFFSET(sustain_gain, EDL_internal_get_double); 192 ADD_TO_OFFSET(sustain_gain, EDL_internal_parse_double);
237 break; 193 break;
238 case 0x3e998b1f: /* CurveIn */ 194 case EDL_HEADER_CURVEIN:
239 ADD_TO_OFFSET(curve_in, EDL_internal_get_int); 195 ADD_TO_OFFSET(curve_in, EDL_internal_parse_int);
240 break; 196 break;
241 case 0x82fb09c4: /* GainIn */ 197 case EDL_HEADER_GAININ:
242 ADD_TO_OFFSET(gain_in, EDL_internal_get_double); 198 ADD_TO_OFFSET(gain_in, EDL_internal_parse_double);
243 break; 199 break;
244 case 0x53add388: /* CurveOut */ 200 case EDL_HEADER_CURVEOUT:
245 ADD_TO_OFFSET(curve_out, EDL_internal_get_int); 201 ADD_TO_OFFSET(curve_out, EDL_internal_parse_int);
246 break; 202 break;
247 case 0x4210ba56: /* GainOut */ 203 case EDL_HEADER_GAINOUT:
248 ADD_TO_OFFSET(gain_out, EDL_internal_get_double); 204 ADD_TO_OFFSET(gain_out, EDL_internal_parse_double);
249 break; 205 break;
250 case 0x89c4df6c: /* Layer */ 206 case EDL_HEADER_LAYER:
251 ADD_TO_OFFSET(layer, EDL_internal_get_int); 207 ADD_TO_OFFSET(layer, EDL_internal_parse_int);
252 break; 208 break;
253 case 0xadf2f1a3: /* Color */ 209 case EDL_HEADER_COLOR:
254 ADD_TO_OFFSET(color, EDL_internal_get_int); 210 ADD_TO_OFFSET(color, EDL_internal_parse_int);
255 break; 211 break;
256 case 0xa56b43e1: /* CurveInR */ 212 case EDL_HEADER_CURVEINR:
257 ADD_TO_OFFSET(curve_in_r, EDL_internal_get_int); 213 ADD_TO_OFFSET(curve_in_r, EDL_internal_parse_int);
258 break; 214 break;
259 case 0xcb6d715e: /* CurveOutR */ 215 case EDL_HEADER_CURVEOUTR:
260 ADD_TO_OFFSET(curve_out_r, EDL_internal_get_int); 216 ADD_TO_OFFSET(curve_out_r, EDL_internal_parse_int);
261 break; 217 break;
262 case 0x9da1b9ed: /* PlayPitch */ 218 case EDL_HEADER_PLAYPITCH:
263 ADD_TO_OFFSET(play_pitch, EDL_internal_get_double); 219 ADD_TO_OFFSET(play_pitch, EDL_internal_parse_double);
264 break; 220 break;
265 case 0x2bda6ed4: /* LockPitch */ 221 case EDL_HEADER_LOCKPITCH:
266 ADD_TO_OFFSET(lock_pitch, EDL_internal_get_bool); 222 ADD_TO_OFFSET(lock_pitch, EDL_internal_parse_bool);
267 break; 223 break;
268 case 0x3071a4c6: /* FirstChannel */ 224 case EDL_HEADER_FIRSTCHANNEL:
269 ADD_TO_OFFSET(first_channel, EDL_internal_get_int); 225 ADD_TO_OFFSET(first_channel, EDL_internal_parse_int);
270 break; 226 break;
271 case 0xe94981a4: /* Channels */ 227 case EDL_HEADER_CHANNELS:
272 ADD_TO_OFFSET(channels, EDL_internal_get_int); 228 ADD_TO_OFFSET(channels, EDL_internal_parse_int);
273 break; 229 break;
274 default: 230 default:
275 /* ... what */ 231 /* ... what */
276 break; 232 break;
277 #undef ADD_TO_OFFSET 233 #undef ADD_TO_OFFSET
279 } 235 }
280 236
281 if (!ok) 237 if (!ok)
282 break; 238 break;
283 239
284 if (++edl.size >= edl.capacity) 240 if (++edl->size >= edl->capacity)
285 EDL_reallocate(&edl, edl.capacity * 2); 241 EDL_reallocate(edl, edl->capacity * 2);
286 } 242 }
287 243
288 EDL_reallocate(&edl, edl.size); 244 /* put on the shrinkwrap */
245 EDL_reallocate(edl, edl->size);
289 246
290 free(order); 247 free(order);
291 248
292 return edl; 249 return EDL_PARSE_ERROR_SUCCESS;
293 } 250 }
294 251
295 static char* EDL_internal_integer_to_string(int value) { 252 static void EDL_dump_line(EDL_internal_string* str, const EDL_line* line, const uint32_t* order, const size_t order_len) {
296 char out[256] = {0}; // this ought to be enough. 253 size_t i;
297 snprintf(out, 256, "%d", value); 254
298 out[255] = '\0'; 255 for (i = 0; i < order_len; i++) {
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]) { 256 switch (order[i]) {
327 #define APPEND_ITEM(a, x) \ 257 #define APPEND_ITEM(a, x) \
328 { \ 258 { \
329 char* tstr = x(line.a); \ 259 char* tstr = x(line->a); \
330 EDL_internal_string_append(str, tstr, strlen(tstr)); \ 260 EDL_internal_string_append(str, tstr, strlen(tstr)); \
331 free(tstr); \ 261 free(tstr); \
332 } 262 }
333 case 0x1541c503: /* ID */ 263 case EDL_HEADER_ID:
334 APPEND_ITEM(id, EDL_internal_integer_to_string); 264 APPEND_ITEM(id, EDL_internal_integer_to_string);
335 break; 265 break;
336 case 0x4b211812: /* Track */ 266 case EDL_HEADER_TRACK:
337 APPEND_ITEM(track, EDL_internal_integer_to_string); 267 APPEND_ITEM(track, EDL_internal_integer_to_string);
338 break; 268 break;
339 case 0xbb46516f: /* StartTime */ 269 case EDL_HEADER_STARTTIME:
340 APPEND_ITEM(start_time, EDL_internal_double_to_string); 270 APPEND_ITEM(start_time, EDL_internal_double_to_string);
341 break; 271 break;
342 case 0xaeac5df7: /* Length */ 272 case EDL_HEADER_LENGTH:
343 APPEND_ITEM(length, EDL_internal_double_to_string); 273 APPEND_ITEM(length, EDL_internal_double_to_string);
344 break; 274 break;
345 case 0x03834606: /* PlayRate */ 275 case EDL_HEADER_PLAYRATE:
346 APPEND_ITEM(play_rate, EDL_internal_double_to_string); 276 APPEND_ITEM(play_rate, EDL_internal_double_to_string);
347 break; 277 break;
348 case 0x0c2083d3: /* Locked */ 278 case EDL_HEADER_LOCKED:
349 APPEND_ITEM(locked, EDL_internal_bool_to_string); 279 APPEND_ITEM(locked, EDL_internal_bool_to_string);
350 break; 280 break;
351 case 0xe60c8b1d: /* Normalized */ 281 case EDL_HEADER_NORMALIZED:
352 APPEND_ITEM(normalized, EDL_internal_bool_to_string); 282 APPEND_ITEM(normalized, EDL_internal_bool_to_string);
353 break; 283 break;
354 case 0xbe5802c9: /* StretchMethod */ 284 case EDL_HEADER_STRETCHMETHOD:
355 APPEND_ITEM(stretch_method, EDL_internal_integer_to_string); 285 APPEND_ITEM(stretch_method, EDL_internal_integer_to_string);
356 break; 286 break;
357 case 0x4ec8be4c: /* Looped */ 287 case EDL_HEADER_LOOPED:
358 APPEND_ITEM(looped, EDL_internal_bool_to_string); 288 APPEND_ITEM(looped, EDL_internal_bool_to_string);
359 break; 289 break;
360 case 0xe6cb84d1: /* OnRuler */ 290 case EDL_HEADER_ONRULER:
361 APPEND_ITEM(on_ruler, EDL_internal_bool_to_string); 291 APPEND_ITEM(on_ruler, EDL_internal_bool_to_string);
362 break; 292 break;
363 case 0x035f84c2: /* MediaType */ 293 case EDL_HEADER_MEDIATYPE:
364 APPEND_ITEM(media_type, EDL_internal_media_type_to_string); 294 APPEND_ITEM(media_type, EDL_internal_media_type_to_string);
365 break; 295 break;
366 case 0x379d32c5: /* FileName */ 296 case EDL_HEADER_FILENAME:
367 EDL_internal_string_append(str, "\"", 1); 297 EDL_internal_string_append(str, "\"", 1);
368 EDL_internal_string_append(str, line.filename, strlen(line.filename)); 298 EDL_internal_string_append(str, line->filename, strlen(line->filename));
369 EDL_internal_string_append(str, "\"", 1); 299 EDL_internal_string_append(str, "\"", 1);
370 break; 300 break;
371 case 0x9f334738: /* Stream */ 301 case EDL_HEADER_STREAM:
372 APPEND_ITEM(stream, EDL_internal_integer_to_string); 302 APPEND_ITEM(stream, EDL_internal_integer_to_string);
373 break; 303 break;
374 case 0x07b4e0e7: /* StreamStart */ 304 case EDL_HEADER_STREAMSTART:
375 APPEND_ITEM(stream_start, EDL_internal_double_to_string); 305 APPEND_ITEM(stream_start, EDL_internal_double_to_string);
376 break; 306 break;
377 case 0x8f16c7b8: /* StreamLength */ 307 case EDL_HEADER_STREAMLENGTH:
378 APPEND_ITEM(stream_length, EDL_internal_double_to_string); 308 APPEND_ITEM(stream_length, EDL_internal_double_to_string);
379 break; 309 break;
380 case 0xd2edd7e4: /* FadeTimeIn */ 310 case EDL_HEADER_FADETIMEIN:
381 APPEND_ITEM(fade_time_in, EDL_internal_double_to_string); 311 APPEND_ITEM(fade_time_in, EDL_internal_double_to_string);
382 break; 312 break;
383 case 0x792e8c40: /* FadeTimeOut */ 313 case EDL_HEADER_FADETIMEOUT:
384 APPEND_ITEM(fade_time_out, EDL_internal_double_to_string); 314 APPEND_ITEM(fade_time_out, EDL_internal_double_to_string);
385 break; 315 break;
386 case 0x98374657: /* SustainGain */ 316 case EDL_HEADER_SUSTAINGAIN:
387 APPEND_ITEM(sustain_gain, EDL_internal_double_to_string); 317 APPEND_ITEM(sustain_gain, EDL_internal_double_to_string);
388 break; 318 break;
389 case 0x3e998b1f: /* CurveIn */ 319 case EDL_HEADER_CURVEIN:
390 APPEND_ITEM(curve_in, EDL_internal_integer_to_string); 320 APPEND_ITEM(curve_in, EDL_internal_integer_to_string);
391 break; 321 break;
392 case 0x82fb09c4: /* GainIn */ 322 case EDL_HEADER_GAININ:
393 APPEND_ITEM(gain_in, EDL_internal_double_to_string); 323 APPEND_ITEM(gain_in, EDL_internal_double_to_string);
394 break; 324 break;
395 case 0x53add388: /* CurveOut */ 325 case EDL_HEADER_CURVEOUT:
396 APPEND_ITEM(curve_out, EDL_internal_integer_to_string); 326 APPEND_ITEM(curve_out, EDL_internal_integer_to_string);
397 break; 327 break;
398 case 0x4210ba56: /* GainOut */ 328 case EDL_HEADER_GAINOUT:
399 APPEND_ITEM(gain_out, EDL_internal_double_to_string); 329 APPEND_ITEM(gain_out, EDL_internal_double_to_string);
400 break; 330 break;
401 case 0x89c4df6c: /* Layer */ 331 case EDL_HEADER_LAYER:
402 APPEND_ITEM(layer, EDL_internal_integer_to_string); 332 APPEND_ITEM(layer, EDL_internal_integer_to_string);
403 break; 333 break;
404 case 0xadf2f1a3: /* Color */ 334 case EDL_HEADER_COLOR:
405 APPEND_ITEM(color, EDL_internal_integer_to_string); 335 APPEND_ITEM(color, EDL_internal_integer_to_string);
406 break; 336 break;
407 case 0xa56b43e1: /* CurveInR */ 337 case EDL_HEADER_CURVEINR:
408 APPEND_ITEM(curve_in_r, EDL_internal_integer_to_string); 338 APPEND_ITEM(curve_in_r, EDL_internal_integer_to_string);
409 break; 339 break;
410 case 0xcb6d715e: /* CurveOutR */ 340 case EDL_HEADER_CURVEOUTR:
411 APPEND_ITEM(curve_out_r, EDL_internal_integer_to_string); 341 APPEND_ITEM(curve_out_r, EDL_internal_integer_to_string);
412 break; 342 break;
413 case 0x9da1b9ed: /* PlayPitch */ 343 case EDL_HEADER_PLAYPITCH:
414 APPEND_ITEM(play_pitch, EDL_internal_double_to_string); 344 APPEND_ITEM(play_pitch, EDL_internal_double_to_string);
415 break; 345 break;
416 case 0x2bda6ed4: /* LockPitch */ 346 case EDL_HEADER_LOCKPITCH:
417 APPEND_ITEM(lock_pitch, EDL_internal_bool_to_string); 347 APPEND_ITEM(lock_pitch, EDL_internal_bool_to_string);
418 break; 348 break;
419 case 0x3071a4c6: /* FirstChannel */ 349 case EDL_HEADER_FIRSTCHANNEL:
420 APPEND_ITEM(first_channel, EDL_internal_integer_to_string); 350 APPEND_ITEM(first_channel, EDL_internal_integer_to_string);
421 break; 351 break;
422 case 0xe94981a4: /* Channels */ 352 case EDL_HEADER_CHANNELS:
423 APPEND_ITEM(channels, EDL_internal_integer_to_string); 353 APPEND_ITEM(channels, EDL_internal_integer_to_string);
424 break; 354 break;
425 default: 355 default:
426 /* ... what */ 356 /* ... what */
427 break; 357 break;
435 } 365 }
436 366
437 EDL_internal_string_append(str, "\n", 1); 367 EDL_internal_string_append(str, "\n", 1);
438 } 368 }
439 369
440 char* EDL_dump(EDL edl) { 370 /* this gets progressively slower and slower... oops */
371 char* EDL_dump(const EDL* edl) {
372 static const char order_str[] =
373 "\"ID\";\"Track\";\"StartTime\";\"Length\";\"PlayRate\";\"Locked\";\"Normalized\";\"StretchMethod\";"
374 "\"Looped\";\"OnRuler\";\"MediaType\";\"FileName\";\"Stream\";\"StreamStart\";\"StreamLength\";"
375 "\"FadeTimeIn\";\"FadeTimeOut\";\"SustainGain\";\"CurveIn\";\"GainIn\";\"CurveOut\";\"GainOut\";"
376 "\"Layer\";\"Color\";\"CurveInR\";\"CurveOutR\":\"PlayPitch\";\"LockPitch\";\"FirstChannel\";\"Channels\"\n";
377
441 EDL_internal_string ret; 378 EDL_internal_string ret;
442 EDL_internal_string_init(&ret); 379 EDL_internal_string_init(&ret);
443 380
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)); 381 EDL_internal_string_append(&ret, order_str, strlen(order_str));
446 382
447 size_t order_len; 383 {
448 uint32_t* order = EDL_internal_parse_first_line(order_str, &order_len); 384 size_t order_len;
449 385 uint32_t* order = EDL_internal_parse_header(order_str, &order_len);
386
387 size_t i;
388 for (i = 0; i < edl->size; i++)
389 EDL_dump_line(&ret, &edl->arr[i], order, order_len);
390
391 free(order);
392 }
393
394 return ret.data;
395 }
396
397 void EDL_free(EDL* edl) {
450 size_t i; 398 size_t i;
451 for (i = 0; i < edl.size; i++) 399 for (i = 0; i < edl->size; i++) {
452 EDL_dump_line(&ret, edl.arr[i], order, order_len); 400 if (edl->arr[i].filename)
453 401 free(edl->arr[i].filename);
454 free(order); 402 }
455 403 free(edl->arr);
456 EDL_internal_string_allocate(&ret, ret.size); 404 }
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 }