source: trunk/Subtitles/SubParsing.m.rl @ 1031

Revision 1031, 13.6 KB checked in by astrange, 6 years ago (diff)
  • Make ffmpeg compile (vhook is gone)
  • Fix several memory leaks and unused variables noticed by clang checker
  • Switch to DWARF debugging info again; it seems to work ok in Shark and gdb now

Import:

  • Remove an apparently pointles seek in AVI files
  • Fix one of my AVIs with no keyframes not importing
  • Return invalidMovie instead of -1 for movies that can't be opened

FFusion:

  • Delete offsetH/V and spooling code, which didn't do anything

Subtitles:

  • Delete multiple-layout-per-line support; VSFilter doesn't actually support it (closes #389)
Line 
1/*
2 *  SubParsing.c
3 *  SSARender2
4 *
5 *  Created by Alexander Strange on 7/25/07.
6 *  Copyright 2007 __MyCompanyName__. All rights reserved.
7 *
8 */
9
10#import "SubParsing.h"
11#import "SubUtilities.h"
12#import "SubContext.h"
13#import "Codecprintf.h"
14
15%%machine SSAfile;
16%%write data;
17
18@implementation SubRenderSpan
19+(SubRenderSpan*)startingSpanForDiv:(SubRenderDiv*)div delegate:(SubRenderer*)delegate
20{
21        SubRenderSpan *span = [[SubRenderSpan alloc] init];
22        span->offset = 0;
23        span->ex = [delegate spanExtraFromRenderDiv:div];
24        span->delegate = delegate;
25        return [span autorelease];
26}
27
28-(SubRenderSpan*)cloneWithDelegate:(SubRenderer*)delegate_
29{
30        SubRenderSpan *span = [[SubRenderSpan alloc] init];
31        span->offset = offset;
32        span->ex = [delegate_ cloneSpanExtra:self];
33        span->delegate = delegate_;
34        return [span autorelease];
35}
36
37-(void)dealloc
38{
39        [delegate releaseSpanExtra:ex];
40        [super dealloc];
41}
42
43-(void)finalize {[delegate releaseSpanExtra:ex]; [super finalize];}
44@end
45
46@implementation SubRenderDiv
47-(NSString*)description
48{
49        int i, sc = [spans count];
50        NSMutableString *tmp = [NSMutableString stringWithFormat:@"div \"%@\" with %d spans:", text, sc];
51        for (i = 0; i < sc; i++) {[tmp appendFormat:@" %d",((SubRenderSpan*)[spans objectAtIndex:i])->offset];}
52        [tmp appendFormat:@" %d", [text length]];
53        return tmp;
54}
55
56-(SubRenderDiv*)init
57{
58        if (self = [super init]) {
59                text = nil;
60                styleLine = nil;
61                marginL = marginR = marginV = layer = 0;
62                spans = nil;
63               
64                posX = posY = 0;
65                alignH = kSubAlignmentMiddle; alignV = kSubAlignmentBottom;
66               
67                positioned = NO;
68                render_complexity = 0;
69        }
70       
71        return self;
72}
73
74-(SubRenderDiv*)nextDivWithDelegate:(SubRenderer*)delegate
75{
76        SubRenderDiv *div = [[[SubRenderDiv alloc] init] autorelease];
77       
78        div->text    = [[NSMutableString string] retain];
79  div->styleLine = [styleLine retain];
80        div->marginL = marginL;
81        div->marginR = marginR;
82        div->marginV = marginV;
83        div->layer   = layer;
84       
85        div->spans   = [[NSMutableArray arrayWithObject:[[spans objectAtIndex:[spans count]-1] cloneWithDelegate:delegate]] retain];
86       
87        div->posX    = posX;
88        div->posY    = posY;
89        div->alignH  = alignH;
90        div->alignV  = alignV;
91  div->wrapStyle = wrapStyle;
92 
93        div->positioned = positioned;
94        div->render_complexity = render_complexity;
95       
96        return div;
97}
98
99-(void)dealloc
100{
101        [text release];
102        [styleLine release];
103        [spans release];
104        [super dealloc];
105}
106@end
107
108extern BOOL IsScriptASS(NSDictionary *headers);
109
110static NSArray *SplitByFormat(NSString *format, NSArray *lines)
111{
112        NSArray *formarray = STSplitStringIgnoringWhitespace(format,@",");
113        int i, numlines = [lines count], numfields = [formarray count];
114        NSMutableArray *ar = [NSMutableArray arrayWithCapacity:numlines];
115       
116        for (i = 0; i < numlines; i++) {
117                NSString *s = [lines objectAtIndex:i];
118                NSArray *splitline = STSplitStringWithCount(s, @",", numfields);
119               
120                if ([splitline count] != numfields) continue;
121                [ar addObject:[NSDictionary dictionaryWithObjects:splitline
122                                                                                                  forKeys:formarray]];
123        }
124       
125        return ar;
126}
127
128void SubParseSSAFile(const unichar *ssa, size_t len, NSDictionary **headers, NSArray **styles, NSArray **subs)
129{
130        const unichar *p = ssa, *pe = ssa + len, *strbegin = p;
131        int cs=0;
132       
133        NSMutableDictionary *hd = [NSMutableDictionary dictionary];
134        NSMutableArray *stylearr = [NSMutableArray array], *eventarr = [NSMutableArray array], *cur_array=NULL;
135        NSCharacterSet *wcs = [NSCharacterSet whitespaceCharacterSet];
136        NSString *str=NULL, *styleformat=NULL, *eventformat=NULL;
137       
138#define send() [NSString stringWithCharacters:strbegin length:p-strbegin]
139       
140        %%{
141                alphtype unsigned short;
142               
143                action sstart {strbegin = p;}
144                action setheaderval {[hd setObject:send() forKey:str];}
145                action savestr {str = send();}
146                action csvlineend {[cur_array addObject:[send() stringByTrimmingCharactersInSet:wcs]];}
147                action setupevents {
148                        cur_array=eventarr;
149                        eventformat = IsScriptASS(hd) ?
150                                @"Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text":
151                                @"Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text";
152                }
153                               
154                nl = ("\n" | "\r" | "\r\n");
155                str = any*;
156                ws = space | 0xa0;
157                bom = 0xfeff;
158               
159                hline = ((";" str) | (([^;] str) >sstart %savestr :> (":" ws* str >sstart %setheaderval)?))? :> nl;
160               
161                header = "[Script Info]" nl hline*;
162                               
163                format = "Format:" ws* %sstart str %savestr :> nl;
164                               
165                action assformat {styleformat = @"Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding";}
166                action ssaformat {styleformat = @"Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding";}
167
168                stylename = ("[" [Vv] "4 Styles]") %ssaformat | ("[" [Vv] "4+ Styles]") %assformat;
169               
170                sline = (("Style:" ws* %sstart str %csvlineend) | str) :> nl;
171               
172                styles = stylename % {cur_array=stylearr;} nl :> (format %{styleformat=str;})? <: (sline*);
173               
174                event_txt = (("Dialogue:" ws* %sstart str %csvlineend) | str);
175                event = event_txt :> nl;
176                       
177                lines = "[Events]" %setupevents nl :> (format %{eventformat=str;})? <: (event*);
178               
179                main := bom? header styles lines?;
180        }%%
181               
182        %%write init;
183        %%write exec;
184        %%write eof;
185
186        *headers = hd;
187        if (styles) *styles = SplitByFormat(styleformat, stylearr);
188        if (subs) *subs = SplitByFormat(eventformat, eventarr);
189}
190
191%%machine SSAtag;
192%%write data;
193
194static NSMutableString *FilterSlashEscapes(NSMutableString *s)
195{
196        [s replaceOccurrencesOfString:@"\\n" withString:@"\n" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [s length])];
197        unichar nbsp = 0xA0;
198       
199        [s replaceOccurrencesOfString:@"\\h" withString:[NSString stringWithCharacters:&nbsp length:1] options:0 range: NSMakeRange(0,[s length])];
200        return s;
201}
202
203static int compare_layer(const void *a, const void *b)
204{
205        const SubRenderDiv *divA = *(id*)a, *divB = *(id*)b;
206
207        if (divA->layer < divB->layer) return -1;
208        else if (divA->layer > divB->layer) return 1;
209        return 0;
210}
211
212NSArray *SubParsePacket(NSString *packet, SubContext *context, SubRenderer *delegate, unichar *linebuf)
213{
214        packet = STStandardizeStringNewlines(packet);
215        NSArray *lines = (context->scriptType == kSubTypeSRT) ? [NSArray arrayWithObject:[packet substringToIndex:[packet length]-1]] : [packet componentsSeparatedByString:@"\n"];
216        size_t line_count = [lines count];
217        NSMutableArray *divs = [NSMutableArray arrayWithCapacity:line_count];
218        int i;
219       
220        for (i = 0; i < line_count; i++) {
221                NSString *inputText = [lines objectAtIndex:(context->collisions == kSubCollisionsReverse) ? (line_count - i - 1) : i];
222                SubRenderDiv *div = [[[SubRenderDiv alloc] init] autorelease];
223               
224                div->text = [[NSMutableString string] retain];
225                div->spans = [[NSMutableArray array] retain];
226               
227                if (context->scriptType == kSubTypeSRT) {
228                        div->styleLine = [context->defaultStyle retain];
229                        div->marginL = div->styleLine->marginL;
230                        div->marginR = div->styleLine->marginR;
231                        div->marginV = div->styleLine->marginV;
232                        div->layer = 0;
233                        div->wrapStyle = kSubLineWrapTopWider;
234                } else {
235                        NSArray *fields = STSplitStringWithCount(inputText, @",", 9);
236                        if ([fields count] < 9) continue;
237                        div->layer = [[fields objectAtIndex:1] intValue];
238                        div->styleLine = [[context styleForName:[fields objectAtIndex:2]] retain];
239                        div->marginL = [[fields objectAtIndex:4] intValue];
240                        div->marginR = [[fields objectAtIndex:5] intValue];
241                        div->marginV = [[fields objectAtIndex:6] intValue];
242                        inputText = [fields objectAtIndex:8];
243                        if ([inputText length] == 0) continue;
244                       
245                        if (div->marginL == 0) div->marginL = div->styleLine->marginL;
246                        if (div->marginR == 0) div->marginR = div->styleLine->marginR;
247                        if (div->marginV == 0) div->marginV = div->styleLine->marginV;
248                       
249                        div->wrapStyle = context->wrapStyle;
250                }
251               
252                div->alignH = div->styleLine->alignH;
253                div->alignV = div->styleLine->alignV;
254               
255                size_t linelen = [inputText length];
256                [inputText getCharacters:linebuf];
257                linebuf[linelen] = 0;
258               
259#undef send
260#define send() [NSString stringWithCharacters:outputbegin length:p-outputbegin]
261#define psend() [NSString stringWithCharacters:parambegin length:p-parambegin]
262#define tag(tagt, p) [delegate spanChangedTag:tag_##tagt span:current_span div:div param:&(p)]
263                               
264                {
265                        unichar *p = linebuf, *pe = linebuf + linelen, *outputbegin = p, *parambegin=p, *last_tag_start=p;
266                        const unichar *pb = p;
267                        int cs = 0;
268                        SubRenderSpan *current_span = [SubRenderSpan startingSpanForDiv:div delegate:delegate];
269                        unsigned chars_deleted = 0; float floatnum = 0;
270                        NSString *strval=NULL;
271                        unsigned curX, curY;
272                        int intnum = 0;
273                        BOOL reachedEnd = NO, setWrapStyle = NO, setPosition = NO, setAlignForDiv = NO, dropThisSpan = NO;
274                       
275                        %%{
276                                action bold {tag(b, intnum);}
277                                action italic {tag(i, intnum);}
278                                action underline {tag(u, intnum);}
279                                action strikeout {tag(s, intnum);}
280                                action outlinesize {tag(bord, floatnum);}
281                                action shadowdist {tag(shad, floatnum);}
282                                action bluredge {tag(be, intnum);}
283                                action fontname {tag(fn, strval);}
284                                action fontsize {tag(fs, floatnum);}
285                                action scalex {tag(fscx, floatnum);}
286                                action scaley {tag(fscy, floatnum);}
287                                action tracking {tag(fsp, floatnum);}
288                                action frz {tag(frz, floatnum);}
289                                action frx {tag(frx, floatnum);}
290                                action fry {tag(fry, floatnum);}
291                                action primaryc {tag(1c, intnum);}
292                                action secondaryc {tag(2c, intnum);}
293                                action outlinec {tag(3c, intnum);}
294                                action shadowc {tag(4c, intnum);}
295                                action alpha {tag(alpha, intnum);}
296                                action primarya {tag(1a, intnum);}
297                                action secondarya {tag(2a, intnum);}
298                                action outlinea {tag(3a, intnum);}
299                                action shadowa {tag(4a, intnum);}
300                                action stylerevert {tag(r, strval);}
301                                action drawingmode {tag(p, floatnum); dropThisSpan = floatnum > 0;}
302
303                                action paramset {parambegin=p;}
304                                action setintnum {intnum = [psend() intValue];}
305                                action sethexnum {intnum = strtoul([psend() UTF8String], NULL, 16);}
306                                action setfloatnum {floatnum = [psend() floatValue];}
307                                action setstringval {strval = psend();}
308                                action setxypos {curX=curY=-1; sscanf([psend() UTF8String], "(%d,%d)", &curX, &curY);}
309                               
310                                action ssaalign {
311                                        if (!setAlignForDiv) {
312                                                setAlignForDiv = YES;
313                                               
314                                                ParseASSAlignment(SSA2ASSAlignment(intnum), &div->alignH, &div->alignV);
315                                        }
316                                }
317                               
318                                action align {
319                                        if (!setAlignForDiv) {
320                                                setAlignForDiv = YES;
321                                               
322                                                ParseASSAlignment(intnum, &div->alignH, &div->alignV);
323                                        }
324                                }
325                               
326                                action wrapstyle {
327                                        if (!setWrapStyle) {
328                                                setWrapStyle = YES;
329                                               
330                                                div->wrapStyle = intnum;
331
332                                        }
333                                }
334                               
335                                action position {
336                                        if (!setPosition) {
337                                                setPosition = YES;
338                                               
339                                                div->posX = curX;
340                                                div->posY = curY;
341                                                div->positioned = YES;
342                                        }
343                                }
344
345                                intnum = ("-"? [0-9]+) >paramset %setintnum;
346                                flag = [01] >paramset %setintnum;
347                                floatnum = ("-"? [0-9]+ ("." [0-9]*)?) >paramset %setfloatnum;
348                                string = ([^\\}]*) >paramset %setstringval;
349                                color = ("H"|"&"){,2} (xdigit+) >paramset %sethexnum "&"?;
350                                parens = "(" [^)]* ")";
351                                xypos = ("(" "-"? [0-9]+ "," "-"? [0-9]+ ")") >paramset %setxypos;
352                               
353                                cmd = "\\" (
354                                                        "b" intnum %bold
355                                                        |"i" flag %italic
356                                                        |"u" flag %underline
357                                                        |"s" flag %strikeout
358                                                        |"bord" floatnum %outlinesize
359                                                        |"shad" floatnum %shadowdist
360                                                        |"be" flag %bluredge
361                                                        |"fn" string %fontname
362                                                        |"fs" floatnum %fontsize
363                                                        |"fscx" floatnum %scalex
364                                                        |"fscy" floatnum %scaley
365                                                        |"fsp" floatnum %tracking
366                                                        |("fr" "z"? floatnum %frz)
367                                                        |"frx" floatnum %frx
368                                                        |"fry" floatnum %fry
369                                                        |"fe" intnum
370                                                        |("1"? "c" color %primaryc)
371                                                        |"2c" color %secondaryc
372                                                        |"3c" color %outlinec
373                                                        |"4c" color %shadowc
374                                                        |"alpha" color %alpha
375                                                        |"1a" color %primarya
376                                                        |"2a" color %secondarya
377                                                        |"3a" color %outlinea
378                                                        |"4a" color %shadowa
379                                                        |"a" intnum %ssaalign
380                                                        |"an" intnum %align
381                                                        |([kK] [fo]? intnum)
382                                                        |"q" intnum %wrapstyle
383                                                        |"r" string %stylerevert
384                                                        |"pos" xypos %position
385                                                        |"t" parens
386                                                        |"org" parens
387                                                        |("fad" "e"? parens)
388                                                        |"clip" parens
389                                                        |"p" floatnum %drawingmode
390                                                        |"pbo" floatnum
391                                           );
392                               
393                                tag = "{" (cmd* | any*) :> "}";
394
395                                action backslash_handler {
396                                        p--;
397                                        [div->text appendString:send()];
398                                        unichar c = *(p+1), o=c;
399                                       
400                                        if (c) {
401                                                switch (c) {
402                                                        case 'N': case 'n':
403                                                                o = '\n';
404                                                                break;
405                                                        case 'h':
406                                                                o = 0xA0; //non-breaking space
407                                                                break;
408                                                }
409                                               
410                                                [div->text appendFormat:@"%C",o];
411                                        }
412                                       
413                                        chars_deleted++;
414                                       
415                                        p++;
416                                        outputbegin = p+1;
417                                }
418                               
419                                action enter_tag {
420                                        if (dropThisSpan) chars_deleted += p - outputbegin;
421                                        else if (p > outputbegin) [div->text appendString:send()];
422                                        if (p == pe) reachedEnd = YES;
423                                       
424                                        if (p != pb) {
425                                                [div->spans addObject:current_span];
426                                               
427                                                if (!reachedEnd) current_span = [current_span cloneWithDelegate:delegate];
428                                        }
429                                       
430                                        last_tag_start = p;
431                                }
432                               
433                                action exit_tag {                       
434                                        p++;
435                                        chars_deleted += (p - last_tag_start);
436                                       
437                                        current_span->offset = (p - pb) - chars_deleted;
438                                        outputbegin = p;
439                                       
440                                        p--;
441                                }
442                                                               
443                                special = ("\\" :> any) @backslash_handler | tag >enter_tag @exit_tag;
444                                sub_text_char = [^\\{];
445                                sub_text = sub_text_char+;
446                               
447                                main := ((sub_text | special)* "\\"?) %/enter_tag;
448                        }%%
449                               
450                        %%write init;
451                        %%write exec;
452                        %%write eof;
453
454                        if (!reachedEnd) Codecprintf(NULL, "parse error: %s\n", [inputText UTF8String]);
455                        if (linebuf[linelen-1] == '\\') [div->text appendString:@"\\"];
456                        [divs addObject:div];
457                }
458               
459        }
460       
461        STSortMutableArrayStably(divs, compare_layer);
462        return divs;
463}
Note: See TracBrowser for help on using the repository browser.