Mercurial > libedl
comparison src/edl.c @ 3:bd99b6549eb4
*: expand in readme and rename src/main to src/edl
author | Paper <mrpapersonic@gmail.com> |
---|---|
date | Sun, 24 Dec 2023 20:22:54 -0500 |
parents | |
children | c2408abb258a |
comparison
equal
deleted
inserted
replaced
2:d00bc412900e | 3:bd99b6549eb4 |
---|---|
1 #include <string.h> | |
2 #include <stdbool.h> | |
3 #include <stdio.h> | |
4 #include <stdlib.h> | |
5 #include <stdint.h> | |
6 #include "edl.h" | |
7 | |
8 #define strnchr(haystack, needle, length) (char*)memchr(haystack, needle, strnlen(haystack, length)) | |
9 | |
10 static uint32_t EDL_internal_crcn32b(const unsigned char* restrict message, size_t length) { | |
11 uint32_t crc = 0xFFFFFFFF; | |
12 | |
13 size_t i; | |
14 for (i = 0; i < length && message[i]; i++) { | |
15 crc = crc ^ message[i]; | |
16 size_t j; | |
17 for (j = 0; j < 8; j++) | |
18 crc = (crc >> 1) ^ (0xEDB88320 & -(crc & 1)); | |
19 } | |
20 | |
21 return ~crc; | |
22 } | |
23 | |
24 /* This parses the first line of the EDL and | |
25 * creates an array with CRC32 hashes in | |
26 * the order of the strings. | |
27 */ | |
28 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 uint32_t* hashes = malloc(hashes_size * sizeof(uint32_t)); | |
31 | |
32 size_t len_until_newline = strchr(data, '\n') - data, i, b; | |
33 for (i = 0, b = 0; i < len_until_newline; i++, b++) { | |
34 if (data[i] == ';') { | |
35 if (current_hash >= hashes_size) | |
36 hashes = realloc(hashes, (hashes_size *= 2) * sizeof(uint32_t)); | |
37 hashes[current_hash++] = EDL_internal_crcn32b((const unsigned char*)&data[i - b], b); | |
38 b = -1; // ew | |
39 } | |
40 } | |
41 | |
42 *length = current_hash; | |
43 | |
44 return hashes; | |
45 } | |
46 | |
47 /* -- Functions to extract different datatypes -- */ | |
48 | |
49 static size_t EDL_internal_append_offset(const char* input, size_t offset, size_t length) { | |
50 size_t s = 0; | |
51 | |
52 s += strchr(&input[offset + s], ';') - &input[offset]; | |
53 if (s + offset > length) | |
54 return s; | |
55 | |
56 s += strspn(&input[offset + s], ";\t "); | |
57 if (s + offset > length) | |
58 return s; | |
59 | |
60 return s; | |
61 } | |
62 | |
63 static size_t EDL_internal_get_int(const char* input, size_t offset, size_t length, int* int_return) { | |
64 if (offset > length) | |
65 return 0; | |
66 | |
67 { | |
68 char* ptr_return; | |
69 *int_return = strtol(&input[offset], &ptr_return, 10); | |
70 | |
71 if (!ptr_return) | |
72 return 0; | |
73 } | |
74 | |
75 return EDL_internal_append_offset(input, offset, length); | |
76 } | |
77 | |
78 static size_t EDL_internal_get_double(const char* input, size_t offset, size_t length, double* double_return) { | |
79 if (offset > length) | |
80 return 0; | |
81 | |
82 { | |
83 char* ptr_return; | |
84 *double_return = strtod(&input[offset], &ptr_return); | |
85 | |
86 if (!ptr_return) | |
87 return 0; | |
88 } | |
89 | |
90 return EDL_internal_append_offset(input, offset, length); | |
91 } | |
92 | |
93 static size_t EDL_internal_get_bool(const char* input, size_t offset, size_t length, bool* bool_return) { | |
94 if (offset > length) | |
95 return 0; | |
96 | |
97 if (strncmp((input + offset), "TRUE", 4)) | |
98 *bool_return = true; | |
99 else if (strncmp((input + offset), "FALSE", 5)) | |
100 *bool_return = false; | |
101 | |
102 return EDL_internal_append_offset(input, offset, length); | |
103 } | |
104 | |
105 static size_t EDL_internal_get_media_type(const char* input, size_t offset, size_t length, MediaType* media_return) { | |
106 if (offset > length) | |
107 return 0; | |
108 | |
109 if (strncmp(input + offset, "VIDEO", 5)) | |
110 *media_return = MEDIATYPE_VIDEO; | |
111 else if (strncmp(input + offset, "AUDIO", 5)) | |
112 *media_return = MEDIATYPE_AUDIO; | |
113 | |
114 return EDL_internal_append_offset(input, offset, length); | |
115 } | |
116 | |
117 static size_t EDL_internal_get_string(const char* input, size_t offset, size_t length, char** string_return) { | |
118 /* Windows filenames will *NEVER* include double quotes. | |
119 This might break with EDL files created with Reaper on Linux. */ | |
120 if (offset > length) | |
121 return 0; | |
122 | |
123 size_t start = strchr(&input[offset], '\"') - &input[offset] + 1; | |
124 if (start + offset > length) | |
125 return 0; | |
126 | |
127 size_t s_length = strchr(&input[offset + start], '\"') - &input[offset] - start; | |
128 if (start + s_length + offset > length) | |
129 return 0; | |
130 | |
131 *string_return = malloc((s_length + 1) * sizeof(char)); | |
132 if (!*string_return) | |
133 return 0; | |
134 | |
135 memcpy(*string_return, &input[offset + start], s_length); | |
136 (*string_return)[s_length] = '\0'; | |
137 | |
138 return EDL_internal_append_offset(input, offset, length); | |
139 } | |
140 | |
141 /* memory management routines */ | |
142 | |
143 static int EDL_internal_reallocate(EDL_file* input, size_t new_capacity) { | |
144 input->arr = realloc(input->arr, new_capacity * sizeof(EDL_line)); | |
145 if (!input->arr) | |
146 return 0; | |
147 | |
148 if (new_capacity > input->capacity) | |
149 memset(input->arr + input->capacity, 0, new_capacity - input->capacity); | |
150 | |
151 input->capacity = new_capacity; | |
152 | |
153 return 1; | |
154 } | |
155 | |
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 */ | |
165 EDL_file EDL_parse(const char* data, size_t length) { | |
166 EDL_file edl = {0}; | |
167 if (!EDL_internal_allocate_memory(&edl)) | |
168 return edl; | |
169 | |
170 size_t order_size = 0; | |
171 uint32_t* order = EDL_internal_parse_first_line(data, &order_size); | |
172 | |
173 size_t offset = strnchr(data, '\n', length) - data + 1; | |
174 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 | |
176 | |
177 bool ok = true; | |
178 | |
179 for (int i = 0; i < order_size; i++) { | |
180 #define ADD_TO_OFFSET(x, a) \ | |
181 { \ | |
182 size_t o = a(data, local_offset, length, &edl.arr[edl.size].x); \ | |
183 if (!o) \ | |
184 ok = false; \ | |
185 local_offset += o; \ | |
186 } | |
187 switch (order[i]) { | |
188 case 0x1541c503: /* ID */ | |
189 ADD_TO_OFFSET(id, EDL_internal_get_int); | |
190 break; | |
191 case 0x4b211812: /* Track */ | |
192 ADD_TO_OFFSET(track, EDL_internal_get_int); | |
193 break; | |
194 case 0xbb46516f: /* StartTime */ | |
195 ADD_TO_OFFSET(start_time, EDL_internal_get_double); | |
196 break; | |
197 case 0xaeac5df7: /* Length */ | |
198 ADD_TO_OFFSET(length, EDL_internal_get_double); | |
199 break; | |
200 case 0x03834606: /* PlayRate */ | |
201 ADD_TO_OFFSET(play_rate, EDL_internal_get_double); | |
202 break; | |
203 case 0x0c2083d3: /* Locked */ | |
204 ADD_TO_OFFSET(locked, EDL_internal_get_bool); | |
205 break; | |
206 case 0xe60c8b1d: /* Normalized */ | |
207 ADD_TO_OFFSET(normalized, EDL_internal_get_bool); | |
208 break; | |
209 case 0xbe5802c9: /* StretchMethod */ | |
210 ADD_TO_OFFSET(stretch_method, EDL_internal_get_int); | |
211 break; | |
212 case 0x4ec8be4c: /* Looped */ | |
213 ADD_TO_OFFSET(looped, EDL_internal_get_bool); | |
214 break; | |
215 case 0xe6cb84d1: /* OnRuler */ | |
216 ADD_TO_OFFSET(on_ruler, EDL_internal_get_bool); | |
217 break; | |
218 case 0x035f84c2: /* MediaType */ | |
219 ADD_TO_OFFSET(media_type, EDL_internal_get_media_type); | |
220 break; | |
221 case 0x379d32c5: /* FileName */ | |
222 ADD_TO_OFFSET(filename, EDL_internal_get_string); | |
223 break; | |
224 case 0x9f334738: /* Stream */ | |
225 ADD_TO_OFFSET(stream, EDL_internal_get_int); | |
226 break; | |
227 case 0x07b4e0e7: /* StreamStart */ | |
228 ADD_TO_OFFSET(stream_start, EDL_internal_get_double); | |
229 break; | |
230 case 0x8f16c7b8: /* StreamLength */ | |
231 ADD_TO_OFFSET(stream_length, EDL_internal_get_double); | |
232 break; | |
233 case 0xd2edd7e4: /* FadeTimeIn */ | |
234 ADD_TO_OFFSET(fade_time_in, EDL_internal_get_double); | |
235 break; | |
236 case 0x792e8c40: /* FadeTimeOut */ | |
237 ADD_TO_OFFSET(fade_time_out, EDL_internal_get_double); | |
238 break; | |
239 case 0x98374657: /* SustainGain */ | |
240 ADD_TO_OFFSET(sustain_gain, EDL_internal_get_double); | |
241 break; | |
242 case 0x3e998b1f: /* CurveIn */ | |
243 ADD_TO_OFFSET(curve_in, EDL_internal_get_int); | |
244 break; | |
245 case 0x82fb09c4: /* GainIn */ | |
246 ADD_TO_OFFSET(gain_in, EDL_internal_get_double); | |
247 break; | |
248 case 0x53add388: /* CurveOut */ | |
249 ADD_TO_OFFSET(curve_out, EDL_internal_get_int); | |
250 break; | |
251 case 0x4210ba56: /* GainOut */ | |
252 ADD_TO_OFFSET(gain_out, EDL_internal_get_double); | |
253 break; | |
254 case 0x89c4df6c: /* Layer */ | |
255 ADD_TO_OFFSET(layer, EDL_internal_get_int); | |
256 break; | |
257 case 0xadf2f1a3: /* Color */ | |
258 ADD_TO_OFFSET(color, EDL_internal_get_int); | |
259 break; | |
260 case 0xa56b43e1: /* CurveInR */ | |
261 ADD_TO_OFFSET(curve_in_r, EDL_internal_get_int); | |
262 break; | |
263 case 0xcb6d715e: /* CurveOutR */ | |
264 ADD_TO_OFFSET(curve_out_r, EDL_internal_get_int); | |
265 break; | |
266 case 0x9da1b9ed: /* PlayPitch */ | |
267 ADD_TO_OFFSET(play_pitch, EDL_internal_get_double); | |
268 break; | |
269 case 0x2bda6ed4: /* LockPitch */ | |
270 ADD_TO_OFFSET(lock_pitch, EDL_internal_get_bool); | |
271 break; | |
272 case 0x3071a4c6: /* FirstChannel */ | |
273 ADD_TO_OFFSET(first_channel, EDL_internal_get_int); | |
274 break; | |
275 case 0x7de1bd40: /* Channels */ | |
276 ADD_TO_OFFSET(channels, EDL_internal_get_int); | |
277 break; | |
278 default: | |
279 /* ... what */ | |
280 break; | |
281 } | |
282 } | |
283 | |
284 if (!ok) | |
285 break; | |
286 | |
287 if (++edl.size >= edl.capacity) | |
288 EDL_internal_allocate_memory(&edl); | |
289 } | |
290 | |
291 EDL_internal_shrink_memory_to_fit(&edl); | |
292 | |
293 free(order); | |
294 | |
295 return edl; | |
296 } | |
297 | |
298 void EDL_free(EDL_file file) { | |
299 size_t i; | |
300 for (i = 0; i < file.size; i++) { | |
301 if (file.arr[i].filename) | |
302 free(file.arr[i].filename); | |
303 } | |
304 free(file.arr); | |
305 } |