private bool HandleTag( TextReader reader, IRtfTag tag )
{
if ( level == 0 )
{
throw new RtfStructureException( Strings.TagOnRootLevel( tag.ToString() ) );
}
if ( tagCount < 4 )
{
// this only handles the initial encoding tag in the header section
UpdateEncoding( tag );
}
string tagName = tag.Name;
// enable the font name detection in case the last tag was introducing
// a theme font
bool detectFontName = expectingThemeFont;
if ( tagCountAtLastGroupStart == tagCount )
{
// first tag in a group
switch ( tagName )
{
case RtfSpec.TagThemeFontLoMajor:
case RtfSpec.TagThemeFontHiMajor:
case RtfSpec.TagThemeFontDbMajor:
case RtfSpec.TagThemeFontBiMajor:
case RtfSpec.TagThemeFontLoMinor:
case RtfSpec.TagThemeFontHiMinor:
case RtfSpec.TagThemeFontDbMinor:
case RtfSpec.TagThemeFontBiMinor:
// these introduce a new font, but the actual font tag will be
// the second tag in the group, so we must remember this condition ...
expectingThemeFont = true;
break;
}
// always enable the font name detection also for the first tag in a group
detectFontName = true;
}
if ( detectFontName )
{
// first tag in a group:
switch ( tagName )
{
case RtfSpec.TagFont:
if ( fontTableStartLevel > 0 )
{
// in the font-table definition:
// -> remember the target font for charset mapping
targetFont = tag.FullName;
expectingThemeFont = false; // reset that state now
}
break;
case RtfSpec.TagFontTable:
// -> remember we're in the font-table definition
fontTableStartLevel = level;
break;
}
}
if ( targetFont != null )
{
// within a font-tables font definition: perform charset mapping
if ( RtfSpec.TagFontCharset.Equals( tagName ) )
{
int charSet = tag.ValueAsNumber;
int codePage = RtfSpec.GetCodePage( charSet );
fontToCodePageMapping[ targetFont ] = codePage;
UpdateEncoding( codePage );
}
}
if ( fontToCodePageMapping.Count > 0 && RtfSpec.TagFont.Equals( tagName ) )
{
int? codePage = (int?)fontToCodePageMapping[ tag.FullName ];
if ( codePage != null )
{
UpdateEncoding( codePage.Value );
}
}
bool skippedContent = false;
switch ( tagName )
{
case RtfSpec.TagUnicodeCode:
int unicodeValue = tag.ValueAsNumber;
char unicodeChar = (char)unicodeValue;
curText.Append( unicodeChar );
// skip over the indicated number of 'alternative representation' text
for ( int i = 0; i < unicodeSkipCount; i++ )
{
int nextChar = PeekNextChar( reader, true );
switch ( nextChar )
{
case ' ':
case '\r':
case '\n':
reader.Read(); // consume peeked char
skippedContent = true;
if ( i == 0 )
{
// the first whitespace after the tag
// -> only a delimiter, doesn't count for skipping ...
i--;
}
break;
case '\\':
reader.Read(); // consume peeked char
skippedContent = true;
int secondChar = ReadOneByte( reader ); // mandatory
switch ( secondChar )
{
case '\'':
// ok, this is a hex-encoded 'byte' -> need to consume both
// hex digits too
ReadOneByte( reader ); // high nibble
ReadOneByte( reader ); // low nibble
break;
}
break;
case '{':
case '}':
// don't consume peeked char and abort skipping
i = unicodeSkipCount;
break;
default:
reader.Read(); // consume peeked char
skippedContent = true;
break;
}
}
break;
case RtfSpec.TagUnicodeSkipCount:
int newSkipCount = tag.ValueAsNumber;
if ( newSkipCount < 0 || newSkipCount > 10 )
{
throw new RtfUnicodeEncodingException( Strings.InvalidUnicodeSkipCount( tag.ToString() ) );
}
unicodeSkipCount = newSkipCount;
break;
default:
FlushText();
NotifyTagFound( tag );
break;
}
tagCount++;
return skippedContent;
}