Bug Summary

File:subreader.c
Location:line 2201, column 41
Description:Call to 'malloc' has an allocation size of 0 bytes

Annotated Source Code

1/*
2 Reading of subtitle files for spumux
3*/
4/* Copyright (C) 2000 - 2003 various authors of the MPLAYER project
5 * This module uses various parts of the MPLAYER project (http://www.mplayerhq.hu)
6 * With many changes by Sjef van Gool (svangool@hotmail.com) November 2003
7 * And many changes by Lawrence D'Oliveiro <ldo@geek-central.gen.nz> April 2010.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or (at
12 * your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 * MA 02110-1301 USA.
23 */
24
25/*
26 * Subtitle reader with format autodetection
27 *
28 * Written by laaz
29 * Some code cleanup & realloc() by A'rpi/ESP-team
30 * pjs sub format by szabi
31 *
32 */
33
34#include "config.h"
35
36#include "compat.h"
37
38#include <ctype.h>
39#include <fcntl.h>
40#include <dirent.h>
41#include <errno(*__errno_location ()).h>
42#include <assert.h>
43
44#include "subglobals.h"
45#include "subreader.h"
46
47#define ERR((void *) -1) ((void *) -1)
48
49#ifdef HAVE_FRIBIDI1
50#include <fribidi/fribidi.h>
51#endif
52
53// subtitle formats
54#define SUB_INVALID-1 -1
55#define SUB_MICRODVD0 0 /* see <http://en.wikipedia.org/wiki/MicroDVD> */
56#define SUB_SUBRIP1 1 /* see <http://wiki.multimedia.cx/index.php?title=SubRip> */
57#define SUB_SUBVIEWER2 2 /* see <http://en.wikipedia.org/wiki/SubViewer>, sample <http://wiki.videolan.org/SubViewer> */
58#define SUB_SAMI3 3 /* see <http://en.wikipedia.org/wiki/SAMI>, sample <http://www.titlefactory.com/TitleFactoryDocs/sami_format.htm> */
59#define SUB_VPLAYER4 4
60#define SUB_RT5 5
61#define SUB_SSA6 6 /* spec is at <http://moodub.free.fr/video/ass-specs.doc>, or see <http://www.matroska.org/technical/specs/subtitles/ssa.html> */
62#define SUB_PJS7 7 /* Phoenix Japanimation Society */
63#define SUB_MPSUB8 8
64#define SUB_AQTITLE9 9
65#define SUB_SUBVIEWER210 10 /* see <http://en.wikipedia.org/wiki/SubViewer>, sample <http://wiki.videolan.org/SubViewer> */
66#define SUB_SUBRIP0911 11
67#define SUB_JACOSUB12 12 /* spec is at <http://unicorn.us.com/jacosub/jscripts.html>. */
68
69/* Maximal length of line of a subtitle */
70#define LINE_LEN1000 1000
71
72static float
73 /* global state for mpsub subtitle format */
74 mpsub_position = 0.0,
75 /* for determining next start time, because file format only gives incremental durations */
76 mpsub_multiplier = 1.0; /* for scaling times */
77static int
78 /* global state for sami subtitle format */
79 sami_sub_slacktime = 20000; //20 sec
80
81static int sub_no_text_pp=0; // 1 => do not apply text post-processing
82 // like {\...} elimination in SSA format.
83 /* never set to any other value */
84
85#define USE_SORTSUB1 1
86 /* whether to ensure that subtitle entries are sorted into time order */
87#ifdef USE_SORTSUB1
88/*
89 Some subtitling formats, namely AQT and Subrip09, define the end of a
90 subtitle as the beginning of the following. Since currently we read one
91 subtitle at time, for these format we keep two global *subtitle,
92 previous_aqt_sub and previous_subrip09_sub, pointing to previous subtitle,
93 so we can change its end when we read current subtitle starting time.
94 When USE_SORTSUB is defined, we use a single global unsigned long,
95 previous_sub_end, for both (and even future) formats, to store the end of
96 the previous sub: it is initialized to 0 in sub_read_file and eventually
97 modified by sub_read_aqt_line or sub_read_subrip09_line.
98 */
99static unsigned long previous_sub_end;
100#endif
101
102/*
103 Caller-controllable settings
104*/
105
106char* subtitle_charset = NULL((void*)0);
107 /* subtitle_charset (char) contains "from character-set" for ICONV like ISO8859-1 and UTF-8, */
108 /* "to character-set" is set to UTF-8. If not specified, then defaults to locale */
109
110float sub_delay=0.0;
111/* sub_delay (float) contains delay for subtitles in 10 msec intervals (optional user parameter, 0.0 for no delay)*/
112float sub_fps=0.0;
113/* sub_fps (float)contains subtitle frames per second, only applicable when we have no timed subs (detection from
114 video stream, 0.0 for setting taken over from fps otherwise subtitle fps)*/
115int suboverlap_enabled=1;
116/* suboverlap_enabled (int) indicates overlap if the user forced it (suboverlap_enabled == 2) or
117 the user didn't forced no-overlapsub and the format is Jacosub or Ssa.
118 this is because usually overlapping subtitles are found in these formats,
119 while in others they are probably result of bad timing (set by subtile file type if
120 initialized on 1) */
121 /* never set to any other value */
122
123/*
124 Useful string-handling routines
125*/
126
127static int eol(char p)
128 /* does p indicate the end of a line. */
129 {
130 return p == '\r' || p == '\n' || p == '\0';
131 } /*eol*/
132
133/* Remove leading and trailing space */
134static void trail_space(char *s)
135 {
136 int i = 0;
137 while (isspace(s[i])((*__ctype_b_loc ())[(int) ((s[i]))] & (unsigned short int
) _ISspace)
)
138 ++i;
139 if (i)
140 strcpy(s, s + i);
141 i = strlen(s) - 1;
142 while (i > 0 && isspace(s[i])((*__ctype_b_loc ())[(int) ((s[i]))] & (unsigned short int
) _ISspace)
)
143 s[i--] = '\0';
144 } /*trail_space*/
145
146static const char *stristr(const char *haystack, const char *needle)
147 /* case-insensitive substring search. */
148 {
149 int len = 0;
150 const char *p = haystack;
151 if (!(haystack && needle))
152 return NULL((void*)0);
153 len = strlen(needle);
154 while (*p != '\0')
155 {
156 if (strncasecmp(p, needle, len) == 0)
157 return p;
158 p++;
159 } /*while*/
160 return NULL((void*)0);
161 } /*stristr*/
162
163/*
164 Input-file reading
165*/
166
167enum
168 {
169 sub_buf_size = 2048,
170 };
171struct vfile
172 subfile;
173static char *
174 sub_buf = NULL((void*)0);
175static size_t
176 sub_out_size,
177 sub_next_out,
178 sub_end_out;
179static bool_Bool
180 sub_buf_rewindable = false0;
181static int
182 in_charno = 0,
183 in_lineno = 1;
184
185static void sub_open(const char * filename)
186 {
187 subfile = varied_open(filename, O_RDONLY00, "subtitle file");
188 sub_out_size = sub_buf_size;
189 sub_buf = malloc(sub_out_size);
190 sub_next_out = 0;
191 sub_end_out = 0;
192 in_charno = 0;
193 in_lineno = 1;
194 } /*sub_open*/
195
196static void sub_close(void)
197 {
198 varied_close(subfile);
199 free(sub_buf);
200 sub_buf = NULL((void*)0);
201 } /*sub_close*/
202
203#ifdef HAVE_ICONV1
204
205static iconv_t
206 icdsc = ICONV_NULL((iconv_t)-1); /* for converting subtitle text encoding to UTF-8 */
207static char
208 ic_inbuf[sub_buf_size]; /* size to minimize reads from disk */
209static size_t
210 ic_next_in,
211 ic_end_in;
212static int
213 ic_needmore,
214 ic_eof;
215
216static void subcp_open(void)
217 /* opens an iconv context for converting subtitles from subtitle_charset to UTF-8 if appropriate. */
218 {
219 const char * const fromcp = subtitle_charset != NULL((void*)0) ? subtitle_charset : default_charset;
220 const char * const tocp = "UTF-8";
221 icdsc = iconv_open(tocp, fromcp);
222 if (icdsc != ICONV_NULL((iconv_t)-1))
223 {
224 fprintf(stderrstderr, "INFO: Opened iconv descriptor. *%s* <= *%s*\n", tocp, fromcp);
225 ic_next_in = 0;
226 ic_end_in = 0;
227 ic_needmore = false0;
228 ic_eof = false0;
229 }
230 else
231 {
232 fprintf
233 (
234 stderrstderr,
235 "ERR: Error %d -- %s opening iconv descriptor for charset \"%s\".\n",
236 errno(*__errno_location ()), strerror(errno(*__errno_location ())), fromcp
237 );
238 exit(1);
239 } /*if*/
240 } /*subcp_open*/
241
242static void subcp_close(void)
243 /* closes the previously-opened iconv context, if any. */
244 {
245 if (icdsc != ICONV_NULL((iconv_t)-1))
246 {
247 (void)iconv_close(icdsc);
248 icdsc = ICONV_NULL((iconv_t)-1);
249/* fprintf(stderr, "INFO: Closed iconv descriptor.\n"); */
250 } /*if*/
251 } /*subcp_close*/
252
253#endif /*HAVE_ICONV*/
254
255static int sub_getc()
256 /* gets the next decoded UTF-8 byte from the input file, or EOF if the
257 end of the file has been reached. */
258 {
259 int result;
260 if (sub_next_out == sub_end_out)
261 {
262#ifdef HAVE_ICONV1
263 if (icdsc != ICONV_NULL((iconv_t)-1))
264 {
265 if ((ic_next_in == ic_end_in || ic_needmore) && !ic_eof)
266 {
267 /* refill the input buffer */
268 size_t bytesread;
269 if (ic_next_in < ic_end_in)
270 {
271 /* move down remaining unprocessed data from last read */
272 ic_end_in -= ic_next_in;
273 memcpy(ic_inbuf, ic_inbuf + ic_next_in, ic_end_in);
274 }
275 else
276 {
277 ic_end_in = 0;
278 } /*if*/
279 bytesread = fread(ic_inbuf + ic_end_in, 1, sizeof ic_inbuf - ic_end_in, subfile.h);
280 ic_end_in += bytesread;
281 if (ic_end_in < sizeof ic_inbuf)
282 {
283 ic_eof = true1;
284 } /*if*/
285 ic_next_in = 0;
286 ic_needmore = false0;
287 } /*if*/
288 if (ic_next_in < ic_end_in)
289 {
290 /* refill sub_buf with more decoded characters */
291 const char * nextin;
292 char * nextout;
293 size_t inleft, outleft, prev_sub_end_out;
294 bool_Bool convok;
295 nextin = ic_inbuf + ic_next_in;
296 if (sub_buf_rewindable)
297 {
298 if (sub_out_size - sub_end_out < sub_buf_size)
299 {
300 /* make room for more */
301 sub_out_size += sub_buf_size;
302 sub_buf = realloc(sub_buf, sub_out_size);
303 } /*if*/
304 nextout = sub_buf + sub_end_out; /* keep what's in buffer */
305 }
306 else
307 {
308 if (sub_out_size > sub_buf_size) /* don't need bigger buffer any more */
309 {
310 sub_out_size = sub_buf_size;
311 sub_buf = realloc(sub_buf, sub_out_size);
312 } /*if*/
313 nextout = sub_buf;
314 } /*if*/
315 inleft = ic_end_in - ic_next_in; /* won't be zero */
316 outleft = sub_out_size - (nextout - sub_buf);
317 prev_sub_end_out = outleft;
318 convok = iconv(icdsc, (char **)&nextin, &inleft, &nextout, &outleft) != (size_t)-1;
319 if (!convok && errno(*__errno_location ()) == E2BIG7 && outleft < prev_sub_end_out)
320 { /* no room to completely convert input, but got something so that's OK */
321 convok = true1;
322 errno(*__errno_location ()) = 0;
323 } /*if*/
324 if (!convok)
325 {
326 if (!ic_eof && errno(*__errno_location ()) == EINVAL22)
327 {
328 errno(*__errno_location ()) = 0;
329 ic_needmore = true1;
330 /* can't decode what's left in ic_inbuf without reading more */
331 }
332 else /* E2BIG (shouldn't occur), EILSEQ, EINVAL at end of file */
333 {
334 fprintf
335 (
336 stderrstderr,
337 "ERR: Error %d -- %s -- decoding subtitle file at approx"
338 " line pos %d + char pos %d\n",
339 errno(*__errno_location ()),
340 strerror(errno(*__errno_location ())),
341 in_lineno, /* might be wrong */
342 in_charno + (int)(nextin - ic_inbuf) /* hopefully this is better */
343 );
344 exit(1);
345 } /*if*/
346 } /*if*/
347 ic_next_in = nextin - ic_inbuf;
348 prev_sub_end_out = sub_buf_rewindable ? sub_end_out : 0;
349 sub_end_out = nextout - sub_buf;
350 assert(sub_end_out != prev_sub_end_out)((sub_end_out != prev_sub_end_out) ? (void) (0) : __assert_fail
("sub_end_out != prev_sub_end_out", "subreader.c", 350, __PRETTY_FUNCTION__
))
;
351 /* because I gave it plenty of input data to work on */
352 if (!sub_buf_rewindable)
353 {
354 sub_next_out = 0;
355 } /*if*/
356 } /*if*/
357 }
358 else
359#endif /*HAVE_ICONV*/
360 {
361 char * nextout;
362 size_t bytesread;
363 if (sub_buf_rewindable)
364 {
365 if (sub_out_size - sub_end_out < sub_buf_size)
366 {
367 /* make room for more */
368 sub_out_size += sub_buf_size;
369 sub_buf = realloc(sub_buf, sub_out_size);
370 } /*if*/
371 nextout = sub_buf + sub_end_out; /* keep what's in buffer */
372 }
373 else
374 {
375 if (sub_out_size > sub_buf_size) /* don't need bigger buffer any more */
376 {
377 sub_out_size = sub_buf_size;
378 sub_buf = realloc(sub_buf, sub_out_size);
379 } /*if*/
380 nextout = sub_buf;
381 } /*if*/
382 if (!sub_buf_rewindable)
383 {
384 sub_end_out = 0;
385 sub_next_out = 0;
386 } /*if*/
387 bytesread = fread(nextout, 1, sub_out_size - sub_end_out, subfile.h);
388 sub_end_out += bytesread;
389 } /*if*/
390 } /*if*/
391 if (sub_next_out < sub_end_out)
392 {
393 result = sub_buf[sub_next_out];
394 ++in_charno;
395 ++sub_next_out;
396 if (result == '\n')
397 {
398 ++in_lineno;
399 } /*if*/
400 }
401 else
402 {
403 result = EOF(-1);
404 } /*if*/
405 return result;
406 } /*sub_getc*/
407
408static void sub_rewind()
409 /* rewinds to the beginning of the input subtitle file. */
410 {
411 if (!sub_buf_rewindable)
412 {
413 fprintf(stderrstderr, "ERR: trying to rewind subtitle file when not in rewindable state\n");
414 exit(1);
415 } /*if*/
416 sub_next_out = 0;
417 in_charno = 0;
418 in_lineno = 1;
419 } /*sub_rewind*/
420
421static char * sub_fgets
422 (
423 char * dst,
424 size_t dstsize /* must be at least 1, probably should be at least 2 */
425 )
426 /* reads a whole line from the input subtitle file into dst, returning dst if
427 at least one character was read. */
428 {
429 const char * dstend = dst + dstsize - 1;
430 char * dstnext = dst;
431 bool_Bool warned_truncated = false0;
432 for (;;)
433 {
434 const int nextch = sub_getc();
435 if (nextch == EOF(-1))
436 {
437 if (dstnext == dst)
438 {
439 dst = NULL((void*)0); /* indicate nothing read */
440 } /*if*/
441 break;
442 } /*if*/
443 if (dstnext < dstend)
444 {
445 *dstnext = nextch;
446 ++dstnext;
447 }
448 else if (!warned_truncated)
449 {
450 fprintf(stderrstderr, "WARN: input subtitle line too long on line %d\n", in_lineno);
451 warned_truncated = true1;
452 /* and continue gobbling rest of line */
453 } /*if*/
454 if (nextch == '\n')
455 break; /* end of line */
456 } /*for*/
457 if (dst != NULL((void*)0))
458 {
459 *dstnext = 0; /* terminating null */
460 } /*if*/
461 return dst;
462 } /*sub_fgets*/
463
464#ifdef HAVE_FRIBIDI1
465#ifndef max
466#define max(a,b)(((a)>(b))?(a):(b)) (((a)>(b))?(a):(b))
467#endif
468subtitle_elt *sub_fribidi(subtitle_elt *sub)
469 /* reorders character codes as necessary so right-to-left text will come out
470 in the correct order when rendered left-to-right. */
471 {
472 FriBidiChar logical[LINE_LEN1000 + 1], visual[LINE_LEN1000 + 1]; // Hopefully these two won't smash the stack
473 char *ip = NULL((void*)0), *op = NULL((void*)0);
474 FriBidiParType base;
475 size_t len, orig_len;
476 int l = sub->lines;
477 fribidi_boolean log2vis;
478 while (l)
479 {
480 ip = sub->text[--l];
481 orig_len = len = strlen(ip);
482 // We assume that we don't use full unicode, only UTF-8
483 if (len > LINE_LEN1000)
484 {
485 fprintf(stderrstderr, "WARN: Sub->text is longer than LINE_LEN.\n");
486 l++;
487 break;
488 } /*if*/
489 len = fribidi_charset_to_unicodefribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8, ip, len, logical);
490 /* fixme: how do I know it will fit? */
491 base = FRIBIDI_TYPE_ON; /* request order-neutral */
492 log2vis = fribidi_log2visfribidi_log2vis
493 (
494 /*str =*/ logical, /* input logical string */
495 /*len =*/ len, /* input logical string length */
496 /*pbase_dir =*/ &base, /* requested and resolved paragraph base direction */
497 /*visual_str =*/ visual, /* output visual string */
498 /*positions_L_to_V =*/ NULL((void*)0),
499 /* output mapping from logical to visual string positions */
500 /*positions_V_to_L =*/ NULL((void*)0),
501 /* output mapping from visual string back to the logical string positions */
502 /*embedding_levels =*/ NULL((void*)0) /* output list of embedding levels */
503 );
504 /* result is maximum level found plus one, or zero if any error occurred */
505 /* Note this function is deprecated because it only handles one-line paragraphs */
506 if (log2vis)
507 {
508 len = fribidi_remove_bidi_marksfribidi_remove_bidi_marks
509 (
510 /*str =*/ visual,
511 /*len =*/ len,
512 /*positions_to_this =*/ NULL((void*)0),
513 /*positions_from_this_list =*/ NULL((void*)0),
514 /*embedding_levels =*/ NULL((void*)0)
515 );
516 op = (char*)malloc(sizeof(char) * (max(2 * orig_len, 2 * len)(((2 * orig_len)>(2 * len))?(2 * orig_len):(2 * len)) + 1));
517 if (op == NULL((void*)0))
518 {
519 fprintf(stderrstderr, "ERR: Error allocating mem.\n");
520 l++;
521 break;
522 } /*if*/
523 fribidi_unicode_to_charsetfribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8, visual, len, op);
524 /* fixme: how do I know it will fit? */
525 free(ip);
526 sub->text[l] = op;
527 } /*if*/
528 } /*while*/
529 if (l) /* unprocessed lines remaining */
530 {
531 for (l = sub->lines; l;)
532 free(sub->text[--l]);
533 return ERR((void *) -1);
534 } /*if*/
535 return sub;
536 } /*sub_fribidi*/
537
538#endif /*HAVE_FRIBIDI*/
539
540/*
541 Decoders for various subtitle formats
542*/
543
544subtitle_elt *sub_read_line_sami(subtitle_elt *current)
545 {
546 /* yuk--internal static state */
547 static char line[LINE_LEN1000 + 1];
548 static const char *s = NULL((void*)0);
549 /* to get rid of above, simply use sub_getc and process input one character
550 at a time, rather than a whole line at a time */
551 char text[LINE_LEN1000 + 1], *p = text;
552 const char *q;
553 int state;
554 current->lines = current->start = current->end = 0;
555 state = 0;
556 /* read the first line */
557 if (!s)
558 if (!(s = sub_fgets(line, LINE_LEN1000)))
559 return 0;
560 do
561 {
562 switch (state)
563 {
564 case 0: /* find "START=" or "Slacktime:" */
565 {
566 const char * const slacktime_s = stristr(s, "Slacktime:");
567 if (slacktime_s)
568 sami_sub_slacktime = strtol(slacktime_s + 10, NULL((void*)0), 0) / 10;
569 s = stristr(s, "Start=");
570 if (s)
571 {
572 current->start = strtol(s + 6, (char **)&s, 0) / 10;
573 state = 1;
574 continue;
575 } /*if*/
576 }
577 break;
578
579 case 1: /* find first "<P" */
580 s = stristr(s, "<P");
581 if (s != 0)
582 {
583 s += 2;
584 state = 2;
585 continue;
586 } /*if*/
587 break;
588
589 case 2: /* find ">" */
590 s = strchr (s, '>')(__extension__ (__builtin_constant_p ('>') && !__builtin_constant_p
(s) && ('>') == '\0' ? (char *) __rawmemchr (s, '>'
) : __builtin_strchr (s, '>')))
;
591 if (s != 0)
592 {
593 s++;
594 state = 3;
595 p = text; /* start collecting text here */
596 continue;
597 } /*if*/
598 break;
599
600 case 3: /* get all text until '<' appears */
601 if (*s == '\0')
602 break;
603 else if (!strncasecmp (s, "<br>", 4))
604 {
605 *p = '\0'; /* end of collected text */
606 p = text; /* point to whole thing */
607 trail_space(text); /* less whitespace */
608 if (text[0] != '\0') /* what's left is nonempty */
609 current->text[current->lines++] = strdup(text)(__extension__ (__builtin_constant_p (text) && ((size_t
)(const void *)((text) + 1) - (size_t)(const void *)(text) ==
1) ? (((const char *) (text))[0] == '\0' ? (char *) calloc (
(size_t) 1, (size_t) 1) : ({ size_t __len = strlen (text) + 1
; char *__retval = (char *) malloc (__len); if (__retval != (
(void*)0)) __retval = (char *) memcpy (__retval, text, __len)
; __retval; })) : __strdup (text)))
;
610 s += 4; /* skip "<br>" tag and stay in this state */
611 }
612 /* wot, no recognition of "<p>" here? */
613 else if (*s == '<')
614 {
615 state = 4;
616 }
617 else if (!strncasecmp (s, "&nbsp;", 6))
618 {
619 *p++ = ' '; /* treat as space */
620 s += 6;
621 }
622 else if (*s == '\t')
623 {
624 *p++ = ' '; /* treat as space */
625 s++;
626 }
627 else if (*s == '\r' || *s == '\n')
628 {
629 s++; /* ignore line breaks */
630 }
631 else
632 {
633 *p++ = *s++; /* preserve everything else */
634 } /*if*/
635 /* skip duplicated space */
636 if (p > text + 2 && p[-1] == ' ' && p[-2] == ' ')
637 p--;
638 continue;
639
640 case 4: /* get current->end or skip rest of <TAG> */
641 q = stristr(s, "Start=");
642 if (q)
643 {
644 current->end = strtol(q + 6, (char **)&q, 0) / 10 - 1;
645 /* start time of new line is end time of previous line */
646 *p = '\0';
647 trail_space(text);
648 if (text[0] != '\0')
649 current->text[current->lines++] = strdup(text)(__extension__ (__builtin_constant_p (text) && ((size_t
)(const void *)((text) + 1) - (size_t)(const void *)(text) ==
1) ? (((const char *) (text))[0] == '\0' ? (char *) calloc (
(size_t) 1, (size_t) 1) : ({ size_t __len = strlen (text) + 1
; char *__retval = (char *) malloc (__len); if (__retval != (
(void*)0)) __retval = (char *) memcpy (__retval, text, __len)
; __retval; })) : __strdup (text)))
;
650 if (current->lines > 0) /* got one line, leave new one for next call */
651 {
652 state = 99;
653 break;
654 } /*if*/
655 state = 0;
656 continue;
657 } /*if*/
658 s = strchr (s, '>')(__extension__ (__builtin_constant_p ('>') && !__builtin_constant_p
(s) && ('>') == '\0' ? (char *) __rawmemchr (s, '>'
) : __builtin_strchr (s, '>')))
;
659 if (s)
660 {
661 s++;
662 state = 3; /* back to collecting text */
663 continue;
664 } /*if*/
665 break;
666 } /*switch*/
667 /* read next line */
668 if (state != 99 && !(s = sub_fgets(line, LINE_LEN1000)))
669 {
670 if (current->start > 0)
671 {
672 break; // if it is the last subtitle
673 }
674 else
675 {
676 return 0;
677 } /*if*/
678 } /*if*/
679 }
680 while (state != 99);
681 // For the last subtitle
682 if (current->end <= 0)
683 {
684 current->end = current->start + sami_sub_slacktime;
685 *p = '\0';
686 trail_space(text);
687 if (text[0] != '\0')
688 current->text[current->lines++] = strdup(text)(__extension__ (__builtin_constant_p (text) && ((size_t
)(const void *)((text) + 1) - (size_t)(const void *)(text) ==
1) ? (((const char *) (text))[0] == '\0' ? (char *) calloc (
(size_t) 1, (size_t) 1) : ({ size_t __len = strlen (text) + 1
; char *__retval = (char *) malloc (__len); if (__retval != (
(void*)0)) __retval = (char *) memcpy (__retval, text, __len)
; __retval; })) : __strdup (text)))
;
689 } /*if*/
690 return current;
691 } /*sub_read_line_sami*/
692
693static const char *sub_readtext(const char *source, char **dest)
694 /* extracts the next text item in source, and returns a copy of it in *dest
695 (could be the empty string). Returns a pointer into the unprocessed remainder
696 of source, or NULL if there is nothing left. */
697 {
698 int len = 0;
699 const char *p = source;
700// fprintf(stderr, "src=%p dest=%p \n", source, dest);
701 while (!eol(*p) && *p!= '|')
702 {
703 p++, len++;
704 } /*while*/
705 *dest = (char *)malloc(len + 1);
706 if (!*dest)
707 {
708 return ERR((void *) -1);
709 } /*if*/
710 strncpy(*dest, source, len)__builtin_strncpy (*dest, source, len);
711 (*dest)[len] = 0;
712 while (*p == '\r' || *p == '\n' || *p == '|')
713 p++;
714 if (*p)
715 return p; // not-last text field
716 else
717 return NULL((void*)0); // last text field
718 } /*sub_readtext*/
719
720subtitle_elt *sub_read_line_microdvd(subtitle_elt *current)
721 {
722 char line[LINE_LEN1000 + 1];
723 char line2[LINE_LEN1000 + 1];
724 const char *p, *next;
725 int i;
726 do /* look for valid timing line */
727 {
728 if (!sub_fgets(line, LINE_LEN1000))
729 return NULL((void*)0);
730 }
731 while
732 (
733 sscanf(line, "{%ld}{}%[^\r\n]", &current->start, line2)
734 <
735 2
736
737 &&
738 sscanf(line, "{%ld}{%ld}%[^\r\n]", &current->start, &current->end, line2)
739 <
740 3
741 );
742 p = line2;
743 next = p, i = 0;
744 while ((next = sub_readtext(next, &current->text[i])) != 0)
745 {
746 if (current->text[i] == ERR((void *) -1))
747 {
748 return ERR((void *) -1);
749 } /*if*/
750 i++;
751 if (i >= SUB_MAX_TEXT16)
752 {
753 fprintf(stderrstderr, "WARN: Too many lines in a subtitle\n");
754 current->lines = i;
755 return current;
756 } /*if*/
757 } /*while*/
758 current->lines = ++i;
759 return current;
760 } /*sub_read_line_microdvd*/
761
762subtitle_elt *sub_read_line_subrip(subtitle_elt *current)
763 {
764 char line[LINE_LEN1000 + 1];
765 int a1, a2, a3, a4, b1, b2, b3, b4;
766 const char *p = NULL((void*)0), *q = NULL((void*)0);
767 int len;
768 while (true1)
769 {
770 if (!sub_fgets(line, LINE_LEN1000))
771 return NULL((void*)0);
772 if (sscanf(line, "%d:%d:%d.%d,%d:%d:%d.%d", &a1, &a2, &a3, &a4, &b1, &b2, &b3, &b4) < 8)
773 /* start and end times in hours:minutes:seconds.hundredths */
774 continue;
775 current->start = a1 * 360000 + a2 * 6000 + a3 * 100 + a4;
776 current->end = b1 * 360000 + b2 * 6000 + b3 * 100 + b4;
777 if (!sub_fgets(line, LINE_LEN1000))
778 return NULL((void*)0);
779 p = q = line;
780 for (current->lines = 1; current->lines < SUB_MAX_TEXT16; current->lines++)
781 {
782 for
783 (
784 q = p, len = 0;
785 *p && *p != '\r' && *p != '\n' && *p != '|' && strncmp(p, "[br]", 4)(__extension__ (__builtin_constant_p (4) && ((__builtin_constant_p
(p) && strlen (p) < ((size_t) (4))) || (__builtin_constant_p
("[br]") && strlen ("[br]") < ((size_t) (4)))) ? __extension__
({ size_t __s1_len, __s2_len; (__builtin_constant_p (p) &&
__builtin_constant_p ("[br]") && (__s1_len = strlen (
p), __s2_len = strlen ("[br]"), (!((size_t)(const void *)((p)
+ 1) - (size_t)(const void *)(p) == 1) || __s1_len >= 4) &&
(!((size_t)(const void *)(("[br]") + 1) - (size_t)(const void
*)("[br]") == 1) || __s2_len >= 4)) ? __builtin_strcmp (p
, "[br]") : (__builtin_constant_p (p) && ((size_t)(const
void *)((p) + 1) - (size_t)(const void *)(p) == 1) &&
(__s1_len = strlen (p), __s1_len < 4) ? (__builtin_constant_p
("[br]") && ((size_t)(const void *)(("[br]") + 1) - (
size_t)(const void *)("[br]") == 1) ? __builtin_strcmp (p, "[br]"
) : (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) ("[br]"); int __result = (((const unsigned
char *) (const char *) (p))[0] - __s2[0]); if (__s1_len >
0 && __result == 0) { __result = (((const unsigned char
*) (const char *) (p))[1] - __s2[1]); if (__s1_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (p))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) (p
))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p (
"[br]") && ((size_t)(const void *)(("[br]") + 1) - (size_t
)(const void *)("[br]") == 1) && (__s2_len = strlen (
"[br]"), __s2_len < 4) ? (__builtin_constant_p (p) &&
((size_t)(const void *)((p) + 1) - (size_t)(const void *)(p)
== 1) ? __builtin_strcmp (p, "[br]") : (- (__extension__ ({ const
unsigned char *__s2 = (const unsigned char *) (const char *)
(p); int __result = (((const unsigned char *) (const char *)
("[br]"))[0] - __s2[0]); if (__s2_len > 0 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
"[br]"))[1] - __s2[1]); if (__s2_len > 1 && __result
== 0) { __result = (((const unsigned char *) (const char *) (
"[br]"))[2] - __s2[2]); if (__s2_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) ("[br]"
))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (p, "[br]"
)))); }) : strncmp (p, "[br]", 4)))
;
786 p++, len++
787 )
788 /* include in current subtitle line until end of line or "|" or "[br]" markers */;
789 current->text[current->lines - 1] = (char *)malloc(len + 1);
790 if (!current->text[current->lines - 1])
791 return ERR((void *) -1);
792 strncpy(current->text[current->lines - 1], q, len)__builtin_strncpy (current->text[current->lines - 1], q
, len)
;
793 current->text[current->lines-1][len] = '\0';
794 if (!*p || *p == '\r' || *p == '\n')
795 break;
796 if (*p == '|')
797 p++;
798 else
799 while (*p++ != ']')
800 /* skip "[br]" marker */;
801 } /*for*/
802 break;
803 } /*while*/
804 return current;
805 } /*sub_read_line_subrip*/
806
807subtitle_elt *sub_read_line_subviewer(subtitle_elt *current)
808 {
809 char line[LINE_LEN1000 + 1];
810 int a1, a2, a3, a4, b1, b2, b3, b4;
811 const char *p = NULL((void*)0);
812 int i, len;
813 while (!current->text[0])
814 {
815 if (!sub_fgets(line, LINE_LEN1000))
816 return NULL((void*)0);
817 if
818 (
819 (len = sscanf
820 (
821 line,
822 "%d:%d:%d%[,.:]%d --> %d:%d:%d%[,.:]%d",
823 &a1, &a2, &a3, (char *)&i, &a4,
824 &b1, &b2, &b3, (char *)&i, &b4
825 ))
826 <
827 10
828 )
829 continue;
830 current->start = a1 * 360000 + a2 * 6000 + a3 * 100 + a4 / 10;
831 current->end = b1 * 360000 + b2 * 6000 + b3 * 100 + b4 / 10;
832 for (i = 0; i < SUB_MAX_TEXT16;)
833 {
834 if (!sub_fgets(line, LINE_LEN1000))
835 break;
836 len = 0;
837 for (p = line; *p != '\n' && *p != '\r' && *p; p++, len++)
838 /* find end of line */;
839 if (len) /* nonempty line */
840 {
841 int j = 0;
842 bool_Bool skip = false0;
843 char *curptr = current->text[i] = (char *)malloc(len + 1);
844 if (!current->text[i])
845 return ERR((void *) -1);
846 //strncpy(current->text[i], line, len); current->text[i][len] = '\0';
847 for(; j < len; j++)
848 {
849 /* let's filter html tags ::atmos */
850 /* fixme: if you're going to filter out "<" characters,
851 shouldn't you provide a way to escape them? For example,
852 using HTML-style "&"-escapes? */
853 if (line[j] == '>')
854 {
855 skip = false0;
856 continue;
857 } /*if*/
858 if (line[j] == '<')
859 {
860 skip = true1;
861 continue;
862 } /*if*/
863 if (skip)
864 {
865 continue;
866 } /*if*/
867 *curptr = line[j];
868 curptr++;
869 } /*for*/
870 *curptr = '\0';
871 i++;
872 }
873 else
874 {
875 break;
876 } /*if*/
877 } /*for*/
878 current->lines = i;
879 } /*while*/
880 return current;
881 } /*sub_read_line_subviewer*/
882
883subtitle_elt *sub_read_line_subviewer2(subtitle_elt *current)
884 {
885 char line[LINE_LEN1000 + 1];
886 int a1, a2, a3, a4;
887 const char *p = NULL((void*)0);
888 int i, len;
889 while (!current->text[0])
890 {
891 if (!sub_fgets(line, LINE_LEN1000))
892 return NULL((void*)0);
893 if (line[0] != '{')
894 continue;
895 if ((len = sscanf(line, "{T %d:%d:%d:%d", &a1, &a2, &a3, &a4)) < 4)
896 continue;
897 current->start = a1 * 360000 + a2 * 6000 + a3 * 100 + a4 / 10;
898 for (i = 0; i < SUB_MAX_TEXT16;)
899 {
900 if (!sub_fgets(line, LINE_LEN1000))
901 break;
902 if (line[0] == '}')
903 break;
904 len = 0;
905 for (p = line; *p != '\n' && *p != '\r' && *p; ++p, ++len)
906 /* find end of line */;
907 if (len) /* nonempty line */
908 {
909 current->text[i] = (char *)malloc(len + 1);
910 if (!current->text[i])
911 return ERR((void *) -1);
912 strncpy(current->text[i], line, len)__builtin_strncpy (current->text[i], line, len);
913 current->text[i][len] = '\0';
914 ++i;
915 }
916 else
917 {
918 break;
919 } /*if*/
920 } /*for*/
921 current->lines = i;
922 } /*while*/
923 return current;
924 } /*sub_read_line_subviewer2*/
925
926subtitle_elt *sub_read_line_vplayer(subtitle_elt *current)
927 {
928 char line[LINE_LEN1000 + 1];
929 int a1, a2, a3;
930 const char *p = NULL((void*)0), *next;
931 char separator;
932 int i, len, plen;
933 while (!current->text[0])
934 {
935 if (!sub_fgets(line, LINE_LEN1000))
936 return NULL((void*)0);
937 if ((len = sscanf(line, "%d:%d:%d%c%n", &a1, &a2, &a3, &separator, &plen)) < 4)
938 continue;
939 if (!(current->start = a1 * 360000 + a2 * 6000 + a3 * 100))
940 continue;
941#if 0 /*removed by wodzu*/
942 p = line;
943 // finds the body of the subtitle
944 for (i = 0; i < 3; i++)
945 {
946 p = strchr(p, ':')(__extension__ (__builtin_constant_p (':') && !__builtin_constant_p
(p) && (':') == '\0' ? (char *) __rawmemchr (p, ':')
: __builtin_strchr (p, ':')))
;
947 if (p == NULL((void*)0))
948 break;
949 ++p;
950 } /*for*/
951 if (p == NULL((void*)0))
952 {
953 fprintf(stderrstderr, "SUB: Skipping incorrect subtitle line!\n");
954 continue;
955 } /*if*/
956#else
957 // by wodzu: hey! this time we know what length it has! what is
958 // that magic for? it can't deal with space instead of third
959 // colon! look, what simple it can be:
960 p = &line[plen];
961#endif
962 if (*p != '|')
963 {
964 //
965 next = p, i = 0;
966 while ((next = sub_readtext(next, &current->text[i])) != 0)
967 {
968 if (current->text[i] == ERR((void *) -1))
969 {
970 return ERR((void *) -1);
971 } /*if*/
972 i++;
973 if (i >= SUB_MAX_TEXT16)
974 {
975 fprintf(stderrstderr, "WARN: Too many lines in a subtitle\n");
976 current->lines = i;
977 return current;
978 } /*if*/
979 } /*while*/
980 current->lines = i + 1;
981 } /*if*/
982 } /*while*/
983 return current;
984 } /*sub_read_line_vplayer*/
985
986subtitle_elt *sub_read_line_rt(subtitle_elt *current)
987 {
988 //TODO: This format uses quite rich (sub/super)set of xhtml
989 // I couldn't check it since DTD is not included.
990 // WARNING: full XML parses can be required for proper parsing
991 char line[LINE_LEN1000 + 1];
992 int a1, a2, a3, a4, b1, b2, b3, b4;
993 const char *next = NULL((void*)0);
994 int i, len, plen;
995 while (!current->text[0])
996 {
997 if (!sub_fgets(line, LINE_LEN1000))
998 return NULL((void*)0);
999 //TODO: it seems that format of time is not easily determined, it may be 1:12, 1:12.0 or 0:1:12.0
1000 //to describe the same moment in time. Maybe there are even more formats in use.
1001 //if ((len = sscanf(line, "<Time Begin=\"%d:%d:%d.%d\" End=\"%d:%d:%d.%d\"",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4)) < 8)
1002 plen = a1 = a2 = a3 = a4 = b1 = b2 = b3 = b4 = 0;
1003 if
1004 (
1005 (len = sscanf
1006 (
1007 line,
1008 "<%*[tT]ime %*[bB]egin=\"%d.%d\" %*[Ee]nd=\"%d.%d\"%*[^<]<clear/>%n",
1009 &a3, &a4, &b3, &b4, &plen
1010 ))
1011 <
1012 4
1013 &&
1014 (len = sscanf
1015 (
1016 line,
1017 "<%*[tT]ime %*[bB]egin=\"%d.%d\" %*[Ee]nd=\"%d:%d.%d\"%*[^<]<clear/>%n",
1018 &a3, &a4, &b2, &b3, &b4, &plen
1019 ))
1020 <
1021 5
1022 &&
1023 (len = sscanf
1024 (
1025 line,
1026 "<%*[tT]ime %*[bB]egin=\"%d:%d\" %*[Ee]nd=\"%d:%d\"%*[^<]<clear/>%n",
1027 &a2, &a3, &b2, &b3, &plen
1028 ))
1029 <
1030 4
1031 &&
1032 (len = sscanf
1033 (
1034 line,
1035 "<%*[tT]ime %*[bB]egin=\"%d:%d\" %*[Ee]nd=\"%d:%d.%d\"%*[^<]<clear/>%n",
1036 &a2, &a3, &b2, &b3, &b4, &plen
1037 ))
1038 <
1039 5
1040#if 0
1041 &&
1042 (len = sscanf
1043 (
1044 line,
1045 "<%*[tT]ime %*[bB]egin=\"%d:%d.%d\" %*[Ee]nd=\"%d:%d\"%*[^<]<clear/>%n",
1046 &a2, &a3, &a4, &b2, &b3, &plen
1047 ))
1048 <
1049 5
1050#endif
1051 &&
1052 (len = sscanf
1053 (
1054 line,
1055 "<%*[tT]ime %*[bB]egin=\"%d:%d.%d\" %*[Ee]nd=\"%d:%d.%d\"%*[^<]<clear/>%n",
1056 &a2, &a3, &a4, &b2, &b3, &b4, &plen
1057 ))
1058 <
1059 6
1060 &&
1061 (len = sscanf
1062 (
1063 line,
1064 "<%*[tT]ime %*[bB]egin=\"%d:%d:%d.%d\" %*[Ee]nd=\"%d:%d:%d.%d\"%*[^<]<clear/>%n",
1065 &a1, &a2, &a3, &a4, &b1, &b2, &b3, &b4, &plen
1066 ))
1067 <
1068 8
1069 &&
1070 //now try it without end time
1071 (len = sscanf
1072 (
1073 line,
1074 "<%*[tT]ime %*[bB]egin=\"%d.%d\"%*[^<]<clear/>%n",
1075 &a3, &a4, &plen
1076 ))
1077 <
1078 2
1079 &&
1080 (len = sscanf
1081 (
1082 line,
1083 "<%*[tT]ime %*[bB]egin=\"%d:%d\"%*[^<]<clear/>%n",
1084 &a2, &a3, &plen
1085 ))
1086 <
1087 2
1088 &&
1089 (len = sscanf
1090 (
1091 line,
1092 "<%*[tT]ime %*[bB]egin=\"%d:%d.%d\"%*[^<]<clear/>%n",
1093 &a2, &a3, &a4, &plen
1094 ))
1095 <
1096 3
1097 &&
1098 (len = sscanf
1099 (
1100 line,
1101 "<%*[tT]ime %*[bB]egin=\"%d:%d:%d.%d\"%*[^<]<clear/>%n",
1102 &a1, &a2, &a3, &a4, &plen
1103 ))
1104 <
1105 4
1106 )
1107 continue; /* couldn't match any of the above */
1108 current->start = a1 * 360000 + a2 * 6000 + a3 * 100 + a4 / 10;
1109 current->end = b1 * 360000 + b2 * 6000 + b3 * 100 + b4 / 10;
1110 if (b1 == 0 && b2 == 0 && b3 == 0 && b4 == 0)
1111 current->end = current->start + 200;
1112 i = 0;
1113 // TODO: I don't know what kind of convention is here for marking
1114 // multiline subs, maybe <br/> like in xml?
1115 next = strstr(line, "<clear/>");
1116 if (next && strlen(next) > 8)
1117 {
1118 next += 8; /* skip "<clear/>" tag */
1119 while ((next = sub_readtext(next, &current->text[i])) != 0)
1120 {
1121 if (current->text[i] == ERR((void *) -1))
1122 {
1123 return ERR((void *) -1);
1124 } /*if*/
1125 i++;
1126 if (i >= SUB_MAX_TEXT16)
1127 {
1128 fprintf(stderrstderr, "WARN: Too many lines in a subtitle\n");
1129 current->lines = i;
1130 return current;
1131 } /*if*/
1132 } /*while*/
1133 } /*if*/
1134 current->lines = i + 1;
1135 } /*while*/
1136 return current;
1137 } /*sub_read_line_rt*/
1138
1139subtitle_elt *sub_read_line_ssa(subtitle_elt *current)
1140 {
1141/*
1142 * Sub Station Alpha v4 (and v2?) scripts have 9 commas before subtitle
1143 * other Sub Station Alpha scripts have only 8 commas before subtitle
1144 * Reading the "ScriptType:" field is not reliable since many scripts appear
1145 * w/o it
1146 *
1147 * http://www.scriptclub.org is a good place to find more examples
1148 * http://www.eswat.demon.co.uk is where the SSA specs can be found
1149 */
1150 int comma;
1151 static int max_comma = 32; /* let's use 32 for the case that the */
1152 /* amount of commas increase with newer SSA versions */
1153
1154 int hour1, min1, sec1, hunsec1,
1155 hour2, min2, sec2, hunsec2, nothing;
1156 int num;
1157 char line[LINE_LEN1000 + 1], line3[LINE_LEN1000 + 1];
1158 const char *line2;
1159 const char *tmp;
1160 do /* look for valid timing line */
1161 {
1162 if (!sub_fgets(line, LINE_LEN1000))
1163 return NULL((void*)0);
1164 }
1165 while
1166 (
1167 sscanf
1168 (
1169 line,
1170 "Dialogue: Marked=%d,%d:%d:%d.%d,%d:%d:%d.%d,%[^\n\r]",
1171 &nothing,
1172 &hour1, &min1, &sec1, &hunsec1,
1173 &hour2, &min2, &sec2, &hunsec2,
1174 line3
1175 )
1176 <
1177 9
1178 &&
1179 sscanf
1180 (
1181 line, "Dialogue: %d,%d:%d:%d.%d,%d:%d:%d.%d,%[^\n\r]",
1182 &nothing,
1183 &hour1, &min1, &sec1, &hunsec1,
1184 &hour2, &min2, &sec2, &hunsec2,
1185 line3
1186 )
1187 <
1188 9
1189 );
1190 line2 = strchr(line3, ',')(__extension__ (__builtin_constant_p (',') && !__builtin_constant_p
(line3) && (',') == '\0' ? (char *) __rawmemchr (line3
, ',') : __builtin_strchr (line3, ',')))
;
1191 for (comma = 4; comma < max_comma; comma ++)
1192 {
1193 tmp = line2;
1194 if (!(tmp = strchr(++tmp, ',')(__extension__ (__builtin_constant_p (',') && !__builtin_constant_p
(++tmp) && (',') == '\0' ? (char *) __rawmemchr (++tmp
, ',') : __builtin_strchr (++tmp, ',')))
))
1195 break;
1196 if (*++tmp == ' ')
1197 break;
1198 /* a space after a comma means we're already in a sentence */
1199 line2 = tmp;
1200 } /*for*/
1201 if (comma < max_comma)
1202 max_comma = comma;
1203 /* eliminate the trailing comma */
1204 if (*line2 == ',')
1205 line2++;
1206 current->lines = 0;
1207 num = 0;
1208 current->start = 360000 * hour1 + 6000 * min1 + 100 * sec1 + hunsec1;
1209 current->end = 360000 * hour2 + 6000 * min2 + 100 * sec2 + hunsec2;
1210 while ((tmp = strstr(line2, "\\n")) != NULL((void*)0) || (tmp = strstr(line2, "\\N")) != NULL((void*)0))
1211 {
1212 current->text[num] = (char *)malloc(tmp - line2 + 1);
1213 strncpy(current->text[num], line2, tmp - line2)__builtin_strncpy (current->text[num], line2, tmp - line2);
1214 current->text[num][tmp - line2] = '\0';
1215 line2 = tmp + 2;
1216 num++;
1217 current->lines++;
1218 if (current->lines >= SUB_MAX_TEXT16)
1219 return current;
1220 } /*while*/
1221 current->text[num] = strdup(line2)(__extension__ (__builtin_constant_p (line2) && ((size_t
)(const void *)((line2) + 1) - (size_t)(const void *)(line2) ==
1) ? (((const char *) (line2))[0] == '\0' ? (char *) calloc (
(size_t) 1, (size_t) 1) : ({ size_t __len = strlen (line2) + 1
; char *__retval = (char *) malloc (__len); if (__retval != (
(void*)0)) __retval = (char *) memcpy (__retval, line2, __len
); __retval; })) : __strdup (line2)))
;
1222 current->lines++;
1223 return current;
1224 } /*sub_read_line_ssa*/
1225
1226void sub_pp_ssa(subtitle_elt *sub)
1227 {
1228 int l = sub->lines;
1229 const char *so, *start;
1230 char *de;
1231 while (l)
1232 {
1233 /* eliminate any text enclosed with {}, they are font and color settings */
1234 so = de = sub->text[--l];
1235 while (*so)
1236 {
1237 if (*so == '{' && so[1] == '\\')
1238 {
1239 for (start = so; *so && *so != '}'; so++);
1240 if (*so)
1241 so++;
1242 else
1243 so = start;
1244 } /*if*/
1245 if (*so)
1246 {
1247 *de = *so;
1248 so++;
1249 de++;
1250 } /*if*/
1251 } /*while*/
1252 *de = *so;
1253 } /*while*/
1254 } /*sub_pp_ssa*/
1255
1256subtitle_elt *sub_read_line_pjs(subtitle_elt *current)
1257 {
1258 char line[LINE_LEN1000 + 1];
1259 char text[LINE_LEN1000 + 1];
1260 if (!sub_fgets(line, LINE_LEN1000))
1261 return NULL((void*)0);
1262 if (sscanf(line, "%ld,%ld,\"%[^\"]", &current->start, &current->end, text) < 3)
1263 return ERR((void *) -1);
1264 current->text[0] = strdup(text)(__extension__ (__builtin_constant_p (text) && ((size_t
)(const void *)((text) + 1) - (size_t)(const void *)(text) ==
1) ? (((const char *) (text))[0] == '\0' ? (char *) calloc (
(size_t) 1, (size_t) 1) : ({ size_t __len = strlen (text) + 1
; char *__retval = (char *) malloc (__len); if (__retval != (
(void*)0)) __retval = (char *) memcpy (__retval, text, __len)
; __retval; })) : __strdup (text)))
;
1265 current->lines = 1;
1266 return current;
1267 } /*sub_read_line_pjs*/
1268
1269subtitle_elt *sub_read_line_mpsub(subtitle_elt *current)
1270 {
1271 char line[LINE_LEN1000 + 1];
1272 float startdelay, duration;
1273 int num = 0;
1274 char *p, *q;
1275 do /* look for valid timing line */
1276 {
1277 if (!sub_fgets(line, LINE_LEN1000))
1278 return NULL((void*)0);
1279 }
1280 while (sscanf(line, "%f %f", &startdelay, &duration) != 2);
1281 mpsub_position += startdelay * mpsub_multiplier;
1282 current->start = (int)mpsub_position;
1283 mpsub_position += duration * mpsub_multiplier;
1284 current->end = (int)mpsub_position;
1285 while (num < SUB_MAX_TEXT16)
1286 {
1287 if (!sub_fgets(line, LINE_LEN1000))
1288 {
1289 if (num == 0)
1290 return NULL((void*)0);
1291 else
1292 return current;
1293 } /*if*/
1294 p = line;
1295 while (isspace(*p)((*__ctype_b_loc ())[(int) ((*p))] & (unsigned short int)
_ISspace)
)
1296 p++;
1297 if (eol(*p) && num > 0)
1298 return current;
1299 if (eol(*p))
1300 return NULL((void*)0);
1301 for (q = p; !eol(*q); q++)
1302 /* look for end of line */;
1303 *q = '\0';
1304 if (strlen(p)) /* nonempty line */
1305 {
1306 current->text[num] = strdup(p)(__extension__ (__builtin_constant_p (p) && ((size_t)
(const void *)((p) + 1) - (size_t)(const void *)(p) == 1) ? (
((const char *) (p))[0] == '\0' ? (char *) calloc ((size_t) 1
, (size_t) 1) : ({ size_t __len = strlen (p) + 1; char *__retval
= (char *) malloc (__len); if (__retval != ((void*)0)) __retval
= (char *) memcpy (__retval, p, __len); __retval; })) : __strdup
(p)))
;
1307// fprintf(stderr, ">%s<\n", p);
1308 current->lines = ++num;
1309 }
1310 else
1311 {
1312 if (num)
1313 return current;
1314 else
1315 return NULL((void*)0);
1316 } /*if*/
1317 } /*while*/
1318 return NULL((void*)0); // we should have returned before if it's OK
1319 } /*sub_read_line_mpsub*/
1320
1321#ifndef USE_SORTSUB1
1322//we don't need this if we use previous_sub_end
1323static subtitle_elt *previous_aqt_sub = NULL((void*)0);
1324#endif
1325
1326subtitle_elt *sub_read_line_aqt(subtitle_elt *current)
1327 {
1328 char line[LINE_LEN1000 + 1];
1329 const char *next;
1330 int i;
1331 while (true1)
1332 {
1333 // try to locate next subtitle
1334 if (!sub_fgets(line, LINE_LEN1000))
1335 return NULL((void*)0);
1336 if (sscanf(line, "-->> %ld", &current->start) == 1)
1337 break;
1338 } /*while*/
1339#ifdef USE_SORTSUB1
1340 previous_sub_end = current->start ? current->start - 1 : 0;
1341#else
1342 if (previous_aqt_sub != NULL((void*)0))
1343 previous_aqt_sub->end = current->start - 1;
1344 previous_aqt_sub = current;
1345#endif
1346 if (!sub_fgets(line, LINE_LEN1000))
1347 return NULL((void*)0);
1348 (void)sub_readtext(line, &current->text[0]);
1349 current->lines = 1;
1350 current->end = current->start; // will be corrected by next subtitle
1351 if (!sub_fgets(line, LINE_LEN1000))
1352 return current;
1353 next = line, i = 1;
1354 while ((next = sub_readtext (next, &current->text[i])) != 0)
1355 {
1356 if (current->text[i] == ERR((void *) -1))
1357 {
1358 return ERR((void *) -1);
1359 } /*if*/
1360 i++;
1361 if (i >= SUB_MAX_TEXT16)
1362 {
1363 fprintf(stderrstderr, "WARN: Too many lines in a subtitle\n");
1364 current->lines = i;
1365 return current;
1366 } /*if*/
1367 } /*while*/
1368 current->lines = i + 1;
1369 if (current->text[0][0] == 0 && current->text[1][0] == 0)
1370 {
1371#ifdef USE_SORTSUB1
1372 previous_sub_end = 0;
1373#else
1374 // void subtitle -> end of previous marked and exit
1375 previous_aqt_sub = NULL((void*)0);
1376#endif
1377 return NULL((void*)0);
1378 } /*if*/
1379 return current;
1380 } /*sub_read_line_aqt*/
1381
1382#ifndef USE_SORTSUB1
1383static subtitle_elt *previous_subrip09_sub = NULL((void*)0);
1384#endif
1385
1386subtitle_elt *sub_read_line_subrip09(subtitle_elt *current)
1387 {
1388 char line[LINE_LEN1000 + 1];
1389 int a1, a2, a3;
1390 const char * next = NULL((void*)0);
1391 int i, len;
1392 while (true1)
1393 {
1394 // try to locate next subtitle
1395 if (!sub_fgets(line, LINE_LEN1000))
1396 return NULL((void*)0);
1397 len = sscanf(line, "[%d:%d:%d]", &a1, &a2, &a3);
1398 if (len == 3)
1399 break;
1400 } /*while*/
1401 current->start = a1 * 360000 + a2 * 6000 + a3 * 100;
1402#ifdef USE_SORTSUB1
1403 previous_sub_end = current->start ? current->start - 1 : 0;
1404#else
1405 if (previous_subrip09_sub != NULL((void*)0))
1406 previous_subrip09_sub->end = current->start - 1;
1407 previous_subrip09_sub = current;
1408#endif
1409 if (!sub_fgets(line, LINE_LEN1000))
1410 return NULL((void*)0);
1411 next = line, i = 0;
1412 while ((next = sub_readtext(next, &current->text[i])) != 0)
1413 {
1414 if (current->text[i] == ERR((void *) -1))
1415 {
1416 return ERR((void *) -1);
1417 } /*if*/
1418 i++;
1419 if (i >= SUB_MAX_TEXT16)
1420 {
1421 fprintf(stderrstderr, "WARN: Too many lines in a subtitle\n");
1422 current->lines = i;
1423 return current;
1424 } /*if*/
1425 } /*while*/
1426 current->lines = i + 1;
1427 if (current->text[0][0] == 0 && i == 0)
1428 {
1429#ifdef USE_SORTSUB1
1430 previous_sub_end = 0;
1431#else
1432 // void subtitle -> end of previous marked and exit
1433 previous_subrip09_sub = NULL((void*)0);
1434#endif
1435 return NULL((void*)0);
1436 } /*if*/
1437 return current;
1438 } /*sub_read_line_subrip09*/
1439
1440subtitle_elt *sub_read_line_jacosub(subtitle_elt * current)
1441 {
1442 char line1[LINE_LEN1000], line2[LINE_LEN1000], directive[LINE_LEN1000];
1443 unsigned a1, a2, a3, a4, b1, b2, b3, b4, comment = 0;
1444 static unsigned jacoTimeres = 30;
1445 static int jacoShift = 0;
1446 const char *p;
1447 char *q;
1448
1449 bzero(current, sizeof(subtitle_elt));
1450 bzero(line1, LINE_LEN1000);
1451 bzero(line2, LINE_LEN1000);
1452 bzero(directive, LINE_LEN1000);
1453 while (!current->text[0])
1454 {
1455 if (!sub_fgets(line1, LINE_LEN1000))
1456 {
1457 return NULL((void*)0);
1458 } /*if*/
1459 if
1460 (
1461 sscanf
1462 (
1463 line1,
1464 "%u:%u:%u.%u %u:%u:%u.%u %[^\n\r]",
1465 &a1, &a2, &a3, &a4, &b1, &b2, &b3, &b4, line2
1466 )
1467 <
1468 9
1469 )
1470 {
1471 if (sscanf(line1, "@%u @%u %[^\n\r]", &a4, &b4, line2) < 3)
1472 {
1473 if (line1[0] == '#')
1474 {
1475 int hours = 0, minutes = 0, seconds, delta, inverter = 1;
1476 unsigned units = jacoShift;
1477 switch (toupper(line1[1])(__extension__ ({ int __res; if (sizeof (line1[1]) > 1) { if
(__builtin_constant_p (line1[1])) { int __c = (line1[1]); __res
= __c < -128 || __c > 255 ? __c : (*__ctype_toupper_loc
())[__c]; } else __res = toupper (line1[1]); } else __res = (
*__ctype_toupper_loc ())[(int) (line1[1])]; __res; }))
)
1478 {
1479 case 'S':
1480 if (isalpha(line1[2])((*__ctype_b_loc ())[(int) ((line1[2]))] & (unsigned short
int) _ISalpha)
)
1481 {
1482 delta = 6;
1483 }
1484 else
1485 {
1486 delta = 2;
1487 } /*if*/
1488 if (sscanf(&line1[delta], "%d", &hours))
1489 {
1490 if (hours < 0)
1491 {
1492 hours *= -1;
1493 inverter = -1;
1494 } /*if*/
1495 if (sscanf(&line1[delta], "%*d:%d", &minutes))
1496 {
1497 if
1498 (
1499 sscanf
1500 (
1501 &line1[delta], "%*d:%*d:%d",
1502 &seconds
1503 )
1504 )
1505 {
1506 sscanf(&line1[delta], "%*d:%*d:%*d.%d", &units);
1507 }
1508 else
1509 {
1510 hours = 0;
1511 sscanf(&line1[delta], "%d:%d.%d", &minutes, &seconds, &units);
1512 minutes *= inverter;
1513 } /*if*/
1514 }
1515 else
1516 {
1517 hours = minutes = 0;
1518 sscanf(&line1[delta], "%d.%d", &seconds, &units);
1519 seconds *= inverter;
1520 } /*if*/
1521 jacoShift =
1522 (
1523 (hours * 3600 + minutes * 60 + seconds) * jacoTimeres
1524 +
1525 units
1526 )
1527 *
1528 inverter;
1529 } /*if*/
1530 break;
1531 case 'T':
1532 if (isalpha(line1[2])((*__ctype_b_loc ())[(int) ((line1[2]))] & (unsigned short
int) _ISalpha)
)
1533 {
1534 delta = 8;
1535 }
1536 else
1537 {
1538 delta = 2;
1539 } /*if*/
1540 sscanf(&line1[delta], "%u", &jacoTimeres);
1541 break;
1542 } /*switch*/
1543 } /*if*/
1544 continue;
1545 }
1546 else /* timing line */
1547 {
1548 current->start =
1549 (unsigned long)((a4 + jacoShift) * 100.0 / jacoTimeres);
1550 current->end =
1551 (unsigned long)((b4 + jacoShift) * 100.0 / jacoTimeres);
1552 } /*if*/
1553 }
1554 else /* timing line */
1555 {
1556 current->start =
1557 (unsigned long)
1558 (
1559 ((a1 * 3600 + a2 * 60 + a3) * jacoTimeres + a4 + jacoShift)
1560 *
1561 100.0
1562 /
1563 jacoTimeres
1564 );
1565 current->end =
1566 (unsigned long)
1567 (
1568 ((b1 * 3600 + b2 * 60 + b3) * jacoTimeres + b4 + jacoShift)
1569 *
1570 100.0
1571 /
1572 jacoTimeres
1573 );
1574 } /*if*/
1575 current->lines = 0;
1576 p = line2;
1577 while (*p == ' ' || *p == '\t')
1578 {
1579 ++p; /* ignore leading whitespace */
1580 } /*while*/
1581 if (isalpha(*p)((*__ctype_b_loc ())[(int) ((*p))] & (unsigned short int)
_ISalpha)
|| *p == '[')
1582 {
1583 int cont, jLength;
1584 if (sscanf(p, "%s %[^\n\r]", directive, line1) < 2)
1585 return (subtitle_elt *)ERR((void *) -1);
1586 jLength = strlen(directive);
1587 for (cont = 0; cont < jLength; ++cont)
1588 {
1589 if (isalpha(directive[cont])((*__ctype_b_loc ())[(int) ((directive[cont]))] & (unsigned
short int) _ISalpha)
)
1590 directive[cont] = toupper(directive[cont])(__extension__ ({ int __res; if (sizeof (directive[cont]) >
1) { if (__builtin_constant_p (directive[cont])) { int __c =
(directive[cont]); __res = __c < -128 || __c > 255 ? __c
: (*__ctype_toupper_loc ())[__c]; } else __res = toupper (directive
[cont]); } else __res = (*__ctype_toupper_loc ())[(int) (directive
[cont])]; __res; }))
;
1591 } /*for*/
1592 if
1593 (
1594 strstr(directive, "RDB") != NULL((void*)0)
1595 ||
1596 strstr(directive, "RDC") != NULL((void*)0)
1597 ||
1598 strstr(directive, "RLB") != NULL((void*)0)
1599 ||
1600 strstr(directive, "RLG") != NULL((void*)0)
1601 )
1602 {
1603 continue;
1604 } /*if*/
1605 if (strstr(directive, "JL") != NULL((void*)0))
1606 {
1607 current->alignment = H_SUB_ALIGNMENT_LEFT;
1608 }
1609 else if (strstr(directive, "JR") != NULL((void*)0))
1610 {
1611 current->alignment = H_SUB_ALIGNMENT_RIGHT;
1612 }
1613 else
1614 {
1615 current->alignment = H_SUB_ALIGNMENT_CENTER;
1616 } /*if*/
1617 strcpy(line2, line1);
1618 p = line2;
1619 } /*if*/
1620 for (q = line1; !eol(*p) && current->lines < SUB_MAX_TEXT16; ++p)
1621 { /* collect text from p into q */
1622 switch (*p)
1623 {
1624 case '{':
1625 comment++;
1626 break;
1627 case '}':
1628 if (comment)
1629 {
1630 --comment;
1631 //the next line to get rid of a blank after the comment
1632 if (p[1] == ' ')
1633 p++;
1634 } /*if*/
1635 break;
1636 case '~':
1637 if (!comment)
1638 {
1639 *q = ' ';
1640 ++q;
1641 } /*if*/
1642 break;
1643 case ' ':
1644 case '\t':
1645 if (p[1] == ' ' || p[1] == '\t') /* ignore duplicated space/tab */
1646 break;
1647 if (!comment)
1648 {
1649 *q = ' '; /* whitespace => single space */
1650 ++q;
1651 } /*if*/
1652 break;
1653 case '\\':
1654 if (p[1] == 'n') /* non-literal line break */
1655 {
1656 *q = '\0';
1657 q = line1;
1658 current->text[current->lines++] = strdup(line1)(__extension__ (__builtin_constant_p (line1) && ((size_t
)(const void *)((line1) + 1) - (size_t)(const void *)(line1) ==
1) ? (((const char *) (line1))[0] == '\0' ? (char *) calloc (
(size_t) 1, (size_t) 1) : ({ size_t __len = strlen (line1) + 1
; char *__retval = (char *) malloc (__len); if (__retval != (
(void*)0)) __retval = (char *) memcpy (__retval, line1, __len
); __retval; })) : __strdup (line1)))
;
1659 ++p;
1660 break;
1661 } /*if*/
1662 if (toupper(p[1])(__extension__ ({ int __res; if (sizeof (p[1]) > 1) { if (
__builtin_constant_p (p[1])) { int __c = (p[1]); __res = __c <
-128 || __c > 255 ? __c : (*__ctype_toupper_loc ())[__c];
} else __res = toupper (p[1]); } else __res = (*__ctype_toupper_loc
())[(int) (p[1])]; __res; }))
== 'C' || toupper(p[1])(__extension__ ({ int __res; if (sizeof (p[1]) > 1) { if (
__builtin_constant_p (p[1])) { int __c = (p[1]); __res = __c <
-128 || __c > 255 ? __c : (*__ctype_toupper_loc ())[__c];
} else __res = toupper (p[1]); } else __res = (*__ctype_toupper_loc
())[(int) (p[1])]; __res; }))
== 'F')
1663 {
1664 ++p, ++p; /* ignore following character as well */
1665 break;
1666 } /*if*/
1667 if
1668 (
1669 p[1] == 'B'
1670 ||
1671 p[1] == 'b'
1672 ||
1673 p[1] == 'D'
1674 || //actually this means "insert current date here"
1675 p[1] == 'I'
1676 ||
1677 p[1] == 'i'
1678 ||
1679 p[1] == 'N'
1680 ||
1681 p[1] == 'T'
1682 || //actually this means "insert current time here"
1683 p[1] == 'U'
1684 ||
1685 p[1] == 'u'
1686 )
1687 {
1688 ++p; /* ignore */
1689 break;
1690 } /*if*/
1691 if
1692 (
1693 p[1] == '\\'
1694 ||
1695 p[1] == '~'
1696 ||
1697 p[1] == '{'
1698 )
1699 {
1700 ++p; /* fallthrough to insert char following "\" literally */
1701 }
1702 else if (eol(p[1]))
1703 {
1704 if (!sub_fgets(directive, LINE_LEN1000))
1705 return NULL((void*)0);
1706 trail_space(directive);
1707 strconcat(line2, LINE_LEN1000, directive);
1708 break;
1709 } /*if*/
1710 /* fallthrough */
1711 default: /* copy character *p literally */
1712 if (!comment)
1713 {
1714 *q = *p;
1715 ++q;
1716 } /*if*/
1717 } /*switch*/
1718 } /*for*/
1719 *q = '\0';
1720 current->text[current->lines] = strdup(line1)(__extension__ (__builtin_constant_p (line1) && ((size_t
)(const void *)((line1) + 1) - (size_t)(const void *)(line1) ==
1) ? (((const char *) (line1))[0] == '\0' ? (char *) calloc (
(size_t) 1, (size_t) 1) : ({ size_t __len = strlen (line1) + 1
; char *__retval = (char *) malloc (__len); if (__retval != (
(void*)0)) __retval = (char *) memcpy (__retval, line1, __len
); __retval; })) : __strdup (line1)))
;
1721 } /*while*/
1722 current->lines++;
1723 return current;
1724 } /*sub_read_line_jacosub*/
1725
1726static int sub_autodetect(bool_Bool * uses_time)
1727 /* scans the first few lines of the file to try to determine what format it is. */
1728 {
1729 char line[LINE_LEN1000 + 1];
1730 int i, j = 0;
1731 char p;
1732 while (j < 100)
1733 {
1734 j++;
1735 if (!sub_fgets(line, LINE_LEN1000))
1736 return SUB_INVALID-1;
1737 if (sscanf(line, "{%d}{%d}", &i, &i) == 2)
1738 {
1739 *uses_time = false0;
1740 return SUB_MICRODVD0;
1741 } /*if*/
1742 if (sscanf(line, "{%d}{}", &i) == 1)
1743 {
1744 *uses_time = false0;
1745 return SUB_MICRODVD0;
1746 } /*if*/
1747 if (sscanf(line, "%d:%d:%d.%d,%d:%d:%d.%d", &i, &i, &i, &i, &i, &i, &i, &i) == 8)
1748 {
1749 *uses_time = true1;
1750 return SUB_SUBRIP1;
1751 } /*if*/
1752 if
1753 (
1754 sscanf
1755 (
1756 line,
1757 "%d:%d:%d%[,.:]%d --> %d:%d:%d%[,.:]%d",
1758 &i, &i, &i, (char *)&i, &i, &i, &i, &i, (char *)&i, &i
1759 )
1760 ==
1761 10
1762 )
1763 {
1764 *uses_time = true1;
1765 return SUB_SUBVIEWER2;
1766 } /*if*/
1767 if (sscanf(line, "{T %d:%d:%d:%d", &i, &i, &i, &i))
1768 {
1769 *uses_time = true1;
1770 return SUB_SUBVIEWER210;
1771 } /*if*/
1772 if (strstr(line, "<SAMI>"))
1773 {
1774 *uses_time = true1;
1775 return SUB_SAMI3;
1776 } /*if*/
1777 if (sscanf(line, "%d:%d:%d.%d %d:%d:%d.%d", &i, &i, &i, &i, &i, &i, &i, &i) == 8)
1778 {
1779 *uses_time = true1;
1780 return SUB_JACOSUB12;
1781 } /*if*/
1782 if (sscanf(line, "@%d @%d", &i, &i) == 2)
1783 {
1784 *uses_time = true1;
1785 return SUB_JACOSUB12;
1786 } /*if*/
1787 if (sscanf(line, "%d:%d:%d:", &i, &i, &i ) == 3)
1788 {
1789 *uses_time = true1;
1790 return SUB_VPLAYER4;
1791 } /*if*/
1792 if (sscanf(line, "%d:%d:%d ", &i, &i, &i ) == 3)
1793 {
1794 *uses_time = true1;
1795 return SUB_VPLAYER4;
1796 } /*if*/
1797 //TODO: just checking if first line of sub starts with "<" is WAY
1798 // too weak test for RT
1799 // Please someone who knows the format of RT... FIX IT!!!
1800 // It may conflict with other sub formats in the future (actually it doesn't)
1801 if (*line == '<')
1802 {
1803 *uses_time = true1;
1804 return SUB_RT5;
1805 } /*if*/
1806 if (!memcmp(line, "Dialogue: Marked", 16))
1807 {
1808 *uses_time = true1;
1809 return SUB_SSA6;
1810 } /*if*/
1811 if (!memcmp(line, "Dialogue: ", 10))
1812 {
1813 *uses_time = true1;
1814 return SUB_SSA6;
1815 } /*if*/
1816 if (sscanf(line, "%d,%d,\"%c", &i, &i, (char *)&i) == 3)
1817 {
1818 *uses_time = false0;
1819 return SUB_PJS7;
1820 } /*if*/
1821 if (sscanf(line, "FORMAT=%d", &i) == 1)
1822 {
1823 *uses_time = false0; /* actually means that durations are in seconds */
1824 return SUB_MPSUB8;
1825 } /*if*/
1826 if (sscanf(line, "FORMAT=TIM%c", &p) == 1 && p == 'E')
1827 {
1828 *uses_time = true1; /* actually means that durations are in hundredths of a second */
1829 return SUB_MPSUB8;
1830 } /*if*/
1831 if (strstr(line, "-->>"))
1832 {
1833 *uses_time = false0;
1834 return SUB_AQTITLE9;
1835 } /*if*/
1836 if (sscanf(line, "[%d:%d:%d]", &i, &i, &i) == 3)
1837 {
1838 *uses_time = true1;
1839 return SUB_SUBRIP0911;
1840 } /*if*/
1841 } /*while*/
1842 return SUB_INVALID-1; // too many bad lines
1843 } /*sub_autodetect*/
1844
1845/*
1846 Common subtitle-handling code
1847*/
1848
1849static void adjust_subs_time
1850 (
1851 subtitle_elt * sub, /* array of subtitle_elts */
1852 float subtime, /* duration to truncate overlapping subtitle to--why? */
1853 float fps,
1854 int block, /* whether to check for overlapping subtitles (false if caller will fix them up) */
1855 int sub_num, /* nr entries in sub array */
1856 bool_Bool sub_uses_time
1857 )
1858 /* adjusts for overlapping subtitle durations, and also for sub_fps if specified. */
1859 {
1860 int nradjusted, adjusted;
1861 subtitle_elt * nextsub;
1862 int i = sub_num;
1863 unsigned long const subfms = (sub_uses_time ? 100 : fps) * subtime;
1864 /* subtime converted to subtitle duration units */
1865 unsigned long const short_overlap = (sub_uses_time ? 100 : fps) / 5; // 0.2s
1866 nradjusted = 0;
1867 if (i)
1868 for (;;)
1869 {
1870 adjusted = 0; /* to begin with */
1871 if (sub->end <= sub->start)
1872 {
1873 sub->end = sub->start + subfms;
1874 adjusted++;
1875 nradjusted++;
1876 } /*if*/
1877 if (!--i)
1878 break; /* no nextsub */
1879 nextsub = sub + 1;
1880 if (block)
1881 {
1882 if (sub->end > nextsub->start && sub->end <= nextsub->start + short_overlap)
1883 {
1884 // these subtitles overlap for less than 0.2 seconds
1885 // and would result in very short overlapping subtitle
1886 // so let's fix the problem here, before overlapping code
1887 // get its hands on them
1888 const unsigned delta = sub->end - nextsub->start, half = delta / 2;
1889 /* remove the overlap by splitting the difference */
1890 sub->end -= half + 1;
1891 nextsub->start += delta - half;
1892 } /*if*/
1893 if (sub->end >= nextsub->start)
1894 {
1895 /* either exact abut, or overlap by more than short_overlap */
1896 sub->end = nextsub->start - 1;
1897 if (sub->end - sub->start > subfms)
1898 sub->end = sub->start + subfms;
1899 /* maximum subtitle duration -- why? */
1900 if (!adjusted)
1901 nradjusted++;
1902 } /*if*/
1903 } /*if*/
1904 /* Theory:
1905 * Movies are often converted from FILM (24 fps)
1906 * to PAL (25) by simply speeding it up, so we
1907 * to multiply the original timestmaps by
1908 * (Movie's FPS / Subtitle's (guessed) FPS)
1909 * so eg. for 23.98 fps movie and PAL time based
1910 * subtitles we say -subfps 25 and we're fine!
1911 */
1912 /* timed sub fps correction ::atmos */
1913 if (sub_uses_time && sub_fps)
1914 {
1915 sub->start *= sub_fps / fps;
1916 sub->end *= sub_fps / fps;
1917 } /*if*/
1918 sub = nextsub;
1919 } /*for; if*/
1920 if (nradjusted != 0)
1921 fprintf(stderrstderr, "INFO: Adjusted %d subtitle(s).\n", nradjusted);
1922 } /*adjust_subs_time*/
1923
1924struct subreader { /* describes a subtitle format */
1925 subtitle_elt * (*read)(subtitle_elt *dest); /* file reader routine */
1926 void (*post)(subtitle_elt *dest); /* optional post-processor routine */
1927 const char *name; /* descriptive name */
1928};
1929
1930sub_data *sub_read_file(const char *filename, float movie_fps)
1931 /* parses the contents of filename, auto-recognizing the subtitle file format,
1932 and returns the result. The subtitles will be translated from the subtitle_charset
1933 character set to Unicode if specified, unless the file name ends in ".utf",
1934 ".utf8" or ".utf-8" (case-insensitive), in which case they will be assumed
1935 to already be in UTF-8. movie_fps is the movie frame rate, needed for subtitle
1936 formats which specify fractional-second durations in frames. */
1937 {
1938 //filename is assumed to be malloc'ed, free() is used in sub_free()
1939 int sub_format;
1940 int n_max;
1941 subtitle_elt *first, *second, *new_sub, *return_sub;
1942#ifdef USE_SORTSUB1
1943 subtitle_elt temp_sub;
1944#endif
1945 sub_data *subt_data;
1946 bool_Bool uses_time = false0;
1947 int sub_num = 0, sub_errs = 0;
1948 struct subreader const sr[] =
1949 /* all the subtitle formats I know about, indexed by the codes defined in subreader.h */
1950 {
1951 {sub_read_line_microdvd, NULL((void*)0), "microdvd"},
1952 {sub_read_line_subrip, NULL((void*)0), "subrip"},
1953 {sub_read_line_subviewer, NULL((void*)0), "subviewer"},
1954 {sub_read_line_sami, NULL((void*)0), "sami"},
1955 {sub_read_line_vplayer, NULL((void*)0), "vplayer"},
1956 {sub_read_line_rt, NULL((void*)0), "rt"},
1957 {sub_read_line_ssa, sub_pp_ssa, "ssa"},
1958 {sub_read_line_pjs, NULL((void*)0), "pjs"},
1959 {sub_read_line_mpsub, NULL((void*)0), "mpsub"},
1960 {sub_read_line_aqt, NULL((void*)0), "aqt"},
1961 {sub_read_line_subviewer2, NULL((void*)0), "subviewer 2.0"},
1962 {sub_read_line_subrip09, NULL((void*)0), "subrip 0.9"},
1963 {sub_read_line_jacosub, NULL((void*)0), "jacosub"},
1964 };
1965 const struct subreader *srp; /* the autodetected format */
1966
1967 if (filename == NULL((void*)0))
1
Assuming 'filename' is not equal to null
2
Taking false branch
1968 return NULL((void*)0); //qnx segfault
1969 sub_open(filename);
1970#ifdef HAVE_ICONV1
1971 {
1972 int l, k;
1973 k = -1;
1974 l = strlen(filename);
1975 if (l > 4) /* long enough to have an extension */
3
Assuming 'l' is <= 4
4
Taking false branch
1976 {
1977 const char * const exts[] = {".utf", ".utf8", ".utf-8"};
1978 /* if filename ends with one of these extensions, then its contents
1979 are assumed to be in UTF-8 encoding, and subtitle_charset is ignored */
1980 for (k = 3; --k >= 0;)
1981 if (l > strlen(exts[k]) && !strcasecmp(filename + (l - strlen(exts[k])), exts[k]))
1982 {
1983 break;
1984 } /*if; for*/
1985 } /*if*/
1986 if (k < 0) /* assume it's not UTF-8 */
5
Taking true branch
1987 subcp_open(); /* to convert the text to UTF-8 */
1988 }
1989#endif
1990 sub_buf_rewindable = true1;
1991 sub_format = sub_autodetect(&uses_time);
1992 mpsub_multiplier = (uses_time ? 100.0 : 1.0);
6
Assuming 'uses_time' is 0
7
'?' condition is false
1993 if (sub_format == SUB_INVALID-1)
8
Taking false branch
1994 {
1995 fprintf(stderrstderr, "ERR: Could not determine format of subtitle file \"%s\"\n", filename);
1996 exit(1);
1997 } /*if*/
1998 srp = sr + sub_format;
1999 fprintf(stderrstderr, "INFO: Detected subtitle file format: %s\n", srp->name);
2000 sub_rewind();
2001 sub_buf_rewindable = false0;
2002 sub_num = 0;
2003 n_max = 32; /* initial size of "first" array */
2004 first = (subtitle_elt *)malloc(n_max * sizeof(subtitle_elt));
2005 /* fixme: don't bother recovering from any of the following allocation etc failures, just die */
2006 if(!first)
9
Assuming 'first' is non-null
10
Taking false branch
2007 {
2008#ifdef HAVE_ICONV1
2009 subcp_close();
2010#endif
2011 return NULL((void*)0);
2012 } /*if*/
2013#ifdef USE_SORTSUB1
2014 //This is to deal with those formats (AQT & Subrip) which define the end of a subtitle
2015 //as the beginning of the following
2016 previous_sub_end = 0;
2017#endif
2018 while (true1)
11
Loop condition is true. Entering loop body
24
Loop condition is true. Entering loop body
38
Loop condition is true. Entering loop body
52
Loop condition is true. Entering loop body
2019 {
2020 /* read subtitle entries from input file */
2021 if (sub_num == n_max) /* need more room in "first" array */
12
Taking false branch
25
Taking false branch
39
Taking false branch
53
Taking false branch
2022 {
2023 n_max += 16;
2024 first = realloc(first, n_max * sizeof(subtitle_elt));
2025 } /*if*/
2026#ifdef USE_SORTSUB1
2027 new_sub = &temp_sub;
2028 /* temporary holding area before copying entry into right place in first array */
2029#else
2030 new_sub = &first[sub_num];
2031 /* just put it directly on the end */
2032#endif
2033 memset(new_sub, '\0', sizeof(subtitle_elt));
2034 new_sub = srp->read(new_sub);
2035 if (!new_sub)
13
Assuming 'new_sub' is non-null
14
Taking false branch
26
Assuming 'new_sub' is non-null
27
Taking false branch
40
Assuming 'new_sub' is non-null
41
Taking false branch
54
Assuming 'new_sub' is null
55
Taking true branch
2036 break; // EOF
56
Execution continues on line 2118
2037 if (h_sub_alignment != H_SUB_ALIGNMENT_DEFAULT)
15
Assuming 'h_sub_alignment' is equal to H_SUB_ALIGNMENT_DEFAULT
16
Taking false branch
28
Assuming 'h_sub_alignment' is equal to H_SUB_ALIGNMENT_DEFAULT
29
Taking false branch
42
Assuming 'h_sub_alignment' is equal to H_SUB_ALIGNMENT_DEFAULT
43
Taking false branch
2038 {
2039 new_sub->alignment = h_sub_alignment; /* override settings from subtitle file */
2040 } /*if*/
2041#ifdef HAVE_FRIBIDI1
2042 if (new_sub != ERR((void *) -1))
17
Taking true branch
30
Taking true branch
44
Taking true branch
2043 new_sub = sub_fribidi(new_sub);
2044#endif
2045 if (new_sub == ERR((void *) -1))
18
Taking false branch
31
Taking false branch
45
Taking false branch
2046 {
2047#ifdef HAVE_ICONV1
2048 subcp_close();
2049#endif
2050 if (first)
2051 free(first);
2052 return NULL((void*)0);
2053 } /*if*/
2054 // Apply any post processing that needs recoding first
2055 if (new_sub != ERR((void *) -1) && !sub_no_text_pp && srp->post)
19
Assuming 'sub_no_text_pp' is not equal to 0
32
Assuming 'sub_no_text_pp' is not equal to 0
46
Assuming 'sub_no_text_pp' is not equal to 0
2056 srp->post(new_sub);
2057#ifdef USE_SORTSUB1
2058 /* fixme: this will all crash if new_sub == ERR */
2059 if (!sub_num || first[sub_num - 1].start <= new_sub->start)
33
Taking true branch
47
Taking true branch
2060 {
2061 /* append contents of new_sub to first */
2062 int i;
2063 first[sub_num].start = new_sub->start;
2064 first[sub_num].end = new_sub->end;
2065 first[sub_num].lines = new_sub->lines;
2066 first[sub_num].alignment = new_sub->alignment;
2067 for (i = 0; i < new_sub->lines; ++i)
20
Loop condition is false. Execution continues on line 2071
34
Loop condition is false. Execution continues on line 2071
48
Loop condition is false. Execution continues on line 2071
2068 {
2069 first[sub_num].text[i] = new_sub->text[i];
2070 }/*for*/
2071 if (previous_sub_end)
21
Assuming 'previous_sub_end' is 0
22
Taking false branch
35
Assuming 'previous_sub_end' is 0
36
Taking false branch
49
Assuming 'previous_sub_end' is 0
50
Taking false branch
2072 {
2073 first[sub_num - 1].end = previous_sub_end;
2074 previous_sub_end = 0;
2075 } /*if*/
2076 }
2077 else
2078 {
2079 /* insert new_sub into first to keep it sorted by start time */
2080 int i, j;
2081 for (j = sub_num - 1; j >= 0; --j)
2082 {
2083 first[j + 1].start = first[j].start;
2084 first[j + 1].end = first[j].end;
2085 first[j + 1].lines = first[j].lines;
2086 first[j + 1].alignment = first[j].alignment;
2087 for (i = 0; i < first[j].lines; ++i)
2088 {
2089 first[j + 1].text[i] = first[j].text[i];
2090 } /*for*/
2091 if (!j || first[j - 1].start <= new_sub->start)
2092 {
2093 first[j].start = new_sub->start;
2094 first[j].end = new_sub->end;
2095 first[j].lines = new_sub->lines;
2096 first[j].alignment = new_sub->alignment;
2097 for (i = 0; i < SUB_MAX_TEXT16; ++i)
2098 {
2099 first[j].text[i] = new_sub->text[i];
2100 } /*for*/
2101 if (previous_sub_end)
2102 {
2103 first[j].end = first[j - 1].end;
2104 first[j - 1].end = previous_sub_end;
2105 previous_sub_end = 0;
2106 } /*if*/
2107 break;
2108 } /*if*/
2109 } /*for*/
2110 } /*if*/
2111#endif
2112 if (new_sub == ERR((void *) -1))
23
Taking false branch
37
Taking false branch
51
Taking false branch
2113 ++sub_errs;
2114 else
2115 ++sub_num; // Error vs. Valid
2116 } /*while*/
2117#ifdef HAVE_ICONV1
2118 subcp_close();
2119#endif
2120 sub_close();
2121// fprintf(stderr, "SUB: Subtitle format %s time.\n", uses_time ? "uses" : "doesn't use");
2122 fprintf(stderrstderr, "INFO: Read %i subtitles\n", sub_num);
2123 if (sub_errs)
57
Taking false branch
2124 fprintf(stderrstderr, "INFO: %i bad line(s).\n", sub_errs);
2125 if (sub_num <= 0)
58
Taking false branch
2126 {
2127 free(first);
2128 return NULL((void*)0);
2129 } /*if*/
2130 // we do overlap if the user forced it (suboverlap_enable == 2) or
2131 // the user didn't forced no-overlapsub and the format is Jacosub or Ssa.
2132 // this is because usually overlapping subtitles are found in these formats,
2133 // while in others they are probably result of bad timing
2134 if
2135 (
2136 suboverlap_enabled == 2
59
Assuming 'suboverlap_enabled' is equal to 2
2137 ||
2138 suboverlap_enabled
2139 &&
2140 (sub_format == SUB_JACOSUB12 || sub_format == SUB_SSA6)
2141 )
2142 {
2143 // here we manage overlapping subtitles
2144 int n_first, sub_first, sub_orig, i, j;
2145 adjust_subs_time(first, 6.0, movie_fps, 0, sub_num, uses_time); /*~6 secs AST*/
2146 sub_orig = sub_num;
2147 n_first = sub_num;
2148 sub_num = 0;
2149 second = NULL((void*)0);
2150 // for each subtitle in first[] we deal with its 'block' of
2151 // bonded subtitles
2152 for (sub_first = 0; sub_first < n_first; ++sub_first)
60
Loop condition is true. Entering loop body
2153 {
2154 unsigned long
2155 global_start = first[sub_first].start,
2156 global_end = first[sub_first].end,
2157 local_start,
2158 local_end;
2159 int
2160 lines_to_add = first[sub_first].lines, /* total nr lines in block */
2161 sub_to_add = 0,
2162 **placeholder = NULL((void*)0),
2163 highest_line = 0,
2164 nr_placeholder_entries,
2165 subs_done;
2166 const int
2167 start_block_sub = sub_num;
2168 bool_Bool real_block = true1;
2169 // here we find the number of subtitles inside the 'block'
2170 // and its span interval. this works well only with sorted
2171 // subtitles
2172 while
61
Loop condition is false. Execution continues on line 2194
2173 (
2174 sub_first + sub_to_add + 1 < n_first
2175 &&
2176 first[sub_first + sub_to_add + 1].start < global_end
2177 )
2178 {
2179 /* another subtitle overlapping sub_first--include in block */
2180 ++sub_to_add;
2181 lines_to_add += first[sub_first + sub_to_add].lines;
2182 /* extend block duration to include this subtitle: */
2183 if (first[sub_first + sub_to_add].start < global_start)
2184 {
2185 global_start = first[sub_first + sub_to_add].start;
2186 } /*if*/
2187 if (first[sub_first + sub_to_add].end > global_end)
2188 {
2189 global_end = first[sub_first + sub_to_add].end;
2190 } /*if*/
2191 } /*while*/
2192 // we need a structure to keep trace of the screen lines
2193 // used by the subs, a 'placeholder'
2194 nr_placeholder_entries = 2 * sub_to_add + 1;
2195 // the maximum number of subs derived from a block of sub_to_add + 1 subs
2196 /* fixme: but only two entries are ever accessed in the following loop:
2197 the previous one and the current one */
2198 placeholder = (int **)malloc(sizeof(int *) * nr_placeholder_entries);
2199 for (i = 0; i < nr_placeholder_entries; ++i)
62
Loop condition is true. Entering loop body
2200 {
2201 placeholder[i] = (int *)malloc(sizeof(int) * lines_to_add);
63
Call to 'malloc' has an allocation size of 0 bytes
2202 for (j = 0; j < lines_to_add; ++j)
2203 {
2204 placeholder[i][j] = -1;
2205 } /*for*/
2206 } /*for*/
2207 subs_done = 0;
2208 local_end = global_start - 1;
2209 do
2210 {
2211 // here we find the beginning and the end of a new
2212 // subtitle in the block
2213 local_start = local_end + 1; /* start after previous duration done */
2214 local_end = global_end;
2215 for (j = 0; j <= sub_to_add; ++j)
2216 {
2217 if
2218 (
2219 first[sub_first + j].start - 1 > local_start
2220 &&
2221 first[sub_first + j].start - 1 < local_end
2222 )
2223 {
2224 local_end = first[sub_first + j].start - 1;
2225 /* local_end becomes earliest start if after local_start? */
2226 }
2227 else if
2228 (
2229 first[sub_first + j].end > local_start
2230 &&
2231 first[sub_first + j].end < local_end
2232 )
2233 {
2234 local_end = first[sub_first + j].end;
2235 /* local_end becomes earliest end if after local_start? */
2236 } /*if*/
2237 } /*for*/
2238 // here we allocate the screen lines to subs we must
2239 // display in current local_start-local_end interval.
2240 // if the subs were yet presents in the previous interval
2241 // they keep the same lines, otherside they get unused lines
2242 for (j = 0; j <= sub_to_add; ++j)
2243 {
2244 if
2245 (
2246 first[sub_first + j].start <= local_end
2247 &&
2248 first[sub_first + j].end > local_start
2249 )
2250 {
2251 /* this one overlaps (local_start .. local_end] */
2252 const unsigned long sub_lines = first[sub_first + j].lines;
2253 unsigned long
2254 fragment_length = lines_to_add + 1,
2255 blank_lines_avail = 0;
2256 bool_Bool wasinprev = false0;
2257 int fragment_position = -1;
2258 // if this is not the first new sub of the block
2259 // we find if this sub was present in the previous
2260 // new sub
2261 if (subs_done)
2262 for (i = 0; i < lines_to_add; ++i)
2263 {
2264 if (placeholder[subs_done - 1][i] == sub_first + j)
2265 {
2266 placeholder[subs_done][i] = sub_first + j;
2267 wasinprev = true1;
2268 } /*if*/
2269 } /*for; if*/
2270 if (wasinprev)
2271 continue; /* already processed this subtitle */
2272 // we are looking for the shortest among all groups of
2273 // sequential blank lines whose length is greater than or
2274 // equal to sub_lines. we store in fragment_position the
2275 // position of the shortest group, in fragment_length its
2276 // length, and in blank_lines_avail the length of the group currently
2277 // examined
2278 for (i = 0; i < lines_to_add; ++i)
2279 {
2280 if (placeholder[subs_done][i] == -1)
2281 {
2282 // placeholder[subs_done][i] is part of the current group
2283 // of blank lines
2284 ++blank_lines_avail;
2285 }
2286 else /* end of a run of empty lines */
2287 {
2288 if (blank_lines_avail == sub_lines)
2289 {
2290 // current group's size fits exactly the one we
2291 // need, so we stop looking
2292 fragment_position = i - blank_lines_avail;
2293 /* starting line position */
2294 blank_lines_avail = 0;
2295 break;
2296 } /*if*/
2297 if
2298 (
2299 blank_lines_avail
2300 &&
2301 blank_lines_avail > sub_lines
2302 &&
2303 blank_lines_avail < fragment_length
2304 )
2305 {
2306 // current group is the best we found till here,
2307 // but is still bigger than the one we are looking
2308 // for, so we keep on looking
2309 fragment_length = blank_lines_avail;
2310 fragment_position = i - blank_lines_avail;
2311 blank_lines_avail = 0;
2312 }
2313 else
2314 {
2315 // current group doesn't fit at all, so we forget it
2316 blank_lines_avail = 0;
2317 } /*if*/
2318 } /*if*/
2319 } /*for*/
2320 if (blank_lines_avail)
2321 {
2322 // last screen line is blank, a group ends with it
2323 if
2324 (
2325 blank_lines_avail >= sub_lines
2326 &&
2327 blank_lines_avail < fragment_length
2328 )
2329 {
2330 fragment_position = i - blank_lines_avail;
2331 } /*if*/
2332 } /*if*/
2333 if (fragment_position == -1)
2334 {
2335 // it was not possible to find free screen line(s) for a subtitle,
2336 // usually this means a bug in the code; however we do not overlap
2337 fprintf
2338 (
2339 stderrstderr,
2340 "WARN: We could not find a suitable position for an"
2341 " overlapping subtitle\n"
2342 );
2343 highest_line = SUB_MAX_TEXT16 + 1;
2344 break;
2345 }
2346 else /* found a place to put it */
2347 {
2348 int k;
2349 for (k = 0; k < sub_lines; ++k)
2350 {
2351 placeholder[subs_done][fragment_position + k] = sub_first + j;
2352 } /*for*/
2353 } /*if*/
2354 } /*if*/
2355 } /*for*/
2356 for (j = highest_line + 1; j < lines_to_add; ++j)
2357 {
2358 if (placeholder[subs_done][j] != -1)
2359 highest_line = j; /* highest nonblank line within block */
2360 else
2361 break;
2362 } /*for*/
2363 if (highest_line >= SUB_MAX_TEXT16)
2364 {
2365 // the 'block' has too much lines, so we don't overlap the
2366 // subtitles
2367 second = (subtitle_elt *)realloc
2368 (
2369 second,
2370 (sub_num + sub_to_add + 1) * sizeof(subtitle_elt)
2371 );
2372 for (j = 0; j <= sub_to_add; ++j)
2373 {
2374 int ls;
2375 memset(&second[sub_num + j], '\0', sizeof(subtitle_elt));
2376 second[sub_num + j].start = first[sub_first + j].start;
2377 second[sub_num + j].end = first[sub_first + j].end;
2378 second[sub_num + j].lines = first[sub_first + j].lines;
2379 second[sub_num + j].alignment = first[sub_first + j].alignment;
2380 for (ls = 0; ls < second[sub_num + j].lines; ls++)
2381 {
2382 second[sub_num + j].text[ls] = strdup(first[sub_first + j].text[ls])(__extension__ (__builtin_constant_p (first[sub_first + j].text
[ls]) && ((size_t)(const void *)((first[sub_first + j
].text[ls]) + 1) - (size_t)(const void *)(first[sub_first + j
].text[ls]) == 1) ? (((const char *) (first[sub_first + j].text
[ls]))[0] == '\0' ? (char *) calloc ((size_t) 1, (size_t) 1) :
({ size_t __len = strlen (first[sub_first + j].text[ls]) + 1
; char *__retval = (char *) malloc (__len); if (__retval != (
(void*)0)) __retval = (char *) memcpy (__retval, first[sub_first
+ j].text[ls], __len); __retval; })) : __strdup (first[sub_first
+ j].text[ls])))
;
2383 } /*for*/
2384 } /*for*/
2385 sub_num += sub_to_add + 1;
2386 sub_first += sub_to_add;
2387 real_block = false0;
2388 break;
2389 } /*if*/
2390 // we read the placeholder structure and create the new subs.
2391 second = (subtitle_elt *)realloc(second, (sub_num + 1) * sizeof(subtitle_elt));
2392 memset(&second[sub_num], '\0', sizeof(subtitle_elt));
2393 second[sub_num].start = local_start;
2394 second[sub_num].end = local_end;
2395 second[sub_num].alignment = H_SUB_ALIGNMENT_CENTER;
2396 n_max = (lines_to_add < SUB_MAX_TEXT16) ? lines_to_add : SUB_MAX_TEXT16;
2397 for (i = 0, j = 0; j < n_max; ++j)
2398 {
2399 if (placeholder[subs_done][j] != -1)
2400 {
2401 /* copy all the lines from first[placeholder[subs_done][j]] into
2402 i and following positions in second */
2403 const int lines = first[placeholder[subs_done][j]].lines;
2404 int ls;
2405 for (ls = 0; ls < lines; ++ls)
2406 {
2407 second[sub_num].text[i++] =
2408 strdup(first[placeholder[subs_done][j]].text[ls])(__extension__ (__builtin_constant_p (first[placeholder[subs_done
][j]].text[ls]) && ((size_t)(const void *)((first[placeholder
[subs_done][j]].text[ls]) + 1) - (size_t)(const void *)(first
[placeholder[subs_done][j]].text[ls]) == 1) ? (((const char *
) (first[placeholder[subs_done][j]].text[ls]))[0] == '\0' ? (
char *) calloc ((size_t) 1, (size_t) 1) : ({ size_t __len = strlen
(first[placeholder[subs_done][j]].text[ls]) + 1; char *__retval
= (char *) malloc (__len); if (__retval != ((void*)0)) __retval
= (char *) memcpy (__retval, first[placeholder[subs_done][j]
].text[ls], __len); __retval; })) : __strdup (first[placeholder
[subs_done][j]].text[ls])))
;
2409 } /*for*/
2410 j += lines - 1; /* skip over lines just copied */
2411 }
2412 else
2413 {
2414 /* no subtitle goes here -- put in blank line */
2415 second[sub_num].text[i++] = strdup(" ")(__extension__ (__builtin_constant_p (" ") && ((size_t
)(const void *)((" ") + 1) - (size_t)(const void *)(" ") == 1
) ? (((const char *) (" "))[0] == '\0' ? (char *) calloc ((size_t
) 1, (size_t) 1) : ({ size_t __len = strlen (" ") + 1; char *
__retval = (char *) malloc (__len); if (__retval != ((void*)0
)) __retval = (char *) memcpy (__retval, " ", __len); __retval
; })) : __strdup (" ")))
;
2416 } /*if*/
2417 } /*for*/
2418 ++sub_num;
2419 ++subs_done;
2420 }
2421 while (local_end < global_end);
2422 if (real_block)
2423 for (i = 0; i < subs_done; ++i)
2424 second[start_block_sub + i].lines = highest_line + 1;
2425 for (i = 0; i < nr_placeholder_entries; ++i)
2426 {
2427 free(placeholder[i]);
2428 } /*for*/
2429 free(placeholder);
2430 sub_first += sub_to_add; /* skip over the ones I just added */
2431 } /*for*/
2432 for (j = sub_orig - 1; j >= 0; --j)
2433 {
2434 for (i = first[j].lines - 1; i >= 0; --i)
2435 {
2436 free(first[j].text[i]);
2437 } /*for*/
2438 } /*for*/
2439 free(first);
2440 return_sub = second;
2441 }
2442 else /* not suboverlap_enabled */
2443 {
2444 adjust_subs_time(first, 6.0, movie_fps, 1, sub_num, uses_time);/*~6 secs AST*/
2445 return_sub = first;
2446 } /*if*/
2447 if (return_sub == NULL((void*)0))
2448 return NULL((void*)0);
2449 subt_data = (sub_data *)malloc(sizeof(sub_data));
2450 subt_data->filename = filename;
2451 subt_data->sub_uses_time = uses_time;
2452 subt_data->sub_num = sub_num;
2453 subt_data->sub_errs = sub_errs;
2454 subt_data->subtitles = return_sub;
2455 return subt_data;
2456 } /*sub_read_file*/
2457
2458void sub_free(sub_data * subd)
2459 /* frees all storage allocated for subd. */
2460 {
2461 int i;
2462 if (!subd)
2463 return;
2464 if (subd->subtitles)
2465 {
2466 for (i = 0; i < subd->subtitles->lines; i++)
2467 free(subd->subtitles->text[i]);
2468 } /*if*/
2469 free(subd->subtitles);
2470 free((void *)subd->filename);
2471 free(subd);
2472 } /*sub_free*/
2473
2474/*
2475 Additional unused stuff (remove some time)
2476*/
2477
2478void list_sub_file(const sub_data * subd)
2479 {
2480 int i, j;
2481 const subtitle_elt * const subs = subd->subtitles;
2482 for (j = 0; j < subd->sub_num; j++)
2483 {
2484 const subtitle_elt * const egysub = &subs[j];
2485 fprintf(stdoutstdout, "%i line%c (%li-%li)\n",
2486 egysub->lines,
2487 1 == egysub->lines ? ' ' : 's',
2488 egysub->start,
2489 egysub->end);
2490 for (i = 0; i < egysub->lines; i++)
2491 {
2492 fprintf(stdoutstdout, "\t\t%d: %s%s", i, egysub->text[i], i == egysub->lines-1 ? "" : " \n ");
2493 } /*for*/
2494 fprintf(stdoutstdout, "\n");
2495 } /*for*/
2496 fprintf(stdoutstdout, "Subtitle format %s time.\n", subd->sub_uses_time ? "uses" : "doesn't use");
2497 fprintf(stdoutstdout, "Read %i subtitles, %i errors.\n", subd->sub_num, subd->sub_errs);
2498 } /*list_sub_file*/