FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/ass_split.c
Date: 2024-04-23 16:28:37
Exec Total Coverage
Lines: 233 292 79.8%
Functions: 16 19 84.2%
Branches: 177 270 65.6%

Line Branch Exec Source
1 /*
2 * SSA/ASS spliting functions
3 * Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include <limits.h>
23 #include <stddef.h>
24 #include <stdint.h>
25 #include <stdio.h>
26 #include <string.h>
27
28 #include "libavutil/error.h"
29 #include "libavutil/macros.h"
30 #include "libavutil/mem.h"
31 #include "ass_split.h"
32
33 typedef enum {
34 ASS_STR,
35 ASS_INT,
36 ASS_FLT,
37 ASS_COLOR,
38 ASS_TIMESTAMP,
39 ASS_ALGN,
40 } ASSFieldType;
41
42 typedef struct {
43 const char *name;
44 int type;
45 int offset;
46 } ASSFields;
47
48 typedef struct {
49 const char *section;
50 const char *format_header;
51 const char *fields_header;
52 int size;
53 int offset;
54 int offset_count;
55 ASSFields fields[24];
56 } ASSSection;
57
58 static const ASSSection ass_sections[] = {
59 { .section = "Script Info",
60 .offset = offsetof(ASS, script_info),
61 .fields = {{"ScriptType", ASS_STR, offsetof(ASSScriptInfo, script_type)},
62 {"Collisions", ASS_STR, offsetof(ASSScriptInfo, collisions) },
63 {"PlayResX", ASS_INT, offsetof(ASSScriptInfo, play_res_x) },
64 {"PlayResY", ASS_INT, offsetof(ASSScriptInfo, play_res_y) },
65 {"Timer", ASS_FLT, offsetof(ASSScriptInfo, timer) },
66 {0},
67 }
68 },
69 { .section = "V4+ Styles",
70 .format_header = "Format",
71 .fields_header = "Style",
72 .size = sizeof(ASSStyle),
73 .offset = offsetof(ASS, styles),
74 .offset_count = offsetof(ASS, styles_count),
75 .fields = {{"Name", ASS_STR, offsetof(ASSStyle, name) },
76 {"Fontname", ASS_STR, offsetof(ASSStyle, font_name) },
77 {"Fontsize", ASS_INT, offsetof(ASSStyle, font_size) },
78 {"PrimaryColour", ASS_COLOR, offsetof(ASSStyle, primary_color) },
79 {"SecondaryColour", ASS_COLOR, offsetof(ASSStyle, secondary_color)},
80 {"OutlineColour", ASS_COLOR, offsetof(ASSStyle, outline_color) },
81 {"BackColour", ASS_COLOR, offsetof(ASSStyle, back_color) },
82 {"Bold", ASS_INT, offsetof(ASSStyle, bold) },
83 {"Italic", ASS_INT, offsetof(ASSStyle, italic) },
84 {"Underline", ASS_INT, offsetof(ASSStyle, underline) },
85 {"StrikeOut", ASS_INT, offsetof(ASSStyle, strikeout) },
86 {"ScaleX", ASS_FLT, offsetof(ASSStyle, scalex) },
87 {"ScaleY", ASS_FLT, offsetof(ASSStyle, scaley) },
88 {"Spacing", ASS_FLT, offsetof(ASSStyle, spacing) },
89 {"Angle", ASS_FLT, offsetof(ASSStyle, angle) },
90 {"BorderStyle", ASS_INT, offsetof(ASSStyle, border_style) },
91 {"Outline", ASS_FLT, offsetof(ASSStyle, outline) },
92 {"Shadow", ASS_FLT, offsetof(ASSStyle, shadow) },
93 {"Alignment", ASS_INT, offsetof(ASSStyle, alignment) },
94 {"MarginL", ASS_INT, offsetof(ASSStyle, margin_l) },
95 {"MarginR", ASS_INT, offsetof(ASSStyle, margin_r) },
96 {"MarginV", ASS_INT, offsetof(ASSStyle, margin_v) },
97 {"Encoding", ASS_INT, offsetof(ASSStyle, encoding) },
98 {0},
99 }
100 },
101 { .section = "V4 Styles",
102 .format_header = "Format",
103 .fields_header = "Style",
104 .size = sizeof(ASSStyle),
105 .offset = offsetof(ASS, styles),
106 .offset_count = offsetof(ASS, styles_count),
107 .fields = {{"Name", ASS_STR, offsetof(ASSStyle, name) },
108 {"Fontname", ASS_STR, offsetof(ASSStyle, font_name) },
109 {"Fontsize", ASS_INT, offsetof(ASSStyle, font_size) },
110 {"PrimaryColour", ASS_COLOR, offsetof(ASSStyle, primary_color) },
111 {"SecondaryColour", ASS_COLOR, offsetof(ASSStyle, secondary_color)},
112 {"TertiaryColour", ASS_COLOR, offsetof(ASSStyle, outline_color) },
113 {"BackColour", ASS_COLOR, offsetof(ASSStyle, back_color) },
114 {"Bold", ASS_INT, offsetof(ASSStyle, bold) },
115 {"Italic", ASS_INT, offsetof(ASSStyle, italic) },
116 {"BorderStyle", ASS_INT, offsetof(ASSStyle, border_style) },
117 {"Outline", ASS_FLT, offsetof(ASSStyle, outline) },
118 {"Shadow", ASS_FLT, offsetof(ASSStyle, shadow) },
119 {"Alignment", ASS_ALGN, offsetof(ASSStyle, alignment) },
120 {"MarginL", ASS_INT, offsetof(ASSStyle, margin_l) },
121 {"MarginR", ASS_INT, offsetof(ASSStyle, margin_r) },
122 {"MarginV", ASS_INT, offsetof(ASSStyle, margin_v) },
123 {"AlphaLevel", ASS_INT, offsetof(ASSStyle, alpha_level) },
124 {"Encoding", ASS_INT, offsetof(ASSStyle, encoding) },
125 {0},
126 }
127 },
128 { .section = "Events",
129 .format_header = "Format",
130 .fields_header = "Dialogue",
131 .size = sizeof(ASSDialog),
132 .offset = offsetof(ASS, dialogs),
133 .offset_count = offsetof(ASS, dialogs_count),
134 .fields = {{"Layer", ASS_INT, offsetof(ASSDialog, layer) },
135 {"Start", ASS_TIMESTAMP, offsetof(ASSDialog, start) },
136 {"End", ASS_TIMESTAMP, offsetof(ASSDialog, end) },
137 {"Style", ASS_STR, offsetof(ASSDialog, style) },
138 {"Name", ASS_STR, offsetof(ASSDialog, name) },
139 {"MarginL", ASS_INT, offsetof(ASSDialog, margin_l)},
140 {"MarginR", ASS_INT, offsetof(ASSDialog, margin_r)},
141 {"MarginV", ASS_INT, offsetof(ASSDialog, margin_v)},
142 {"Effect", ASS_STR, offsetof(ASSDialog, effect) },
143 {"Text", ASS_STR, offsetof(ASSDialog, text) },
144 {0},
145 }
146 },
147 };
148
149
150 typedef int (*ASSConvertFunc)(void *dest, const char *buf, int len);
151
152 1061 static int convert_str(void *dest, const char *buf, int len)
153 {
154 1061 char *str = av_malloc(len + 1);
155
1/2
✓ Branch 0 taken 1061 times.
✗ Branch 1 not taken.
1061 if (str) {
156 1061 memcpy(str, buf, len);
157 1061 str[len] = 0;
158
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1061 times.
1061 if (*(void **)dest)
159 av_free(*(void **)dest);
160 1061 *(char **)dest = str;
161 }
162 1061 return !str;
163 }
164 1428 static int convert_int(void *dest, const char *buf, int len)
165 {
166 1428 return sscanf(buf, "%d", (int *)dest) == 1;
167 }
168 55 static int convert_flt(void *dest, const char *buf, int len)
169 {
170 55 return sscanf(buf, "%f", (float *)dest) == 1;
171 }
172 55 static int convert_color(void *dest, const char *buf, int len)
173 {
174
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 44 times.
66 return sscanf(buf, "&H%8x", (int *)dest) == 1 ||
175
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 sscanf(buf, "%d", (int *)dest) == 1;
176 }
177 static int convert_timestamp(void *dest, const char *buf, int len)
178 {
179 int c, h, m, s, cs;
180 if ((c = sscanf(buf, "%d:%02d:%02d.%02d", &h, &m, &s, &cs)) == 4)
181 *(int *)dest = 360000*h + 6000*m + 100*s + cs;
182 return c == 4;
183 }
184 static int convert_alignment(void *dest, const char *buf, int len)
185 {
186 int a;
187 if (sscanf(buf, "%d", &a) == 1) {
188 /* convert V4 Style alignment to V4+ Style */
189 *(int *)dest = a + ((a&4) >> 1) - 5*!!(a&8);
190 return 1;
191 }
192 return 0;
193 }
194
195 static const ASSConvertFunc convert_func[] = {
196 [ASS_STR] = convert_str,
197 [ASS_INT] = convert_int,
198 [ASS_FLT] = convert_flt,
199 [ASS_COLOR] = convert_color,
200 [ASS_TIMESTAMP] = convert_timestamp,
201 [ASS_ALGN] = convert_alignment,
202 };
203
204
205 struct ASSSplitContext {
206 ASS ass;
207 int current_section;
208 int field_number[FF_ARRAY_ELEMS(ass_sections)];
209 int *field_order[FF_ARRAY_ELEMS(ass_sections)];
210 };
211
212
213 11 static uint8_t *realloc_section_array(ASSSplitContext *ctx)
214 {
215 11 const ASSSection *section = &ass_sections[ctx->current_section];
216 11 int *count = (int *)((uint8_t *)&ctx->ass + section->offset_count);
217 11 void **section_ptr = (void **)((uint8_t *)&ctx->ass + section->offset);
218 11 uint8_t *tmp = av_realloc_array(*section_ptr, (*count+1), section->size);
219
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (!tmp)
220 return NULL;
221 11 *section_ptr = tmp;
222 11 tmp += *count * section->size;
223 11 memset(tmp, 0, section->size);
224 11 (*count)++;
225 11 return tmp;
226 }
227
228 649 static inline int is_eol(char buf)
229 {
230
4/6
✓ Branch 0 taken 649 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 616 times.
✓ Branch 3 taken 33 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 616 times.
649 return buf == '\r' || buf == '\n' || buf == 0;
231 }
232
233 3578 static inline const char *skip_space(const char *buf)
234 {
235
2/2
✓ Branch 0 taken 407 times.
✓ Branch 1 taken 3578 times.
3985 while (*buf == ' ')
236 407 buf++;
237 3578 return buf;
238 }
239
240 static int *get_default_field_orders(const ASSSection *section, int *number)
241 {
242 int i;
243 int *order = av_malloc_array(FF_ARRAY_ELEMS(section->fields), sizeof(*order));
244
245 if (!order)
246 return NULL;
247 for (i = 0; section->fields[i].name; i++)
248 order[i] = i;
249 *number = i;
250 while (i < FF_ARRAY_ELEMS(section->fields))
251 order[i++] = -1;
252 return order;
253 }
254
255 33 static const char *ass_split_section(ASSSplitContext *ctx, const char *buf)
256 {
257 33 const ASSSection *section = &ass_sections[ctx->current_section];
258 33 int *number = &ctx->field_number[ctx->current_section];
259 33 int *order = ctx->field_order[ctx->current_section];
260 int i, len;
261
262
3/4
✓ Branch 0 taken 154 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 143 times.
✓ Branch 3 taken 11 times.
154 while (buf && *buf) {
263
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 121 times.
143 if (buf[0] == '[') {
264 22 ctx->current_section = -1;
265 22 break;
266 }
267
3/6
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 110 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
121 if (buf[0] == ';' || (buf[0] == '!' && buf[1] == ':'))
268 11 goto next_line; // skip comments
269
270 110 len = strcspn(buf, ":\r\n");
271
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 22 times.
110 if (buf[len] == ':' &&
272
4/4
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 55 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 11 times.
88 (!section->fields_header || strncmp(buf, section->fields_header, len))) {
273
2/2
✓ Branch 0 taken 308 times.
✓ Branch 1 taken 77 times.
385 for (i = 0; i < FF_ARRAY_ELEMS(ass_sections); i++) {
274
2/2
✓ Branch 0 taken 231 times.
✓ Branch 1 taken 77 times.
308 if (ass_sections[i].fields_header &&
275
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 231 times.
231 !strncmp(buf, ass_sections[i].fields_header, len)) {
276 ctx->current_section = i;
277 section = &ass_sections[ctx->current_section];
278 number = &ctx->field_number[ctx->current_section];
279 order = ctx->field_order[ctx->current_section];
280 break;
281 }
282 }
283 }
284
4/4
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 22 times.
110 if (section->format_header && !order) {
285 22 len = strlen(section->format_header);
286
2/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
22 if (!strncmp(buf, section->format_header, len) && buf[len] == ':') {
287 22 buf += len + 1;
288
2/2
✓ Branch 1 taken 363 times.
✓ Branch 2 taken 22 times.
385 while (!is_eol(*buf)) {
289 363 buf = skip_space(buf);
290 363 len = strcspn(buf, ", \r\n");
291
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 363 times.
363 if (av_reallocp_array(&order, (*number + 1), sizeof(*order)) != 0)
292 return NULL;
293
294 363 order[*number] = -1;
295
1/2
✓ Branch 0 taken 3520 times.
✗ Branch 1 not taken.
3520 for (i=0; section->fields[i].name; i++)
296
2/2
✓ Branch 0 taken 363 times.
✓ Branch 1 taken 3157 times.
3520 if (!strncmp(buf, section->fields[i].name, len)) {
297 363 order[*number] = i;
298 363 break;
299 }
300 363 (*number)++;
301 363 buf = skip_space(buf + len + (buf[len] == ','));
302 }
303 22 ctx->field_order[ctx->current_section] = order;
304 22 goto next_line;
305 }
306 }
307
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 66 times.
88 if (section->fields_header) {
308 22 len = strlen(section->fields_header);
309
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
22 if (!strncmp(buf, section->fields_header, len) && buf[len] == ':') {
310 11 uint8_t *ptr, *struct_ptr = realloc_section_array(ctx);
311
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (!struct_ptr) return NULL;
312
313 /* No format header line found so far, assume default */
314
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (!order) {
315 order = get_default_field_orders(section, number);
316 if (!order)
317 return NULL;
318 ctx->field_order[ctx->current_section] = order;
319 }
320
321 11 buf += len + 1;
322
3/4
✓ Branch 1 taken 253 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 253 times.
✗ Branch 4 not taken.
264 for (i=0; !is_eol(*buf) && i < *number; i++) {
323 253 int last = i == *number - 1;
324 253 buf = skip_space(buf);
325
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 242 times.
253 len = strcspn(buf, last ? "\r\n" : ",\r\n");
326
1/2
✓ Branch 0 taken 253 times.
✗ Branch 1 not taken.
253 if (order[i] >= 0) {
327 253 ASSFieldType type = section->fields[order[i]].type;
328 253 ptr = struct_ptr + section->fields[order[i]].offset;
329 253 convert_func[type](ptr, buf, len);
330 }
331 253 buf += len;
332
3/4
✓ Branch 0 taken 242 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 242 times.
✗ Branch 3 not taken.
253 if (!last && *buf) buf++;
333 253 buf = skip_space(buf);
334 }
335 }
336 } else {
337 66 len = strcspn(buf, ":\r\n");
338
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 55 times.
66 if (buf[len] == ':') {
339
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 22 times.
220 for (i=0; section->fields[i].name; i++)
340
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 165 times.
198 if (!strncmp(buf, section->fields[i].name, len)) {
341 33 ASSFieldType type = section->fields[i].type;
342 33 uint8_t *ptr = (uint8_t *)&ctx->ass + section->offset;
343 33 ptr += section->fields[i].offset;
344 33 buf = skip_space(buf + len + 1);
345 33 convert_func[type](ptr, buf, strcspn(buf, "\r\n"));
346 33 break;
347 }
348 }
349 }
350 33 next_line:
351 121 buf += strcspn(buf, "\n");
352 121 buf += !!*buf;
353 }
354 33 return buf;
355 }
356
357 11 static int ass_split(ASSSplitContext *ctx, const char *buf)
358 {
359 char c, section[16];
360 int i;
361
362
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (ctx->current_section >= 0)
363 buf = ass_split_section(ctx, buf);
364
365
3/4
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 11 times.
44 while (buf && *buf) {
366
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 if (sscanf(buf, "[%15[0-9A-Za-z+ ]]%c", section, &c) == 2) {
367 33 buf += strcspn(buf, "\n");
368 33 buf += !!*buf;
369
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 33 times.
165 for (i=0; i<FF_ARRAY_ELEMS(ass_sections); i++)
370
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 99 times.
132 if (!strcmp(section, ass_sections[i].section)) {
371 33 ctx->current_section = i;
372 33 buf = ass_split_section(ctx, buf);
373 }
374 } else {
375 buf += strcspn(buf, "\n");
376 buf += !!*buf;
377 }
378 }
379
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 return buf ? 0 : AVERROR_INVALIDDATA;
380 }
381
382 11 ASSSplitContext *ff_ass_split(const char *buf)
383 {
384 11 ASSSplitContext *ctx = av_mallocz(sizeof(*ctx));
385
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (!ctx)
386 return NULL;
387
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
11 if (buf && !strncmp(buf, "\xef\xbb\xbf", 3)) // Skip UTF-8 BOM header
388 buf += 3;
389 11 ctx->current_section = -1;
390
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
11 if (ass_split(ctx, buf) < 0) {
391 ff_ass_split_free(ctx);
392 return NULL;
393 }
394 11 return ctx;
395 }
396
397 44 static void free_section(ASSSplitContext *ctx, const ASSSection *section)
398 {
399 44 uint8_t *ptr = (uint8_t *)&ctx->ass + section->offset;
400 44 int i, j, *count, c = 1;
401
402
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 11 times.
44 if (section->format_header) {
403 33 ptr = *(void **)ptr;
404 33 count = (int *)((uint8_t *)&ctx->ass + section->offset_count);
405 } else
406 11 count = &c;
407
408
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 22 times.
44 if (ptr)
409
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 22 times.
44 for (i=0; i<*count; i++, ptr += section->size)
410
2/2
✓ Branch 0 taken 308 times.
✓ Branch 1 taken 22 times.
330 for (j=0; section->fields[j].name; j++) {
411 308 const ASSFields *field = &section->fields[j];
412
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 264 times.
308 if (field->type == ASS_STR)
413 44 av_freep(ptr + field->offset);
414 }
415 44 *count = 0;
416
417
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 11 times.
44 if (section->format_header)
418 33 av_freep((uint8_t *)&ctx->ass + section->offset);
419 44 }
420
421 257 void ff_ass_free_dialog(ASSDialog **dialogp)
422 {
423 257 ASSDialog *dialog = *dialogp;
424
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 257 times.
257 if (!dialog)
425 return;
426 257 av_freep(&dialog->style);
427 257 av_freep(&dialog->name);
428 257 av_freep(&dialog->effect);
429 257 av_freep(&dialog->text);
430 257 av_freep(dialogp);
431 }
432
433 257 ASSDialog *ff_ass_split_dialog(ASSSplitContext *ctx, const char *buf)
434 {
435 int i;
436 static const ASSFields fields[] = {
437 {"ReadOrder", ASS_INT, offsetof(ASSDialog, readorder)},
438 {"Layer", ASS_INT, offsetof(ASSDialog, layer) },
439 {"Style", ASS_STR, offsetof(ASSDialog, style) },
440 {"Name", ASS_STR, offsetof(ASSDialog, name) },
441 {"MarginL", ASS_INT, offsetof(ASSDialog, margin_l) },
442 {"MarginR", ASS_INT, offsetof(ASSDialog, margin_r) },
443 {"MarginV", ASS_INT, offsetof(ASSDialog, margin_v) },
444 {"Effect", ASS_STR, offsetof(ASSDialog, effect) },
445 {"Text", ASS_STR, offsetof(ASSDialog, text) },
446 };
447
448 257 ASSDialog *dialog = av_mallocz(sizeof(*dialog));
449
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 257 times.
257 if (!dialog)
450 return NULL;
451
452
2/2
✓ Branch 0 taken 2313 times.
✓ Branch 1 taken 257 times.
2570 for (i = 0; i < FF_ARRAY_ELEMS(fields); i++) {
453 size_t len;
454 2313 const int last = i == FF_ARRAY_ELEMS(fields) - 1;
455 2313 const ASSFieldType type = fields[i].type;
456 2313 uint8_t *ptr = (uint8_t *)dialog + fields[i].offset;
457 2313 buf = skip_space(buf);
458
2/2
✓ Branch 0 taken 257 times.
✓ Branch 1 taken 2056 times.
2313 len = last ? strlen(buf) : strcspn(buf, ",");
459
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2313 times.
2313 if (len >= INT_MAX) {
460 ff_ass_free_dialog(&dialog);
461 return NULL;
462 }
463 2313 convert_func[type](ptr, buf, len);
464 2313 buf += len;
465
2/2
✓ Branch 0 taken 2056 times.
✓ Branch 1 taken 257 times.
2313 if (*buf) buf++;
466 }
467 257 return dialog;
468 }
469
470 11 void ff_ass_split_free(ASSSplitContext *ctx)
471 {
472
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (ctx) {
473 int i;
474
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 11 times.
55 for (i=0; i<FF_ARRAY_ELEMS(ass_sections); i++) {
475 44 free_section(ctx, &ass_sections[i]);
476 44 av_freep(&(ctx->field_order[i]));
477 }
478 11 av_free(ctx);
479 }
480 11 }
481
482
483 257 int ff_ass_split_override_codes(const ASSCodesCallbacks *callbacks, void *priv,
484 const char *buf)
485 {
486 257 const char *text = NULL;
487 char new_line[2];
488 257 int text_len = 0;
489
490
3/4
✓ Branch 0 taken 19198 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18941 times.
✓ Branch 3 taken 257 times.
19198 while (buf && *buf) {
491
3/4
✓ Branch 0 taken 17905 times.
✓ Branch 1 taken 1036 times.
✓ Branch 2 taken 17905 times.
✗ Branch 3 not taken.
18941 if (text && callbacks->text &&
492
2/2
✓ Branch 0 taken 17662 times.
✓ Branch 1 taken 243 times.
17905 (sscanf(buf, "\\%1[nN]", new_line) == 1 ||
493
2/2
✓ Branch 0 taken 164 times.
✓ Branch 1 taken 17498 times.
17662 !strncmp(buf, "{\\", 2))) {
494 407 callbacks->text(priv, text, text_len);
495 407 text = NULL;
496 }
497
2/2
✓ Branch 0 taken 338 times.
✓ Branch 1 taken 18603 times.
18941 if (sscanf(buf, "\\%1[nN]", new_line) == 1) {
498
1/2
✓ Branch 0 taken 338 times.
✗ Branch 1 not taken.
338 if (callbacks->new_line)
499 338 callbacks->new_line(priv, new_line[0] == 'N');
500 338 buf += 2;
501
2/2
✓ Branch 0 taken 478 times.
✓ Branch 1 taken 18125 times.
18603 } else if (!strncmp(buf, "{\\", 2)) {
502 478 buf++;
503
2/2
✓ Branch 0 taken 478 times.
✓ Branch 1 taken 478 times.
956 while (*buf == '\\') {
504 478 char style[2], c[2], sep[2], c_num[2] = "0", tmp[128] = {0};
505 478 unsigned int color = 0xFFFFFFFF;
506 478 int len, size = -1, an = -1, alpha = -1;
507 478 int x1, y1, x2, y2, t1 = -1, t2 = -1;
508
2/2
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 304 times.
478 if (sscanf(buf, "\\%1[bisu]%1[01\\}]%n", style, c, &len) > 1) {
509
3/4
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 84 times.
✓ Branch 2 taken 90 times.
✗ Branch 3 not taken.
174 int close = c[0] == '0' ? 1 : c[0] == '1' ? 0 : -1;
510 174 len += close != -1;
511
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 112 times.
174 if (callbacks->style)
512 62 callbacks->style(priv, style[0], close);
513
2/2
✓ Branch 0 taken 269 times.
✓ Branch 1 taken 35 times.
304 } else if (sscanf(buf, "\\c%1[\\}]%n", sep, &len) > 0 ||
514
2/2
✓ Branch 0 taken 224 times.
✓ Branch 1 taken 45 times.
269 sscanf(buf, "\\c&H%X&%1[\\}]%n", &color, sep, &len) > 1 ||
515
1/2
✓ Branch 0 taken 224 times.
✗ Branch 1 not taken.
224 sscanf(buf, "\\%1[1234]c%1[\\}]%n", c_num, sep, &len) > 1 ||
516
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 224 times.
224 sscanf(buf, "\\%1[1234]c&H%X&%1[\\}]%n", c_num, &color, sep, &len) > 2) {
517
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 80 times.
80 if (callbacks->color)
518 callbacks->color(priv, color, c_num[0] - '0');
519
1/2
✓ Branch 0 taken 224 times.
✗ Branch 1 not taken.
224 } else if (sscanf(buf, "\\alpha%1[\\}]%n", sep, &len) > 0 ||
520
1/2
✓ Branch 0 taken 224 times.
✗ Branch 1 not taken.
224 sscanf(buf, "\\alpha&H%2X&%1[\\}]%n", &alpha, sep, &len) > 1 ||
521
1/2
✓ Branch 0 taken 224 times.
✗ Branch 1 not taken.
224 sscanf(buf, "\\%1[1234]a%1[\\}]%n", c_num, sep, &len) > 1 ||
522
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 224 times.
224 sscanf(buf, "\\%1[1234]a&H%2X&%1[\\}]%n", c_num, &alpha, sep, &len) > 2) {
523 if (callbacks->alpha)
524 callbacks->alpha(priv, alpha, c_num[0] - '0');
525
2/2
✓ Branch 0 taken 219 times.
✓ Branch 1 taken 5 times.
224 } else if (sscanf(buf, "\\fn%1[\\}]%n", sep, &len) > 0 ||
526
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 214 times.
219 sscanf(buf, "\\fn%127[^\\}]%1[\\}]%n", tmp, sep, &len) > 1) {
527
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (callbacks->font_name)
528 callbacks->font_name(priv, tmp[0] ? tmp : NULL);
529
2/2
✓ Branch 0 taken 179 times.
✓ Branch 1 taken 35 times.
214 } else if (sscanf(buf, "\\fs%1[\\}]%n", sep, &len) > 0 ||
530
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 134 times.
179 sscanf(buf, "\\fs%u%1[\\}]%n", &size, sep, &len) > 1) {
531
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 80 times.
80 if (callbacks->font_size)
532 callbacks->font_size(priv, size);
533
1/2
✓ Branch 0 taken 134 times.
✗ Branch 1 not taken.
134 } else if (sscanf(buf, "\\a%1[\\}]%n", sep, &len) > 0 ||
534
1/2
✓ Branch 0 taken 134 times.
✗ Branch 1 not taken.
134 sscanf(buf, "\\a%2u%1[\\}]%n", &an, sep, &len) > 1 ||
535
1/2
✓ Branch 0 taken 134 times.
✗ Branch 1 not taken.
134 sscanf(buf, "\\an%1[\\}]%n", sep, &len) > 0 ||
536
2/2
✓ Branch 0 taken 97 times.
✓ Branch 1 taken 37 times.
134 sscanf(buf, "\\an%1u%1[\\}]%n", &an, sep, &len) > 1) {
537
2/4
✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 97 times.
97 if (an != -1 && buf[2] != 'n')
538 an = (an&3) + (an&4 ? 6 : an&8 ? 3 : 0);
539
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 65 times.
97 if (callbacks->alignment)
540 32 callbacks->alignment(priv, an);
541
1/2
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
37 } else if (sscanf(buf, "\\r%1[\\}]%n", sep, &len) > 0 ||
542
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 sscanf(buf, "\\r%127[^\\}]%1[\\}]%n", tmp, sep, &len) > 1) {
543 if (callbacks->cancel_overrides)
544 callbacks->cancel_overrides(priv, tmp);
545
1/2
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
37 } else if (sscanf(buf, "\\move(%d,%d,%d,%d)%1[\\}]%n", &x1, &y1, &x2, &y2, sep, &len) > 4 ||
546
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 sscanf(buf, "\\move(%d,%d,%d,%d,%d,%d)%1[\\}]%n", &x1, &y1, &x2, &y2, &t1, &t2, sep, &len) > 6) {
547 if (callbacks->move)
548 callbacks->move(priv, x1, y1, x2, y2, t1, t2);
549
1/2
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
37 } else if (sscanf(buf, "\\pos(%d,%d)%1[\\}]%n", &x1, &y1, sep, &len) > 2) {
550
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 5 times.
37 if (callbacks->move)
551 32 callbacks->move(priv, x1, y1, x1, y1, -1, -1);
552 } else if (sscanf(buf, "\\org(%d,%d)%1[\\}]%n", &x1, &y1, sep, &len) > 2) {
553 if (callbacks->origin)
554 callbacks->origin(priv, x1, y1);
555 } else {
556 len = strcspn(buf+1, "\\}") + 2; /* skip unknown code */
557 }
558 478 buf += len - 1;
559 }
560
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 478 times.
478 if (*buf++ != '}')
561 return AVERROR_INVALIDDATA;
562 } else {
563
2/2
✓ Branch 0 taken 627 times.
✓ Branch 1 taken 17498 times.
18125 if (!text) {
564 627 text = buf;
565 627 text_len = 1;
566 } else
567 17498 text_len++;
568 18125 buf++;
569 }
570 }
571
3/4
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 37 times.
✓ Branch 2 taken 220 times.
✗ Branch 3 not taken.
257 if (text && callbacks->text)
572 220 callbacks->text(priv, text, text_len);
573
2/2
✓ Branch 0 taken 109 times.
✓ Branch 1 taken 148 times.
257 if (callbacks->end)
574 109 callbacks->end(priv);
575 257 return 0;
576 }
577
578 110 ASSStyle *ff_ass_style_get(ASSSplitContext *ctx, const char *style)
579 {
580 110 ASS *ass = &ctx->ass;
581 int i;
582
583
2/4
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 110 times.
110 if (!style || !*style)
584 style = "Default";
585
1/2
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
110 for (i=0; i<ass->styles_count; i++)
586
2/4
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 110 times.
✗ Branch 3 not taken.
110 if (ass->styles[i].name && !strcmp(ass->styles[i].name, style))
587 110 return ass->styles + i;
588 return NULL;
589 }
590