[jnc_test] added async/await tokens to jancy highlighter

//..............................................................................
//
//  This file is part of the Jancy toolkit.
//
//  Jancy is distributed under the MIT license.
//  For details see accompanying license.txt file,
//  the public copy of which is also available at:
//  http://tibbo.com/downloads/archive/jancy/license.txt
//
//..............................................................................

%%{

machine jancy_lexer;
write data;

#. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
#
# standard definitions
#

dec    = [0-9];
hex    = [0-9a-fA-F];
oct    = [0-7];
bin    = [01];
id     = [_a-zA-Z] [_a-zA-Z0-9]*;
ws     = [ \t\r]+;
nl     = '\n';
lc_nl  = '\\' '\r'? nl;
esc    = '\\' [^\n];

lit_dq     = '"' ([^"\n\\] | esc)* (["\\] | nl);
lit_sq     = "'" ([^'\n\\] | esc)* (['\\] | nl);
raw_lit_dq = '"' [^"\n]* ('"' | nl);
raw_lit_sq = "'" [^'\n]* ("'" | nl);

#. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
#
# main machine
#

main := |*

#. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

(
'import'          |
'namespace'       |
'extension'       |
'dynamiclib'      |
'using'           |
'friend'          |
'public'          |
'protected'       |
'alignment'       |
'setas'           |

'typedef'         |
'alias'           |
'static'          |
'threadlocal'     |
'stack'           |
'heap'            |
'abstract'        |
'virtual'         |
'override'        |
'mutable'         |
'disposable'      |

'signed'          |
'unsigned'        |
'bigendian'       |
'const'           |
'cmut'            |
'readonly'        |
'volatile'        |
'safe'            |
'unsafe'          |
'weak'            |
'thin'            |
'errorcode'       |
'cdecl'           |
'stdcall'         |
'thiscall'        |
'jnccall'         |
'array'           |
'function'        |
'property'        |
'bindable'        |
'autoget'         |
'indexed'         |
'multicast'       |
'event'           |
'reactor'         |
'async'           |

'anydata'         |
'void'            |
'variant'         |
'bool'            |
'int'             |
'intptr'          |
'char'            |
'short'           |
'long'            |
'float'           |
'double'          |
'enum'            |
'struct'          |
'union'           |
'class'           |
'opaque'          |
'exposed'         |
'bitflag'         |

'get'             |
'set'             |
'preconstruct'    |
'construct'       |
'destruct'        |
'operator'        |
'postfix'         |

'if'              |
'else'            |
'for'             |
'while'           |
'do'              |
'break'           |
'break' [1-9]?    |
'continue' [1-9]? |
'return'          |
'switch'          |
'reswitch'        |
'case'            |
'default'         |
'once'            |
'onevent'         |
'try'             |
'throw'           |
'catch'           |
'finally'         |
'nestedscope'     |
'assert'          |
'await'           |

'basetype' [1-9]? |
'this'            |
'true'            |
'false'           |
'null'            |

'new'             |
'delete'          |
'sizeof'          |
'countof'         |
'offsetof'        |
'typeof'          |
'bindingof'       |
'dynamic'

)                   { colorize (ts, te, Qt::blue); };

#. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

id                  ;

(
lit_sq              |
lit_dq              |
[rR] raw_lit_sq     |
[rR] raw_lit_dq     |
dec+                |
'0' oct+            |
'0' [xX] hex+       |
'0' [oO] oct+       |
'0' [bB] bin+       |
'0' [nNdD] dec+     |
'0' [xXoObBnNdD] raw_lit_dq |
dec+ (('.' dec*) | ([eE] [+\-]? dec+)) |
[$fF] lit_dq
)					{ colorize (ts, te, Qt::darkRed); };

('0' [xXoObBnNdD])? '"""'
					{ colorize (ts, te, Qt::darkRed); fgoto lit_ml; };

'//' any*           { colorize (ts, te, Qt::darkGray); };
'/*'                { colorize (ts, te, Qt::darkGray); fgoto comment; };

ws | nl             ;
any                 ;

*|;

#. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
#
# comment machine
#

comment := |*

'*/'                { colorize (ts, te, Qt::darkGray); fgoto main; };
any                 { colorize (ts, te, Qt::darkGray); };

*|;

#. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
#
# multi-line literal machine
#

lit_ml := |*

'"""'               { colorize (ts, te, Qt::darkRed); fgoto main; };
any                 { colorize (ts, te, Qt::darkRed); };

*|;

}%%

//..............................................................................

#define BLOCK_STATE_NONE	0
#define BLOCK_STATE_COMMENT 1
#define BLOCK_STATE_LIT_ML  2

void JancyHighlighter::ragelInit ()
{
	%% write init;
}

void JancyHighlighter::ragelExec ()
{
	%% write exec;
}

void JancyHighlighter::ragelExecPreEvent (int &ragelState)
{
	setCurrentBlockState (BLOCK_STATE_NONE);

	int prevBlockState = previousBlockState ();
	switch (prevBlockState)
	{
	case BLOCK_STATE_COMMENT:
		ragelState = jancy_lexer_en_comment;
		break;

	case BLOCK_STATE_LIT_ML:
		ragelState = jancy_lexer_en_lit_ml;
		break;
	}
}

void JancyHighlighter::ragelExecPostEvent (int ragelState)
{
	switch (ragelState)
	{
	case jancy_lexer_en_comment:
		setCurrentBlockState (BLOCK_STATE_COMMENT);
		break;

	case jancy_lexer_en_lit_ml:
		setCurrentBlockState (BLOCK_STATE_LIT_ML);
		break;
	}
}

//..............................................................................

//..............................................................................
//
//  This file is part of the Jancy toolkit.
//
//  Jancy is distributed under the MIT license.
//  For details see accompanying license.txt file,
//  the public copy of which is also available at:
//  http://tibbo.com/downloads/archive/jancy/license.txt
//
//..............................................................................

%%{

machine jancy_lexer;
write data;

#. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
#
# standard definitions
#

dec    = [0-9];
hex    = [0-9a-fA-F];
oct    = [0-7];
bin    = [01];
id     = [_a-zA-Z] [_a-zA-Z0-9]*;
ws     = [ \t\r]+;
nl     = '\n';
lc_nl  = '\\' '\r'? nl;
esc    = '\\' [^\n];

lit_dq     = '"' ([^"\n\\] | esc)* (["\\] | nl);
lit_sq     = "'" ([^'\n\\] | esc)* (['\\] | nl);
raw_lit_dq = '"' [^"\n]* ('"' | nl);
raw_lit_sq = "'" [^'\n]* ("'" | nl);

#. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
#
# main machine
#

main := |*

#. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

(
'import'          |
'namespace'       |
'extension'       |
'dynamiclib'      |
'using'           |
'friend'          |
'public'          |
'protected'       |
'alignment'       |
'setas'           |

'typedef'         |
'alias'           |
'static'          |
'threadlocal'     |
'stack'           |
'heap'            |
'abstract'        |
'virtual'         |
'override'        |
'mutable'         |
'disposable'      |

'signed'          |
'unsigned'        |
'bigendian'       |
'const'           |
'cmut'            |
'readonly'        |
'volatile'        |
'safe'            |
'unsafe'          |
'weak'            |
'thin'            |
'errorcode'       |
'cdecl'           |
'stdcall'         |
'thiscall'        |
'jnccall'         |
'array'           |
'function'        |
'property'        |
'bindable'        |
'autoget'         |
'indexed'         |
'multicast'       |
'event'           |
'reactor'         |

'auto'            |
'anydata'         |
'void'            |
'variant'         |
'bool'            |
'int'             |
'intptr'          |
'char'            |
'short'           |
'long'            |
'float'           |
'double'          |
'enum'            |
'struct'          |
'union'           |
'class'           |
'opaque'          |
'exposed'         |
'bitflag'         |

'get'             |
'set'             |
'preconstruct'    |
'construct'       |
'destruct'        |
'operator'        |
'postfix'         |

'if'              |
'else'            |
'for'             |
'while'           |
'do'              |
'break'           |
'break' [1-9]?    |
'continue' [1-9]? |
'return'          |
'switch'          |
'reswitch'        |
'case'            |
'default'         |
'once'            |
'onevent'         |
'try'             |
'throw'           |
'catch'           |
'finally'         |
'nestedscope'     |
'assert'          |

'basetype' [1-9]? |
'this'            |
'true'            |
'false'           |
'null'            |

'new'             |
'delete'          |
'sizeof'          |
'countof'         |
'offsetof'        |
'typeof'          |
'bindingof'       |
'dynamic'

)                   { colorize (ts, te, Qt::blue); };

#. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

id                  ;

(
lit_sq              |
lit_dq              |
[rR] raw_lit_sq     |
[rR] raw_lit_dq     |
dec+                |
'0' oct+            |
'0' [xX] hex+       |
'0' [oO] oct+       |
'0' [bB] bin+       |
'0' [nNdD] dec+     |
'0' [xXoObBnNdD] raw_lit_dq |
dec+ (('.' dec*) | ([eE] [+\-]? dec+)) |
[$fF] lit_dq
)					{ colorize (ts, te, Qt::darkRed); };

('0' [xXoObBnNdD])? '"""'
					{ colorize (ts, te, Qt::darkRed); fgoto lit_ml; };

'//' any*           { colorize (ts, te, Qt::darkGray); };
'/*'                { colorize (ts, te, Qt::darkGray); fgoto comment; };

ws | nl             ;
any                 ;

*|;

#. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
#
# comment machine
#

comment := |*

'*/'                { colorize (ts, te, Qt::darkGray); fgoto main; };
any                 { colorize (ts, te, Qt::darkGray); };

*|;

#. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
#
# multi-line literal machine
#

lit_ml := |*

'"""'               { colorize (ts, te, Qt::darkRed); fgoto main; };
any                 { colorize (ts, te, Qt::darkRed); };

*|;

}%%

//..............................................................................

#define BLOCK_STATE_NONE	0
#define BLOCK_STATE_COMMENT 1
#define BLOCK_STATE_LIT_ML  2

void JancyHighlighter::ragelInit ()
{
	%% write init;
}

void JancyHighlighter::ragelExec ()
{
	%% write exec;
}

void JancyHighlighter::ragelExecPreEvent (int &ragelState)
{
	setCurrentBlockState (BLOCK_STATE_NONE);

	int prevBlockState = previousBlockState ();
	switch (prevBlockState)
	{
	case BLOCK_STATE_COMMENT:
		ragelState = jancy_lexer_en_comment;
		break;

	case BLOCK_STATE_LIT_ML:
		ragelState = jancy_lexer_en_lit_ml;
		break;
	}
}

void JancyHighlighter::ragelExecPostEvent (int ragelState)
{
	switch (ragelState)
	{
	case jancy_lexer_en_comment:
		setCurrentBlockState (BLOCK_STATE_COMMENT);
		break;

	case jancy_lexer_en_lit_ml:
		setCurrentBlockState (BLOCK_STATE_LIT_ML);
		break;
	}
}

//..............................................................................


Don't split srt into individual lines. (fixes lines drawn out of order)

git-svn-id: d8f21eb7283bfb39ebab2f8f9b4a259b233f9348@326 621663c8-3916-0410-8f58-edc14a8543d5

//
//  SSATagParsing.m
//  SSAView
//
//  Created by Alexander Strange on 1/21/07.
//  Copyright 2007 Perian Project. All rights reserved.
//

#import "SSATagParsing.h"
#import "Categories.h"

@implementation SSAStyleSpan
-(void)dealloc
{
	ATSUDisposeStyle(astyle);
	[super dealloc];
}
@end

@implementation SSARenderEntity
-(void)dealloc
{
	int i;
	for (i=0; i < style_count; i++) [styles[i] release];
	if (disposelayout) ATSUDisposeTextLayout(layout);
	free(text);
	free(styles);
	[nstext release];
	[super dealloc];
}

-(void)increasestyles
{
	style_count++;
	styles = realloc(styles, sizeof(SSAStyleSpan*[style_count]));
}
@end

%% machine SSAtag;
%% write data;

static void SetATSUStyleFlag(ATSUStyle style, ATSUAttributeTag t, Boolean v)
{
	ATSUAttributeTag tags[] = {t};
	ByteCount		 sizes[] = {sizeof(v)};
	ATSUAttributeValuePtr vals[] = {&v};

	ATSUSetAttributes(style,1,tags,sizes,vals);
}

static void SetATSUStyleOther(ATSUStyle style, ATSUAttributeTag t, ByteCount s, ATSUAttributeValuePtr v)
{
	ATSUAttributeTag tags[] = {t};
	ByteCount		 sizes[] = {s};
	ATSUAttributeValuePtr vals[] = {v};

	ATSUSetAttributes(style,1,tags,sizes,vals);
}

static void SetATSULayoutOther(ATSUTextLayout l, ATSUAttributeTag t, ByteCount s, ATSUAttributeValuePtr v)
{
	ATSUAttributeTag tags[] = {t};
	ByteCount		 sizes[] = {s};
	ATSUAttributeValuePtr vals[] = {v};

	ATSUSetLayoutControls(l,1,tags,sizes,vals);
}

static ATSURGBAlphaColor ParseColorTag(unsigned long c, float a)
{
	unsigned char r,g,b;
	r = c & 0xff;
	g = (c >> 8) & 0xff;
	b = (c >> 16) & 0xff;

	return (ATSURGBAlphaColor){r/255.,g/255.,b/255.,a};
}

static void PruneEmptyStyleSpans(SSARenderEntity *re)
{
	SSAStyleSpan *styles_new[re->style_count];
	size_t style_count_new = 0;
	int i;

	for (i = 0; i < re->style_count; i++) {
		if (re->styles[i]->range.length == 0) {
			[re->styles[i] release];
		} else {
			styles_new[style_count_new++] = re->styles[i];
		}
	}

	if (style_count_new != re->style_count) {
		re->styles = realloc(re->styles, sizeof(SSAStyleSpan*) * style_count_new);
		memcpy(re->styles, styles_new, sizeof(SSAStyleSpan*) * style_count_new);

		re->style_count = style_count_new;
	}
}

NSArray *ParseSubPacket(NSString *str, SSADocument *ssa, Boolean plaintext)
{
	NSArray *linea;
	int i, j, pcount; unsigned len;
	NSMutableArray *rentities = [NSMutableArray array];

	if (plaintext) {
		linea = [NSArray arrayWithObject:str];
		pcount = 1;
	} else {
		linea =  [str componentsSeparatedByString:@"\n"];
		pcount = [linea count];
	}

	for (i = 0; i < pcount; i++) {
		SSARenderEntity *re = [[[SSARenderEntity alloc] init] autorelease];
		BOOL ldirty = NO;

		if (plaintext) {
			re->style = ssa->defaultstyle;
			re->layout = re->style->layout;
			re->layer = 0;
			re->marginl = re->style->marginl;
			re->marginr = re->style->marginl;
			re->marginv = re->style->marginl;
			re->usablewidth = re->style->usablewidth;
			re->halign = 1;
			re->valign = 0;
			re->nstext = [linea objectAtIndex:i];
			re->styles = NULL;
			re->disposelayout = NO;
		} else {
			NSArray *ar = [[linea objectAtIndex:i] componentsSeparatedByString:@"," count:9];

			if ([ar count] < 9) continue;

			re->layer = [[ar objectAtIndex:1] intValue];
			NSString *sn = [ar objectAtIndex:2];

			re->style = NULL;

			for (j=0; j < ssa->stylecount; j++) {
				if ([sn isEqualToString:ssa->styles[j].name])  {
					re->style = &ssa->styles[j];
					break;
				}
			}

			if (!re->style) {
				re->style = ssa->defaultstyle;
			}

			re->marginl = [[ar objectAtIndex:5] intValue];
			re->marginr = [[ar objectAtIndex:6] intValue];
			re->marginv = [[ar objectAtIndex:7] intValue];

			if (re->marginl == 0) re->marginl = re->style->marginl; else ldirty = TRUE;
			if (re->marginr == 0) re->marginr = re->style->marginr; else ldirty = TRUE;
			if (re->marginv == 0) re->marginv = re->style->marginv; else ldirty = TRUE;

			if (ldirty) {
				ATSUTextMeasurement width;
				ATSUAttributeTag tag[] = {kATSULineWidthTag};
				ByteCount		 size[] = {sizeof(ATSUTextMeasurement)};
				ATSUAttributeValuePtr val[] = {&width};

				re->usablewidth = ssa->resX - re->marginl - re->marginr;
				ATSUCreateAndCopyTextLayout(re->style->layout,&re->layout);
				width = IntToFixed(re->usablewidth);

				ATSUSetLayoutControls(re->layout,1,tag,size,val);
				re->disposelayout = YES;
			} else {
				re->usablewidth = re->style->usablewidth;
				re->layout = re->style->layout;
				re->disposelayout = NO;
			}

			re->nstext = [ar objectAtIndex:8];
		}
		len = [re->nstext length];
		re->text = malloc(sizeof(unichar[len]));

		[re->nstext getCharacters:re->text];
		re->style_count = 0;
		re->posx = re->posy = -1;
		re->halign = re->style->halign;
		re->valign = re->style->valign;
		re->multipleruns=NO;

#define end_re \
		cur_range = (NSRange){strbegin - pb, p - strbegin};\
		cur_range.location -= outputoffset;\
		cur_range.length -= lengthreduce;\
		[re increasestyles];\
		re->styles[re->style_count-1] = [[SSAStyleSpan alloc] init];\
		re->styles[re->style_count-1]->outline = cur_outline;\
		re->styles[re->style_count-1]->shadow = cur_shadow;\
		re->styles[re->style_count-1]->astyle = cur_style;\
		re->styles[re->style_count-1]->range = cur_range;\
		re->styles[re->style_count-1]->outlineblur = cur_be;\
		re->styles[re->style_count-1]->color = cur_color;\
		parsetmp = [NSString stringWithCharacters:skipbegin length:p-skipbegin];\
		[output appendString:parsetmp]; \
		re->nstext = dtmp = output;\
		re->text = malloc(sizeof(unichar[[re->nstext length]]));\
		[re->nstext getCharacters:re->text];\
		[re->nstext retain];

		{
			NSRange cur_range = {0,0};
			ATSUStyle cur_style;
			ATSUTextLayout cur_layout;
			NSMutableString *output = [NSMutableString string], *dtmp;
			unichar *p = re->text, *pe = &re->text[len], *numbegin, *strbegin = p, *skipbegin = p, *intbegin, *pb = p, *posbegin, *strparambegin;
			float num, cur_outline = re->style->outline, cur_shadow = re->style->shadow;
			NSString *parsetmp;
			int cs, cur_valign=re->valign, cur_halign=re->halign, cur_posx, cur_posy;
			ssacolors cur_color = re->style->color;

			unsigned long inum;
			unsigned outputoffset=0, lengthreduce=0;
			BOOL flag, newLayout=FALSE, cur_be = FALSE;
			Fixed fixv;

			ATSUCreateAndCopyStyle(re->style->atsustyle,&cur_style);

			%%{
				alphtype unsigned short;

				action bold {SetATSUStyleFlag(cur_style, kATSUQDBoldfaceTag, flag);}

				action italic {SetATSUStyleFlag(cur_style, kATSUQDItalicTag, flag);}

				action uline {SetATSUStyleFlag(cur_style, kATSUQDUnderlineTag, flag);}

				action strike {SetATSUStyleFlag(cur_style, kATSUStyleStrikeThroughTag, flag);}

				action bordersize {cur_outline = num; re->multipleruns = YES;}

				action shadowsize {cur_shadow = num; re->multipleruns = YES;}

				action bluredge {cur_be = flag;}

				action frot {
					if (!newLayout) {
						newLayout = TRUE;
						ATSUCreateAndCopyTextLayout(re->layout,&cur_layout);
					}
					fixv = FloatToFixed(num);

					SetATSULayoutOther(cur_layout, kATSULineRotationTag, sizeof(Fixed), &fixv);
				}

				action fsize {
					fixv = FloatToFixed(num);
					SetATSUStyleOther(cur_style, kATSUSizeTag, sizeof(fixv), &fixv);
				}

				action fn_begin {
					strparambegin = p;
				}

				action fontname {
					ATSUFontID	font;
					font = FMGetFontFromATSFontRef(ATSFontFindFromName((CFStringRef)[NSString stringWithCharacters:strparambegin length:p-strparambegin],kATSOptionFlagsDefault));
					SetATSUStyleOther(cur_style, kATSUFontTag, sizeof(ATSUFontID), &font);
				}

				action alignment {
					if (!newLayout) {
						newLayout = TRUE;
						ATSUCreateAndCopyTextLayout(re->layout,&cur_layout);
					}

					if (ssa->version == S_SSA) inum = SSA2ASSAlignment(inum);

					switch (inum)
					{case 1: case 4: case 7: cur_halign = S_LeftAlign; break;
					case 2: case 5: case 8: default: cur_halign = S_CenterAlign; break;
					case 3: case 6: case 9: cur_halign = S_RightAlign;}

					switch (inum)
					{case 1: case 2: case 3: default: cur_valign = S_BottomAlign; break;
					case 4: case 5: case 6: cur_valign = S_MiddleAlign; break;
					case 7: case 8: case 9: cur_valign = S_TopAlign;}

					Fract alignment;

					if (cur_posx != -1) {
						switch(cur_halign) {
							case S_LeftAlign:
								alignment = FloatToFract(0.);
								break;
							case S_CenterAlign: default:
								alignment = kATSUCenterAlignment;
								break;
							case S_RightAlign:
								alignment = FloatToFract(1.);
						}
						SetATSULayoutOther(cur_layout, kATSULineFlushFactorTag, sizeof(Fract), &alignment);
					}
				}

				action pos_begin {
					posbegin=p;
				}

				action pos_end {
					if (!newLayout) {
						newLayout = TRUE;
						ATSUCreateAndCopyTextLayout(re->layout,&cur_layout);
					}
					NSArray *coo = [[NSString stringWithCharacters:posbegin length:p-posbegin] componentsSeparatedByString:@","];
					cur_posx = [[coo objectAtIndex:0] intValue];
					cur_posy = [[coo objectAtIndex:1] intValue];

					Fract alignment = FloatToFract(0);

					SetATSULayoutOther(cur_layout, kATSULineFlushFactorTag, sizeof(Fract), &alignment);
				}

				action primarycolor {
					cur_color.primary = ParseColorTag(inum,cur_color.primary.alpha);
					re->multipleruns = YES;
				}

				action outlinecolor {
					cur_color.outline = ParseColorTag(inum,cur_color.outline.alpha);
					re->multipleruns = YES;
				}

				action shadowcolor {
					cur_color.shadow = ParseColorTag(inum,cur_color.shadow.alpha);
					re->multipleruns = YES;
				}

				action nl_handler {
					parsetmp = [NSString stringWithCharacters:skipbegin length:(p-2)-skipbegin];
					[output appendString:parsetmp];

					skipbegin = p;

					[output appendString:@"\n"];

					lengthreduce++;
				}

				action enter_tag {
					parsetmp = [NSString stringWithCharacters:skipbegin length:p-skipbegin];
					[output appendString:parsetmp];

					cur_range = (NSRange){strbegin - pb, p - strbegin};
					cur_range.location -= outputoffset;
					cur_range.length -= lengthreduce;

					outputoffset += lengthreduce;
					lengthreduce = 0;

					skipbegin = p;

					[re increasestyles];
					re->styles[re->style_count-1] = [[SSAStyleSpan alloc] init];
					re->styles[re->style_count-1]->outline = cur_outline;
					re->styles[re->style_count-1]->shadow = cur_shadow;
					re->styles[re->style_count-1]->astyle = cur_style;
					re->styles[re->style_count-1]->range = cur_range;
					re->styles[re->style_count-1]->outlineblur = cur_be;
					re->styles[re->style_count-1]->color = cur_color;
					ATSUCreateAndCopyStyle(cur_style,&cur_style);
				}

				action exit_tag {
					outputoffset += p - skipbegin;
					skipbegin = p;
					strbegin = p;

					if (newLayout) {
						newLayout = FALSE;
						end_re;

						if ([re->nstext length] != 0) [rentities addObject:re];

						SSARenderEntity *nre = [[SSARenderEntity alloc] init];
						nre->layer = re->layer;
						nre->style = re->style;
						nre->marginl = re->marginl; nre->marginr = re->marginr; nre->marginv = re->marginv; nre->usablewidth = re->usablewidth;
						nre->posx = cur_posx; nre->posy = cur_posy; nre->halign = cur_halign; nre->valign = cur_valign;
						nre->nstext = nil;
						nre->text = nil;
						nre->layout = cur_layout;
						nre->styles = malloc(0);
						nre->style_count = 0;
						nre->disposelayout = YES;
						nre->multipleruns = NO;
						re = nre;
					}
				}

				action color_end {
					NSString *hexn = [NSString stringWithCharacters:intbegin length:p-intbegin];
					inum = strtoul([hexn UTF8String], NULL, 16);
				}

				flag = ([01] % {unichar fl = *(p-1); if (flag == '0' || flag == '1') flag = fl - '0';})? > {flag = 1;};
				num_ = digit+ ('.' digit*)?;
				num = num_ > {numbegin = p;} % {num = [[NSString stringWithCharacters:numbegin length:p-numbegin] doubleValue];};

				intnum = digit* > {intbegin = p;} % {inum = [[NSString stringWithCharacters:intbegin length:p-intbegin] intValue];};

				color = "&H" xdigit* > {intbegin = p;} % color_end "&";

				cmd_specific = (("pos(" [^)]+ > pos_begin ")" % pos_end)
								|"bord" num %bordersize
								|"b" :> flag %bold
								|"be" flag %bluredge
								|"i" flag %italic
								|"u" flag %uline
								|"s" flag %strike
								|"fad" [^\\}]*
								|"fs" num %fsize
								|("fr" "z"? num %frot)
								|("fn" [^\\}]* > fn_begin %fontname)
								|"shad" num %shadowsize
								|"an" intnum %alignment
								|"1"? "c" color %primarycolor
								|"3c" color %outlinecolor
								|"4c" color %shadowcolor
								);

				cmd = "\\"  cmd_specific ;

				tag = "{" ((cmd*) | ([^\\}]*)) "}";

				nl = "\\" [Nn];

				special = nl % nl_handler |
						 (tag > enter_tag % exit_tag);

				text = any*;
				main := (text :> special?)*;
			}%%

			%%write init;
			%%write exec;
			%%write eof;

			if (re->text[len-1] == '}') skipbegin = p; // make up for how exit_tag isn't called if the } is the last char in the line

			end_re;

			PruneEmptyStyleSpans(re);

			free(pb);
			if ([re->nstext length] != 0) [rentities addObject:re];
		}

	}

	return rentities;
}

//
//  SSATagParsing.m
//  SSAView
//
//  Created by Alexander Strange on 1/21/07.
//  Copyright 2007 Perian Project. All rights reserved.
//

#import "SSATagParsing.h"
#import "Categories.h"

@implementation SSAStyleSpan
-(void)dealloc
{
	ATSUDisposeStyle(astyle);
	[super dealloc];
}
@end

@implementation SSARenderEntity
-(void)dealloc
{
	int i;
	for (i=0; i < style_count; i++) [styles[i] release];
	if (disposelayout) ATSUDisposeTextLayout(layout);
	free(text);
	free(styles);
	[nstext release];
	[super dealloc];
}

-(void)increasestyles
{
	style_count++;
	styles = realloc(styles, sizeof(SSAStyleSpan*[style_count]));
}
@end

%% machine SSAtag;
%% write data;

static void SetATSUStyleFlag(ATSUStyle style, ATSUAttributeTag t, Boolean v)
{
	ATSUAttributeTag tags[] = {t};
	ByteCount		 sizes[] = {sizeof(v)};
	ATSUAttributeValuePtr vals[] = {&v};

	ATSUSetAttributes(style,1,tags,sizes,vals);
}

static void SetATSUStyleOther(ATSUStyle style, ATSUAttributeTag t, ByteCount s, ATSUAttributeValuePtr v)
{
	ATSUAttributeTag tags[] = {t};
	ByteCount		 sizes[] = {s};
	ATSUAttributeValuePtr vals[] = {v};

	ATSUSetAttributes(style,1,tags,sizes,vals);
}

static void SetATSULayoutOther(ATSUTextLayout l, ATSUAttributeTag t, ByteCount s, ATSUAttributeValuePtr v)
{
	ATSUAttributeTag tags[] = {t};
	ByteCount		 sizes[] = {s};
	ATSUAttributeValuePtr vals[] = {v};

	ATSUSetLayoutControls(l,1,tags,sizes,vals);
}

static ATSURGBAlphaColor ParseColorTag(unsigned long c, float a)
{
	unsigned char r,g,b;
	r = c & 0xff;
	g = (c >> 8) & 0xff;
	b = (c >> 16) & 0xff;

	return (ATSURGBAlphaColor){r/255.,g/255.,b/255.,a};
}

static void PruneEmptyStyleSpans(SSARenderEntity *re)
{
	SSAStyleSpan *styles_new[re->style_count];
	size_t style_count_new = 0;
	int i;

	for (i = 0; i < re->style_count; i++) {
		if (re->styles[i]->range.length == 0) {
			[re->styles[i] release];
		} else {
			styles_new[style_count_new++] = re->styles[i];
		}
	}

	if (style_count_new != re->style_count) {
		re->styles = realloc(re->styles, sizeof(SSAStyleSpan*) * style_count_new);
		memcpy(re->styles, styles_new, sizeof(SSAStyleSpan*) * style_count_new);

		re->style_count = style_count_new;
	}
}

NSArray *ParseSubPacket(NSString *str, SSADocument *ssa, Boolean plaintext)
{
	NSArray *linea = [str componentsSeparatedByString:@"\n"];
	int i, j, pcount = [linea count]; unsigned len;
	NSMutableArray *rentities = [NSMutableArray array];

	for (i = 0; i < pcount; i++) {
		SSARenderEntity *re = [[[SSARenderEntity alloc] init] autorelease];
		BOOL ldirty = NO;

		if (plaintext) {
			re->style = ssa->defaultstyle;
			re->layout = re->style->layout;
			re->layer = 0;
			re->marginl = re->style->marginl;
			re->marginr = re->style->marginl;
			re->marginv = re->style->marginl;
			re->usablewidth = re->style->usablewidth;
			re->halign = 1;
			re->valign = 0;
			re->nstext = [linea objectAtIndex:i];
			re->styles = NULL;
			re->disposelayout = NO;
		} else {
			NSArray *ar = [[linea objectAtIndex:i] componentsSeparatedByString:@"," count:9];

			if ([ar count] < 9) continue;

			re->layer = [[ar objectAtIndex:1] intValue];
			NSString *sn = [ar objectAtIndex:2];

			re->style = NULL;

			for (j=0; j < ssa->stylecount; j++) {
				if ([sn isEqualToString:ssa->styles[j].name])  {
					re->style = &ssa->styles[j];
					break;
				}
			}

			if (!re->style) {
				re->style = ssa->defaultstyle;
			}

			re->marginl = [[ar objectAtIndex:5] intValue];
			re->marginr = [[ar objectAtIndex:6] intValue];
			re->marginv = [[ar objectAtIndex:7] intValue];

			if (re->marginl == 0) re->marginl = re->style->marginl; else ldirty = TRUE;
			if (re->marginr == 0) re->marginr = re->style->marginr; else ldirty = TRUE;
			if (re->marginv == 0) re->marginv = re->style->marginv; else ldirty = TRUE;

			if (ldirty) {
				ATSUTextMeasurement width;
				ATSUAttributeTag tag[] = {kATSULineWidthTag};
				ByteCount		 size[] = {sizeof(ATSUTextMeasurement)};
				ATSUAttributeValuePtr val[] = {&width};

				re->usablewidth = ssa->resX - re->marginl - re->marginr;
				ATSUCreateAndCopyTextLayout(re->style->layout,&re->layout);
				width = IntToFixed(re->usablewidth);

				ATSUSetLayoutControls(re->layout,1,tag,size,val);
				re->disposelayout = YES;
			} else {
				re->usablewidth = re->style->usablewidth;
				re->layout = re->style->layout;
				re->disposelayout = NO;
			}

			re->nstext = [ar objectAtIndex:8];
		}
		len = [re->nstext length];
		re->text = malloc(sizeof(unichar[len]));

		[re->nstext getCharacters:re->text];
		re->style_count = 0;
		re->posx = re->posy = -1;
		re->halign = re->style->halign;
		re->valign = re->style->valign;
		re->multipleruns=NO;

#define end_re \
		cur_range = (NSRange){strbegin - pb, p - strbegin};\
		cur_range.location -= outputoffset;\
		cur_range.length -= lengthreduce;\
		[re increasestyles];\
		re->styles[re->style_count-1] = [[SSAStyleSpan alloc] init];\
		re->styles[re->style_count-1]->outline = cur_outline;\
		re->styles[re->style_count-1]->shadow = cur_shadow;\
		re->styles[re->style_count-1]->astyle = cur_style;\
		re->styles[re->style_count-1]->range = cur_range;\
		re->styles[re->style_count-1]->outlineblur = cur_be;\
		re->styles[re->style_count-1]->color = cur_color;\
		parsetmp = [NSString stringWithCharacters:skipbegin length:p-skipbegin];\
		[output appendString:parsetmp]; \
		re->nstext = dtmp = output;\
		re->text = malloc(sizeof(unichar[[re->nstext length]]));\
		[re->nstext getCharacters:re->text];\
		[re->nstext retain];

		{
			NSRange cur_range = {0,0};
			ATSUStyle cur_style;
			ATSUTextLayout cur_layout;
			NSMutableString *output = [NSMutableString string], *dtmp;
			unichar *p = re->text, *pe = &re->text[len], *numbegin, *strbegin = p, *skipbegin = p, *intbegin, *pb = p, *posbegin, *strparambegin;
			float num, cur_outline = re->style->outline, cur_shadow = re->style->shadow;
			NSString *parsetmp;
			int cs, cur_valign=re->valign, cur_halign=re->halign, cur_posx, cur_posy;
			ssacolors cur_color = re->style->color;

			unsigned long inum;
			unsigned outputoffset=0, lengthreduce=0;
			BOOL flag, newLayout=FALSE, cur_be = FALSE;
			Fixed fixv;

			ATSUCreateAndCopyStyle(re->style->atsustyle,&cur_style);

			%%{
				alphtype unsigned short;

				action bold {SetATSUStyleFlag(cur_style, kATSUQDBoldfaceTag, flag);}

				action italic {SetATSUStyleFlag(cur_style, kATSUQDItalicTag, flag);}

				action uline {SetATSUStyleFlag(cur_style, kATSUQDUnderlineTag, flag);}

				action strike {SetATSUStyleFlag(cur_style, kATSUStyleStrikeThroughTag, flag);}

				action bordersize {cur_outline = num; re->multipleruns = YES;}

				action shadowsize {cur_shadow = num; re->multipleruns = YES;}

				action bluredge {cur_be = flag;}

				action frot {
					if (!newLayout) {
						newLayout = TRUE;
						ATSUCreateAndCopyTextLayout(re->layout,&cur_layout);
					}
					fixv = FloatToFixed(num);

					SetATSULayoutOther(cur_layout, kATSULineRotationTag, sizeof(Fixed), &fixv);
				}

				action fsize {
					fixv = FloatToFixed(num);
					SetATSUStyleOther(cur_style, kATSUSizeTag, sizeof(fixv), &fixv);
				}

				action fn_begin {
					strparambegin = p;
				}

				action fontname {
					ATSUFontID	font;
					font = FMGetFontFromATSFontRef(ATSFontFindFromName((CFStringRef)[NSString stringWithCharacters:strparambegin length:p-strparambegin],kATSOptionFlagsDefault));
					SetATSUStyleOther(cur_style, kATSUFontTag, sizeof(ATSUFontID), &font);
				}

				action alignment {
					if (!newLayout) {
						newLayout = TRUE;
						ATSUCreateAndCopyTextLayout(re->layout,&cur_layout);
					}

					if (ssa->version == S_SSA) inum = SSA2ASSAlignment(inum);

					switch (inum)
					{case 1: case 4: case 7: cur_halign = S_LeftAlign; break;
					case 2: case 5: case 8: default: cur_halign = S_CenterAlign; break;
					case 3: case 6: case 9: cur_halign = S_RightAlign;}

					switch (inum)
					{case 1: case 2: case 3: default: cur_valign = S_BottomAlign; break;
					case 4: case 5: case 6: cur_valign = S_MiddleAlign; break;
					case 7: case 8: case 9: cur_valign = S_TopAlign;}

					Fract alignment;

					if (cur_posx != -1) {
						switch(cur_halign) {
							case S_LeftAlign:
								alignment = FloatToFract(0.);
								break;
							case S_CenterAlign: default:
								alignment = kATSUCenterAlignment;
								break;
							case S_RightAlign:
								alignment = FloatToFract(1.);
						}
						SetATSULayoutOther(cur_layout, kATSULineFlushFactorTag, sizeof(Fract), &alignment);
					}
				}

				action pos_begin {
					posbegin=p;
				}

				action pos_end {
					if (!newLayout) {
						newLayout = TRUE;
						ATSUCreateAndCopyTextLayout(re->layout,&cur_layout);
					}
					NSArray *coo = [[NSString stringWithCharacters:posbegin length:p-posbegin] componentsSeparatedByString:@","];
					cur_posx = [[coo objectAtIndex:0] intValue];
					cur_posy = [[coo objectAtIndex:1] intValue];

					Fract alignment = FloatToFract(0);

					SetATSULayoutOther(cur_layout, kATSULineFlushFactorTag, sizeof(Fract), &alignment);
				}

				action primarycolor {
					cur_color.primary = ParseColorTag(inum,cur_color.primary.alpha);
					re->multipleruns = YES;
				}

				action outlinecolor {
					cur_color.outline = ParseColorTag(inum,cur_color.outline.alpha);
					re->multipleruns = YES;
				}

				action shadowcolor {
					cur_color.shadow = ParseColorTag(inum,cur_color.shadow.alpha);
					re->multipleruns = YES;
				}

				action nl_handler {
					parsetmp = [NSString stringWithCharacters:skipbegin length:(p-2)-skipbegin];
					[output appendString:parsetmp];

					skipbegin = p;

					[output appendString:@"\n"];

					lengthreduce++;
				}

				action enter_tag {
					parsetmp = [NSString stringWithCharacters:skipbegin length:p-skipbegin];
					[output appendString:parsetmp];

					cur_range = (NSRange){strbegin - pb, p - strbegin};
					cur_range.location -= outputoffset;
					cur_range.length -= lengthreduce;

					outputoffset += lengthreduce;
					lengthreduce = 0;

					skipbegin = p;

					[re increasestyles];
					re->styles[re->style_count-1] = [[SSAStyleSpan alloc] init];
					re->styles[re->style_count-1]->outline = cur_outline;
					re->styles[re->style_count-1]->shadow = cur_shadow;
					re->styles[re->style_count-1]->astyle = cur_style;
					re->styles[re->style_count-1]->range = cur_range;
					re->styles[re->style_count-1]->outlineblur = cur_be;
					re->styles[re->style_count-1]->color = cur_color;
					ATSUCreateAndCopyStyle(cur_style,&cur_style);
				}

				action exit_tag {
					outputoffset += p - skipbegin;
					skipbegin = p;
					strbegin = p;

					if (newLayout) {
						newLayout = FALSE;
						end_re;

						if ([re->nstext length] != 0) [rentities addObject:re];

						SSARenderEntity *nre = [[SSARenderEntity alloc] init];
						nre->layer = re->layer;
						nre->style = re->style;
						nre->marginl = re->marginl; nre->marginr = re->marginr; nre->marginv = re->marginv; nre->usablewidth = re->usablewidth;
						nre->posx = cur_posx; nre->posy = cur_posy; nre->halign = cur_halign; nre->valign = cur_valign;
						nre->nstext = nil;
						nre->text = nil;
						nre->layout = cur_layout;
						nre->styles = malloc(0);
						nre->style_count = 0;
						nre->disposelayout = YES;
						nre->multipleruns = NO;
						re = nre;
					}
				}

				action color_end {
					NSString *hexn = [NSString stringWithCharacters:intbegin length:p-intbegin];
					inum = strtoul([hexn UTF8String], NULL, 16);
				}

				flag = ([01] % {unichar fl = *(p-1); if (flag == '0' || flag == '1') flag = fl - '0';})? > {flag = 1;};
				num_ = digit+ ('.' digit*)?;
				num = num_ > {numbegin = p;} % {num = [[NSString stringWithCharacters:numbegin length:p-numbegin] doubleValue];};

				intnum = digit* > {intbegin = p;} % {inum = [[NSString stringWithCharacters:intbegin length:p-intbegin] intValue];};

				color = "&H" xdigit* > {intbegin = p;} % color_end "&";

				cmd_specific = (("pos(" [^)]+ > pos_begin ")" % pos_end)
								|"bord" num %bordersize
								|"b" :> flag %bold
								|"be" flag %bluredge
								|"i" flag %italic
								|"u" flag %uline
								|"s" flag %strike
								|"fad" [^\\}]*
								|"fs" num %fsize
								|("fr" "z"? num %frot)
								|("fn" [^\\}]* > fn_begin %fontname)
								|"shad" num %shadowsize
								|"an" intnum %alignment
								|"1"? "c" color %primarycolor
								|"3c" color %outlinecolor
								|"4c" color %shadowcolor
								);

				cmd = "\\"  cmd_specific ;

				tag = "{" ((cmd*) | ([^\\}]*)) "}";

				nl = "\\" [Nn];

				special = nl % nl_handler |
						 (tag > enter_tag % exit_tag);

				text = any*;
				main := (text :> special?)*;
			}%%

			%%write init;
			%%write exec;
			%%write eof;

			if (re->text[len-1] == '}') skipbegin = p; // make up for how exit_tag isn't called if the } is the last char in the line

			end_re;

			PruneEmptyStyleSpans(re);

			free(pb);
			if ([re->nstext length] != 0) [rentities addObject:re];
		}

	}

	return rentities;
}