FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/ass_split.c
Date: 2022-11-28 23:49:43
Exec Total Coverage
Lines: 233 292 79.8%
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 991 static int convert_str(void *dest, const char *buf, int len)
153 {
154 991 char *str = av_malloc(len + 1);
155
1/2
✓ Branch 0 taken 991 times.
✗ Branch 1 not taken.
991 if (str) {
156 991 memcpy(str, buf, len);
157 991 str[len] = 0;
158
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 991 times.
991 if (*(void **)dest)
159 av_free(*(void **)dest);
160 991 *(char **)dest = str;
161 }
162 991 return !str;
163 }
164 1322 static int convert_int(void *dest, const char *buf, int len)
165 {
166 1322 return sscanf(buf, "%d", (int *)dest) == 1;
167 }
168 45 static int convert_flt(void *dest, const char *buf, int len)
169 {
170 45 return sscanf(buf, "%f", (float *)dest) == 1;
171 }
172 45 static int convert_color(void *dest, const char *buf, int len)
173 {
174
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 36 times.
54 return sscanf(buf, "&H%8x", (int *)dest) == 1 ||
175
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 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 9 static uint8_t *realloc_section_array(ASSSplitContext *ctx)
214 {
215 9 const ASSSection *section = &ass_sections[ctx->current_section];
216 9 int *count = (int *)((uint8_t *)&ctx->ass + section->offset_count);
217 9 void **section_ptr = (void **)((uint8_t *)&ctx->ass + section->offset);
218 9 uint8_t *tmp = av_realloc_array(*section_ptr, (*count+1), section->size);
219
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (!tmp)
220 return NULL;
221 9 *section_ptr = tmp;
222 9 tmp += *count * section->size;
223 9 memset(tmp, 0, section->size);
224 9 (*count)++;
225 9 return tmp;
226 }
227
228 531 static inline int is_eol(char buf)
229 {
230
4/6
✓ Branch 0 taken 504 times.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 504 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 504 times.
531 return buf == '\r' || buf == '\n' || buf == 0;
231 }
232
233 3204 static inline const char *skip_space(const char *buf)
234 {
235
2/2
✓ Branch 0 taken 333 times.
✓ Branch 1 taken 3204 times.
3537 while (*buf == ' ')
236 333 buf++;
237 3204 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 27 static const char *ass_split_section(ASSSplitContext *ctx, const char *buf)
256 {
257 27 const ASSSection *section = &ass_sections[ctx->current_section];
258 27 int *number = &ctx->field_number[ctx->current_section];
259 27 int *order = ctx->field_order[ctx->current_section];
260 int i, len;
261
262
3/4
✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 108 times.
✓ Branch 3 taken 9 times.
117 while (buf && *buf) {
263
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 90 times.
108 if (buf[0] == '[') {
264 18 ctx->current_section = -1;
265 18 break;
266 }
267
3/6
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 81 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
90 if (buf[0] == ';' || (buf[0] == '!' && buf[1] == ':'))
268 9 goto next_line; // skip comments
269
270 81 len = strcspn(buf, ":\r\n");
271
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 18 times.
81 if (buf[len] == ':' &&
272
4/4
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 9 times.
63 (!section->fields_header || strncmp(buf, section->fields_header, len))) {
273
2/2
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 54 times.
270 for (i = 0; i < FF_ARRAY_ELEMS(ass_sections); i++) {
274
2/2
✓ Branch 0 taken 162 times.
✓ Branch 1 taken 54 times.
216 if (ass_sections[i].fields_header &&
275
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 162 times.
162 !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 36 times.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 18 times.
81 if (section->format_header && !order) {
285 18 len = strlen(section->format_header);
286
2/4
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
18 if (!strncmp(buf, section->format_header, len) && buf[len] == ':') {
287 18 buf += len + 1;
288
2/2
✓ Branch 1 taken 297 times.
✓ Branch 2 taken 18 times.
315 while (!is_eol(*buf)) {
289 297 buf = skip_space(buf);
290 297 len = strcspn(buf, ", \r\n");
291
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 297 times.
297 if (av_reallocp_array(&order, (*number + 1), sizeof(*order)) != 0)
292 return NULL;
293
294 297 order[*number] = -1;
295
1/2
✓ Branch 0 taken 2880 times.
✗ Branch 1 not taken.
2880 for (i=0; section->fields[i].name; i++)
296
2/2
✓ Branch 0 taken 297 times.
✓ Branch 1 taken 2583 times.
2880 if (!strncmp(buf, section->fields[i].name, len)) {
297 297 order[*number] = i;
298 297 break;
299 }
300 297 (*number)++;
301 297 buf = skip_space(buf + len + (buf[len] == ','));
302 }
303 18 ctx->field_order[ctx->current_section] = order;
304 18 goto next_line;
305 }
306 }
307
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 45 times.
63 if (section->fields_header) {
308 18 len = strlen(section->fields_header);
309
3/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
18 if (!strncmp(buf, section->fields_header, len) && buf[len] == ':') {
310 9 uint8_t *ptr, *struct_ptr = realloc_section_array(ctx);
311
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 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 9 times.
9 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 9 buf += len + 1;
322
3/4
✓ Branch 1 taken 207 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 207 times.
✗ Branch 4 not taken.
216 for (i=0; !is_eol(*buf) && i < *number; i++) {
323 207 int last = i == *number - 1;
324 207 buf = skip_space(buf);
325
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 198 times.
207 len = strcspn(buf, last ? "\r\n" : ",\r\n");
326
1/2
✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
207 if (order[i] >= 0) {
327 207 ASSFieldType type = section->fields[order[i]].type;
328 207 ptr = struct_ptr + section->fields[order[i]].offset;
329 207 convert_func[type](ptr, buf, len);
330 }
331 207 buf += len;
332
3/4
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 198 times.
✗ Branch 3 not taken.
207 if (!last && *buf) buf++;
333 207 buf = skip_space(buf);
334 }
335 }
336 } else {
337 45 len = strcspn(buf, ":\r\n");
338
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 36 times.
45 if (buf[len] == ':') {
339
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 9 times.
126 for (i=0; section->fields[i].name; i++)
340
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 90 times.
117 if (!strncmp(buf, section->fields[i].name, len)) {
341 27 ASSFieldType type = section->fields[i].type;
342 27 uint8_t *ptr = (uint8_t *)&ctx->ass + section->offset;
343 27 ptr += section->fields[i].offset;
344 27 buf = skip_space(buf + len + 1);
345 27 convert_func[type](ptr, buf, strcspn(buf, "\r\n"));
346 27 break;
347 }
348 }
349 }
350 18 next_line:
351 90 buf += strcspn(buf, "\n");
352 90 buf += !!*buf;
353 }
354 27 return buf;
355 }
356
357 9 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 9 times.
9 if (ctx->current_section >= 0)
363 buf = ass_split_section(ctx, buf);
364
365
3/4
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 9 times.
36 while (buf && *buf) {
366
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 if (sscanf(buf, "[%15[0-9A-Za-z+ ]]%c", section, &c) == 2) {
367 27 buf += strcspn(buf, "\n");
368 27 buf += !!*buf;
369
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 27 times.
135 for (i=0; i<FF_ARRAY_ELEMS(ass_sections); i++)
370
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 81 times.
108 if (!strcmp(section, ass_sections[i].section)) {
371 27 ctx->current_section = i;
372 27 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 9 times.
✗ Branch 1 not taken.
9 return buf ? 0 : AVERROR_INVALIDDATA;
380 }
381
382 9 ASSSplitContext *ff_ass_split(const char *buf)
383 {
384 9 ASSSplitContext *ctx = av_mallocz(sizeof(*ctx));
385
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (!ctx)
386 return NULL;
387
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
9 if (buf && !strncmp(buf, "\xef\xbb\xbf", 3)) // Skip UTF-8 BOM header
388 buf += 3;
389 9 ctx->current_section = -1;
390
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
9 if (ass_split(ctx, buf) < 0) {
391 ff_ass_split_free(ctx);
392 return NULL;
393 }
394 9 return ctx;
395 }
396
397 36 static void free_section(ASSSplitContext *ctx, const ASSSection *section)
398 {
399 36 uint8_t *ptr = (uint8_t *)&ctx->ass + section->offset;
400 36 int i, j, *count, c = 1;
401
402
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 9 times.
36 if (section->format_header) {
403 27 ptr = *(void **)ptr;
404 27 count = (int *)((uint8_t *)&ctx->ass + section->offset_count);
405 } else
406 9 count = &c;
407
408
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 18 times.
36 if (ptr)
409
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 18 times.
36 for (i=0; i<*count; i++, ptr += section->size)
410
2/2
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 18 times.
270 for (j=0; section->fields[j].name; j++) {
411 252 const ASSFields *field = &section->fields[j];
412
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 216 times.
252 if (field->type == ASS_STR)
413 36 av_freep(ptr + field->offset);
414 }
415 36 *count = 0;
416
417
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 9 times.
36 if (section->format_header)
418 27 av_freep((uint8_t *)&ctx->ass + section->offset);
419 36 }
420
421 241 void ff_ass_free_dialog(ASSDialog **dialogp)
422 {
423 241 ASSDialog *dialog = *dialogp;
424
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 241 times.
241 if (!dialog)
425 return;
426 241 av_freep(&dialog->style);
427 241 av_freep(&dialog->name);
428 241 av_freep(&dialog->effect);
429 241 av_freep(&dialog->text);
430 241 av_freep(dialogp);
431 }
432
433 241 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 241 ASSDialog *dialog = av_mallocz(sizeof(*dialog));
449
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 241 times.
241 if (!dialog)
450 return NULL;
451
452
2/2
✓ Branch 0 taken 2169 times.
✓ Branch 1 taken 241 times.
2410 for (i = 0; i < FF_ARRAY_ELEMS(fields); i++) {
453 size_t len;
454 2169 const int last = i == FF_ARRAY_ELEMS(fields) - 1;
455 2169 const ASSFieldType type = fields[i].type;
456 2169 uint8_t *ptr = (uint8_t *)dialog + fields[i].offset;
457 2169 buf = skip_space(buf);
458
2/2
✓ Branch 0 taken 241 times.
✓ Branch 1 taken 1928 times.
2169 len = last ? strlen(buf) : strcspn(buf, ",");
459
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2169 times.
2169 if (len >= INT_MAX) {
460 ff_ass_free_dialog(&dialog);
461 return NULL;
462 }
463 2169 convert_func[type](ptr, buf, len);
464 2169 buf += len;
465
2/2
✓ Branch 0 taken 1928 times.
✓ Branch 1 taken 241 times.
2169 if (*buf) buf++;
466 }
467 241 return dialog;
468 }
469
470 9 void ff_ass_split_free(ASSSplitContext *ctx)
471 {
472
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (ctx) {
473 int i;
474
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 9 times.
45 for (i=0; i<FF_ARRAY_ELEMS(ass_sections); i++) {
475 36 free_section(ctx, &ass_sections[i]);
476 36 av_freep(&(ctx->field_order[i]));
477 }
478 9 av_free(ctx);
479 }
480 9 }
481
482
483 241 int ff_ass_split_override_codes(const ASSCodesCallbacks *callbacks, void *priv,
484 const char *buf)
485 {
486 241 const char *text = NULL;
487 char new_line[2];
488 241 int text_len = 0;
489
490
3/4
✓ Branch 0 taken 18688 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18447 times.
✓ Branch 3 taken 241 times.
18688 while (buf && *buf) {
491
3/4
✓ Branch 0 taken 17501 times.
✓ Branch 1 taken 946 times.
✓ Branch 2 taken 17501 times.
✗ Branch 3 not taken.
18447 if (text && callbacks->text &&
492
2/2
✓ Branch 0 taken 17264 times.
✓ Branch 1 taken 237 times.
17501 (sscanf(buf, "\\%1[nN]", new_line) == 1 ||
493
2/2
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 17124 times.
17264 !strncmp(buf, "{\\", 2))) {
494 377 callbacks->text(priv, text, text_len);
495 377 text = NULL;
496 }
497
2/2
✓ Branch 0 taken 332 times.
✓ Branch 1 taken 18115 times.
18447 if (sscanf(buf, "\\%1[nN]", new_line) == 1) {
498
1/2
✓ Branch 0 taken 332 times.
✗ Branch 1 not taken.
332 if (callbacks->new_line)
499 332 callbacks->new_line(priv, new_line[0] == 'N');
500 332 buf += 2;
501
2/2
✓ Branch 0 taken 410 times.
✓ Branch 1 taken 17705 times.
18115 } else if (!strncmp(buf, "{\\", 2)) {
502 410 buf++;
503
2/2
✓ Branch 0 taken 410 times.
✓ Branch 1 taken 410 times.
820 while (*buf == '\\') {
504 410 char style[2], c[2], sep[2], c_num[2] = "0", tmp[128] = {0};
505 410 unsigned int color = 0xFFFFFFFF;
506 410 int len, size = -1, an = -1, alpha = -1;
507 410 int x1, y1, x2, y2, t1 = -1, t2 = -1;
508
2/2
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 260 times.
410 if (sscanf(buf, "\\%1[bisu]%1[01\\}]%n", style, c, &len) > 1) {
509
3/4
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 74 times.
✓ Branch 2 taken 76 times.
✗ Branch 3 not taken.
150 int close = c[0] == '0' ? 1 : c[0] == '1' ? 0 : -1;
510 150 len += close != -1;
511
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 112 times.
150 if (callbacks->style)
512 38 callbacks->style(priv, style[0], close);
513
2/2
✓ Branch 0 taken 225 times.
✓ Branch 1 taken 35 times.
260 } else if (sscanf(buf, "\\c%1[\\}]%n", sep, &len) > 0 ||
514
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 45 times.
225 sscanf(buf, "\\c&H%X&%1[\\}]%n", &color, sep, &len) > 1 ||
515
1/2
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
180 sscanf(buf, "\\%1[1234]c%1[\\}]%n", c_num, sep, &len) > 1 ||
516
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 180 times.
180 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 180 times.
✗ Branch 1 not taken.
180 } else if (sscanf(buf, "\\alpha%1[\\}]%n", sep, &len) > 0 ||
520
1/2
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
180 sscanf(buf, "\\alpha&H%2X&%1[\\}]%n", &alpha, sep, &len) > 1 ||
521
1/2
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
180 sscanf(buf, "\\%1[1234]a%1[\\}]%n", c_num, sep, &len) > 1 ||
522
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 180 times.
180 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 175 times.
✓ Branch 1 taken 5 times.
180 } else if (sscanf(buf, "\\fn%1[\\}]%n", sep, &len) > 0 ||
526
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 170 times.
175 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 135 times.
✓ Branch 1 taken 35 times.
170 } else if (sscanf(buf, "\\fs%1[\\}]%n", sep, &len) > 0 ||
530
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 90 times.
135 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 90 times.
✗ Branch 1 not taken.
90 } else if (sscanf(buf, "\\a%1[\\}]%n", sep, &len) > 0 ||
534
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 sscanf(buf, "\\a%2u%1[\\}]%n", &an, sep, &len) > 1 ||
535
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 sscanf(buf, "\\an%1[\\}]%n", sep, &len) > 0 ||
536
2/2
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 15 times.
90 sscanf(buf, "\\an%1u%1[\\}]%n", &an, sep, &len) > 1) {
537
2/4
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 75 times.
75 if (an != -1 && buf[2] != 'n')
538 an = (an&3) + (an&4 ? 6 : an&8 ? 3 : 0);
539
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 65 times.
75 if (callbacks->alignment)
540 10 callbacks->alignment(priv, an);
541
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 } else if (sscanf(buf, "\\r%1[\\}]%n", sep, &len) > 0 ||
542
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 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 15 times.
✗ Branch 1 not taken.
15 } 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 15 times.
15 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 15 times.
✗ Branch 1 not taken.
15 } else if (sscanf(buf, "\\pos(%d,%d)%1[\\}]%n", &x1, &y1, sep, &len) > 2) {
550
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 if (callbacks->move)
551 10 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 410 buf += len - 1;
559 }
560
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 410 times.
410 if (*buf++ != '}')
561 return AVERROR_INVALIDDATA;
562 } else {
563
2/2
✓ Branch 0 taken 581 times.
✓ Branch 1 taken 17124 times.
17705 if (!text) {
564 581 text = buf;
565 581 text_len = 1;
566 } else
567 17124 text_len++;
568 17705 buf++;
569 }
570 }
571
3/4
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 37 times.
✓ Branch 2 taken 204 times.
✗ Branch 3 not taken.
241 if (text && callbacks->text)
572 204 callbacks->text(priv, text, text_len);
573
2/2
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 148 times.
241 if (callbacks->end)
574 93 callbacks->end(priv);
575 241 return 0;
576 }
577
578 94 ASSStyle *ff_ass_style_get(ASSSplitContext *ctx, const char *style)
579 {
580 94 ASS *ass = &ctx->ass;
581 int i;
582
583
2/4
✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 94 times.
94 if (!style || !*style)
584 style = "Default";
585
1/2
✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
94 for (i=0; i<ass->styles_count; i++)
586
2/4
✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 94 times.
✗ Branch 3 not taken.
94 if (ass->styles[i].name && !strcmp(ass->styles[i].name, style))
587 94 return ass->styles + i;
588 return NULL;
589 }
590