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
23 #include <stddef.h>
24 #include <stdint.h>
25 #include <stdio.h>
26 #include <string.h>
27
32
41
47
57
60 .offset = offsetof(
ASS, script_info),
66 {0},
67 }
68 },
69 { .section = "V4+ Styles",
70 .format_header = "Format",
71 .fields_header = "Style",
74 .offset_count = offsetof(
ASS, styles_count),
98 {0},
99 }
100 },
101 { .section = "V4 Styles",
102 .format_header = "Format",
103 .fields_header = "Style",
106 .offset_count = offsetof(
ASS, styles_count),
125 {0},
126 }
127 },
128 { .section = "Events",
129 .format_header = "Format",
130 .fields_header = "Dialogue",
133 .offset_count = offsetof(
ASS, dialogs_count),
144 {0},
145 }
146 },
147 };
148
149
151
153 {
158 if (*(void **)dest)
160 *(
char **)dest =
str;
161 }
163 }
165 {
166 return sscanf(buf, "%d", (int *)dest) == 1;
167 }
169 {
170 return sscanf(buf, "%f", (float *)dest) == 1;
171 }
173 {
174 return sscanf(buf, "&H%8x", (int *)dest) == 1 ||
175 sscanf(buf, "%d", (int *)dest) == 1;
176 }
178 {
180 if ((
c = sscanf(buf,
"%d:%02d:%02d.%02d", &
h, &m, &
s, &cs)) == 4)
181 *(
int *)dest = 360000*
h + 6000*m + 100*
s + cs;
183 }
185 {
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
202 };
203
204
210 };
211
212
214 {
216 int *count = (
int *)((uint8_t *)&
ctx->ass +
section->offset_count);
217 void **section_ptr = (
void **)((uint8_t *)&
ctx->ass +
section->offset);
224 (*count)++;
226 }
227
229 {
230 return buf == '\r' || buf == '\n' || buf == 0;
231 }
232
234 {
235 while (*buf == ' ')
236 buf++;
237 return buf;
238 }
239
241 {
244
245 if (!order)
252 return order;
253 }
254
256 {
258 int *number = &
ctx->field_number[
ctx->current_section];
259 int *order =
ctx->field_order[
ctx->current_section];
261
262 while (buf && *buf) {
263 if (buf[0] == '[') {
264 ctx->current_section = -1;
265 break;
266 }
267 if (buf[0] == ';' || (buf[0] == '!' && buf[1] == ':'))
268 goto next_line; // skip comments
269
270 len = strcspn(buf,
":\r\n");
271 if (buf[
len] ==
':' &&
276 ctx->current_section =
i;
278 number = &
ctx->field_number[
ctx->current_section];
279 order =
ctx->field_order[
ctx->current_section];
280 break;
281 }
282 }
283 }
284 if (
section->format_header && !order) {
286 if (!strncmp(buf,
section->format_header,
len) && buf[
len] ==
':') {
290 len = strcspn(buf,
", \r\n");
293
294 order[*number] = -1;
298 break;
299 }
300 (*number)++;
302 }
303 ctx->field_order[
ctx->current_section] = order;
304 goto next_line;
305 }
306 }
309 if (!strncmp(buf,
section->fields_header,
len) && buf[
len] ==
':') {
311 if (!struct_ptr)
return NULL;
312
313 /* No format header line found so far, assume default */
314 if (!order) {
316 if (!order)
318 ctx->field_order[
ctx->current_section] = order;
319 }
320
322 for (
i=0; !
is_eol(*buf) &&
i < *number;
i++) {
323 int last =
i == *number - 1;
325 len = strcspn(buf, last ?
"\r\n" :
",\r\n");
328 ptr = struct_ptr +
section->fields[order[
i]].offset;
330 }
332 if (!last && *buf) buf++;
334 }
335 }
336 } else {
337 len = strcspn(buf,
":\r\n");
338 if (buf[
len] ==
':') {
342 uint8_t *ptr = (uint8_t *)&
ctx->ass +
section->offset;
346 break;
347 }
348 }
349 }
350 next_line:
351 buf += strcspn(buf, "\n");
352 buf += !!*buf;
353 }
354 return buf;
355 }
356
358 {
361
362 if (
ctx->current_section >= 0)
364
365 while (buf && *buf) {
366 if (sscanf(buf,
"[%15[0-9A-Za-z+ ]]%c",
section, &
c) == 2) {
367 buf += strcspn(buf, "\n");
368 buf += !!*buf;
371 ctx->current_section =
i;
373 }
374 } else {
375 buf += strcspn(buf, "\n");
376 buf += !!*buf;
377 }
378 }
380 }
381
383 {
387 if (buf && !strncmp(buf, "\xef\xbb\xbf", 3)) // Skip UTF-8 BOM header
388 buf += 3;
389 ctx->current_section = -1;
393 }
395 }
396
398 {
399 uint8_t *ptr = (uint8_t *)&
ctx->ass +
section->offset;
400 int i, j, *count,
c = 1;
401
403 ptr = *(void **)ptr;
404 count = (
int *)((uint8_t *)&
ctx->ass +
section->offset_count);
405 } else
407
408 if (ptr)
409 for (
i=0;
i<*count;
i++, ptr +=
section->size)
414 }
415 *count = 0;
416
419 }
420
422 {
424 if (!dialog)
425 return;
431 }
432
434 {
446 };
447
449 if (!dialog)
451
458 len = last ? strlen(buf) : strcspn(buf,
",");
459 if (
len >= INT_MAX) {
462 }
465 if (*buf) buf++;
466 }
467 return dialog;
468 }
469
471 {
477 }
479 }
480 }
481
482
484 const char *buf)
485 {
486 const char *text =
NULL;
487 char new_line[2];
488 int text_len = 0;
489
490 while (buf && *buf) {
492 (sscanf(buf, "\\%1[nN]", new_line) == 1 ||
493 !strncmp(buf, "{\\", 2))) {
496 }
497 if (sscanf(buf, "\\%1[nN]", new_line) == 1) {
499 callbacks->new_line(priv, new_line[0] ==
'N');
500 buf += 2;
501 } else if (!strncmp(buf, "{\\", 2)) {
502 buf++;
503 while (*buf == '\\') {
504 char style[2],
c[2], sep[2], c_num[2] =
"0",
tmp[128] = {0};
505 unsigned int color = 0xFFFFFFFF;
507 int x1, y1, x2, y2,
t1 = -1,
t2 = -1;
508 if (sscanf(buf,
"\\%1[bisu]%1[01\\}]%n", style,
c, &
len) > 1) {
509 int close =
c[0] ==
'0' ? 1 :
c[0] ==
'1' ? 0 : -1;
513 }
else if (sscanf(buf,
"\\c%1[\\}]%n", sep, &
len) > 0 ||
514 sscanf(buf,
"\\c&H%X&%1[\\}]%n", &
color, sep, &
len) > 1 ||
515 sscanf(buf,
"\\%1[1234]c%1[\\}]%n", c_num, sep, &
len) > 1 ||
516 sscanf(buf,
"\\%1[1234]c&H%X&%1[\\}]%n", c_num, &
color, sep, &
len) > 2) {
519 }
else if (sscanf(buf,
"\\alpha%1[\\}]%n", sep, &
len) > 0 ||
520 sscanf(buf,
"\\alpha&H%2X&%1[\\}]%n", &
alpha, sep, &
len) > 1 ||
521 sscanf(buf,
"\\%1[1234]a%1[\\}]%n", c_num, sep, &
len) > 1 ||
522 sscanf(buf,
"\\%1[1234]a&H%2X&%1[\\}]%n", c_num, &
alpha, sep, &
len) > 2) {
525 }
else if (sscanf(buf,
"\\fn%1[\\}]%n", sep, &
len) > 0 ||
526 sscanf(buf,
"\\fn%127[^\\}]%1[\\}]%n",
tmp, sep, &
len) > 1) {
529 }
else if (sscanf(buf,
"\\fs%1[\\}]%n", sep, &
len) > 0 ||
530 sscanf(buf,
"\\fs%u%1[\\}]%n", &
size, sep, &
len) > 1) {
533 }
else if (sscanf(buf,
"\\a%1[\\}]%n", sep, &
len) > 0 ||
534 sscanf(buf,
"\\a%2u%1[\\}]%n", &an, sep, &
len) > 1 ||
535 sscanf(buf,
"\\an%1[\\}]%n", sep, &
len) > 0 ||
536 sscanf(buf,
"\\an%1u%1[\\}]%n", &an, sep, &
len) > 1) {
537 if (an != -1 && buf[2] != 'n')
538 an = (an&3) + (an&4 ? 6 : an&8 ? 3 : 0);
541 }
else if (sscanf(buf,
"\\r%1[\\}]%n", sep, &
len) > 0 ||
542 sscanf(buf,
"\\r%127[^\\}]%1[\\}]%n",
tmp, sep, &
len) > 1) {
545 }
else if (sscanf(buf,
"\\move(%d,%d,%d,%d)%1[\\}]%n", &x1, &y1, &x2, &y2, sep, &
len) > 4 ||
546 sscanf(buf,
"\\move(%d,%d,%d,%d,%d,%d)%1[\\}]%n", &x1, &y1, &x2, &y2, &
t1, &
t2, sep, &
len) > 6) {
549 }
else if (sscanf(buf,
"\\pos(%d,%d)%1[\\}]%n", &x1, &y1, sep, &
len) > 2) {
551 callbacks->move(priv, x1, y1, x1, y1, -1, -1);
552 }
else if (sscanf(buf,
"\\org(%d,%d)%1[\\}]%n", &x1, &y1, sep, &
len) > 2) {
555 } else {
556 len = strcspn(buf+1,
"\\}") + 2;
/* skip unknown code */
557 }
559 }
560 if (*buf++ != '}')
562 } else {
563 if (!text) {
564 text = buf;
565 text_len = 1;
566 } else
567 text_len++;
568 buf++;
569 }
570 }
575 return 0;
576 }
577
579 {
582
583 if (!style || !*style)
584 style = "Default";
589 }