filters
amiproparser.cpp00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "amiproparser.h"
00021
00022 #include <qfile.h>
00023 #include <qstring.h>
00024 #include <qstringlist.h>
00025 #include <qtextstream.h>
00026
00027 const float AmiPro::LS_Single = -1;
00028 const float AmiPro::LS_OneAndHalf = -1.5;
00029 const float AmiPro::LS_Double = -2;
00030
00031
00032 static QString AmiProUnescape( const QString& str )
00033 {
00034 QString result;
00035
00036 for( unsigned i=0; i< str.length(); i++ )
00037 {
00038 QChar c = str[i];
00039 result.append( c );
00040
00041
00042 if( c == '@' )
00043 if( str[i+1] == '@' )
00044 i++ ;
00045
00046
00047 if( c == '<' )
00048 {
00049
00050
00051 if( str[i+1] == '<' )
00052 {
00053 result.truncate( result.length() - 1 );
00054 result.append( '<' );
00055 i++;
00056 }
00057
00058
00059 if( str[i+1] == ';' )
00060 {
00061 result.truncate( result.length() - 1 );
00062 result.append( '>' );
00063 i+=2;
00064 }
00065
00066
00067 if( str[i+1] == '[' )
00068 {
00069 result.truncate( result.length() - 1 );
00070 result.append( '[' );
00071 i+=2;
00072 }
00073
00074
00075 if( str[i+1] == '/' )
00076 {
00077 if( str[i+2] == 'R' )
00078 {
00079 result.truncate( result.length() - 1 );
00080 result.append( '\'' );
00081 i += 3;
00082 }
00083 else
00084 {
00085 result.truncate( result.length() - 1 );
00086 result.append( QChar(str[i+2].unicode() + 0x40 ) );
00087 i += 3;
00088 }
00089 }
00090
00091
00092 if( str[i+1] == '\\' )
00093 {
00094 result.truncate( result.length() - 1 );
00095 result.append( QChar(str[i+2].unicode() | 0x80 ) );
00096 i += 3;
00097 }
00098
00099 }
00100
00101 }
00102
00103 return result;
00104 }
00105
00106 AmiProParser::AmiProParser()
00107 {
00108 m_result = OK;
00109 m_listener = NULL;
00110 }
00111
00112 AmiProParser::~AmiProParser()
00113 {
00114 }
00115
00116 bool AmiProParser::setResult( int result )
00117 {
00118 m_result = result;
00119 return m_result == OK;
00120 }
00121
00122 void AmiProParser::setListener( AmiProListener *listener )
00123 {
00124 m_listener = listener;
00125 }
00126
00127 bool AmiProParser::process( const QString& filename )
00128 {
00129 QString line;
00130
00131
00132 QFile in( filename );
00133 if( !in.open( IO_ReadOnly))
00134 return setResult( FileError );
00135
00136 QTextStream stream;
00137 stream.setDevice( &in );
00138
00139
00140 line = stream.readLine();
00141 if( line != "[ver]" )
00142 return setResult( InvalidFormat );
00143
00144
00145 line = stream.readLine();
00146 int format_version = line.toInt();
00147
00148
00149
00150 if( format_version != 4 )
00151 return setResult( InvalidFormat );
00152
00153
00154 m_currentFormat = AmiProFormat();
00155 m_formatList.clear();
00156 m_styleList.clear();
00157 m_currentSection = "";
00158 QStringList lines;
00159
00160
00161 for( ;; )
00162 {
00163
00164 line = stream.readLine();
00165 if( line.isNull() ) break;
00166
00167 QString old_section = m_currentSection;
00168 bool enter_new_section = false;
00169
00170
00171 if( !line.isEmpty() ) if( line[0] == '[' )
00172 {
00173 enter_new_section = true;
00174 m_currentSection = "";
00175 for( unsigned i=1; i<line.length(); i++ )
00176 if( line[i] == ']' ) break;
00177 else m_currentSection += line[i];
00178 }
00179
00180
00181 if( enter_new_section && ( old_section == "tag" ) )
00182 {
00183 parseStyle( lines );
00184 lines.clear();
00185 }
00186
00187
00188 if( enter_new_section && ( old_section == "edoc" ) )
00189 {
00190 parseParagraph( lines.join(" ") );
00191 lines.clear();
00192 }
00193
00194
00195 if( !enter_new_section && ( old_section == "tag" ) )
00196 {
00197 lines.append( line );
00198 }
00199
00200
00201 if( !enter_new_section && ( old_section == "edoc" ) )
00202 {
00203 if( line.isEmpty() )
00204 {
00205 parseParagraph( lines );
00206 lines.clear();
00207 }
00208 lines.append( line );
00209 }
00210
00211
00212 if( enter_new_section && ( m_currentSection == "tag" ) )
00213 {
00214 lines.clear();
00215 }
00216
00217
00218 if( enter_new_section && ( m_currentSection == "edoc" ) )
00219 {
00220 processOpenDocument();
00221 lines.clear();
00222 }
00223
00224 }
00225
00226
00227 if( lines.count() > 0 ) parseParagraph( lines.join( " " ) );
00228
00229 processCloseDocument();
00230
00231 return true;
00232 }
00233
00234 bool AmiProParser::processOpenDocument()
00235 {
00236 if( m_listener ) return m_listener->doOpenDocument();
00237 return true;
00238 }
00239
00240 bool AmiProParser::processCloseDocument()
00241 {
00242 if( m_listener )
00243 return m_listener->doCloseDocument();
00244 return true;
00245 }
00246
00247 bool AmiProParser::parseParagraph( const QStringList& lines )
00248 {
00249 m_text = "";
00250 m_formatList.clear();
00251 m_layout = AmiProLayout();
00252
00253
00254 QString partext = "";
00255 for( unsigned i=0; i<lines.count(); i++ )
00256 if( lines[i][0] == '>' ) break;
00257 else partext.append( lines[i] + "\n" );
00258
00259 QChar ch = partext[partext.length()-1];
00260 while( ( ch == '\n' ) || ( ch == '\r' ) )
00261 {
00262 partext.remove( partext.length()-1, 1 );
00263 ch = partext[partext.length()-1];
00264 }
00265
00266
00267 QString text = AmiProUnescape( partext );
00268
00269
00270 m_layout.applyStyle( findStyle( "Body Text" ) );
00271
00272 for( unsigned i=0; i<text.length(); i++ )
00273 {
00274 QChar ch = text[i];
00275
00276
00277 if( ch == '<' )
00278 {
00279 QString tag = "";
00280 for( i++; (i < text.length()) &&
00281 (text[i] != '>'); i++) tag.append( text[i] );
00282 handleTag( tag );
00283 }
00284
00285 else
00286
00287
00288 if( ch == '@' )
00289 {
00290 QString styleName;
00291 for( i++; (i < partext.length()) && (partext[i] != '@'); i++)
00292 styleName += partext[i];
00293 m_layout.name = styleName;
00294 AmiProStyle style = findStyle( styleName );
00295 m_currentFormat.applyStyle( style );
00296 m_formatList.append( m_currentFormat );
00297 m_layout.applyStyle( style );
00298 }
00299
00300 else
00301
00302 m_text.append( ch );
00303 }
00304
00305
00306 for( unsigned j=0; j<m_formatList.count(); j++ )
00307 {
00308 int nextpos;
00309 AmiProFormat& format = m_formatList[j];
00310 if( j < m_formatList.count()-1 )
00311 {
00312 AmiProFormat& nextformat = m_formatList[j+1];
00313 nextpos = nextformat.pos;
00314 }
00315 else nextpos = m_text.length();
00316 format.len = nextpos - format.pos;
00317 }
00318
00319 if( m_listener )
00320 return m_listener->doParagraph( m_text, m_formatList, m_layout );
00321
00322 return true;
00323 }
00324
00325 bool AmiProParser::parseStyle( const QStringList& lines )
00326 {
00327 AmiProStyle style;
00328
00329 style.name = AmiProUnescape( lines[0].stripWhiteSpace() );
00330 if( style.name.isEmpty() ) return true;
00331
00332
00333 if( lines[2].stripWhiteSpace() != "[fnt]" ) return true;
00334 style.fontFamily = lines[3].stripWhiteSpace();
00335 style.fontSize = lines[4].stripWhiteSpace().toFloat() / 20.0;
00336
00337 unsigned color = lines[5].stripWhiteSpace().toUInt();
00338 style.fontColor.setRgb( color&255, (color>>8)&255, (color>>16)&255);
00339
00340 unsigned flag = lines[6].stripWhiteSpace().toUInt();
00341 style.bold = flag & 1;
00342 style.italic = flag & 2;
00343 style.underline = flag & 4;
00344 style.word_underline = flag & 8;
00345 style.double_underline = flag & 64;
00346
00347
00348 if( lines[7].stripWhiteSpace() != "[algn]" ) return true;
00349 unsigned align_flag = lines[8].stripWhiteSpace().toUInt();
00350 if( align_flag & 1 ) style.align = Qt::AlignLeft;
00351 if( align_flag & 2 ) style.align = Qt::AlignRight;
00352 if( align_flag & 4 ) style.align = Qt::AlignCenter;
00353 if( align_flag & 8 ) style.align = Qt::AlignJustify;
00354
00355
00356 if( lines[13].stripWhiteSpace() != "[spc]" ) return true;
00357 unsigned ls_flag = lines[14].stripWhiteSpace().toUInt();
00358 if( ls_flag & 1 ) style.linespace = AmiPro::LS_Single;
00359 if( ls_flag & 2 ) style.linespace = AmiPro::LS_OneAndHalf;
00360 if( ls_flag & 4 ) style.linespace = AmiPro::LS_Double;
00361 if( ls_flag & 8 )
00362 style.linespace = lines[15].stripWhiteSpace().toFloat() / 20.0;
00363 style.spaceBefore = lines[17].stripWhiteSpace().toFloat() / 20.0;
00364 style.spaceAfter = lines[18].stripWhiteSpace().toFloat() / 20.0;
00365
00366 m_styleList.append( style );
00367
00368
00369
00370 if( style.name.left( 7 ) != "Style #" )
00371 if( m_listener )
00372 return m_listener->doDefineStyle( style );
00373 return true;
00374 }
00375
00376 AmiProStyle AmiProParser::findStyle( const QString& name )
00377 {
00378 AmiProStyleList::iterator it;
00379 for( it=m_styleList.begin(); it!=m_styleList.end(); ++it )
00380 {
00381 AmiProStyle& style = *it;
00382 if( style.name == name )
00383 return style;
00384 }
00385 return AmiProStyle();
00386 }
00387
00388 bool AmiProParser::handleTag( const QString& tag )
00389 {
00390
00391 if( tag == ";" )
00392 m_text.append( ">" );
00393
00394
00395 if( tag == "[" )
00396 m_text.append( "[" );
00397
00398
00399 if( tag == "+!" )
00400 {
00401 m_currentFormat.bold = true;
00402 m_currentFormat.pos = m_text.length();
00403 m_formatList.append( m_currentFormat );
00404 }
00405
00406
00407 if( tag == "-!" )
00408 {
00409 m_currentFormat.bold = false;
00410 m_currentFormat.pos = m_text.length();
00411 m_formatList.append( m_currentFormat );
00412 }
00413
00414
00415 if( tag == "+\"" )
00416 {
00417 m_currentFormat.italic = true;
00418 m_currentFormat.pos = m_text.length();
00419 m_formatList.append( m_currentFormat );
00420 }
00421
00422
00423 if( tag == "-\"" )
00424 {
00425 m_currentFormat.italic = false;
00426 m_currentFormat.pos = m_text.length();
00427 m_formatList.append( m_currentFormat );
00428 }
00429
00430
00431 if( tag == "+#" )
00432 {
00433 m_currentFormat.underline = true;
00434 m_currentFormat.pos = m_text.length();
00435 m_formatList.append( m_currentFormat );
00436 }
00437
00438
00439 if( tag == "-#" )
00440 {
00441 m_currentFormat.underline = false;
00442 m_currentFormat.pos = m_text.length();
00443 m_formatList.append( m_currentFormat );
00444 }
00445
00446
00447 if( tag == "+)" )
00448 {
00449 m_currentFormat.double_underline = true;
00450 m_currentFormat.pos = m_text.length();
00451 m_formatList.append( m_currentFormat );
00452 }
00453
00454
00455 if( tag == "-)" )
00456 {
00457 m_currentFormat.double_underline = false;
00458 m_currentFormat.pos = m_text.length();
00459 m_formatList.append( m_currentFormat );
00460 }
00461
00462
00463 if( tag == "+$" )
00464 {
00465 m_currentFormat.word_underline = true;
00466 m_currentFormat.pos = m_text.length();
00467 m_formatList.append( m_currentFormat );
00468 }
00469
00470
00471 if( tag == "-$" )
00472 {
00473 m_currentFormat.word_underline = false;
00474 m_currentFormat.pos = m_text.length();
00475 m_formatList.append( m_currentFormat );
00476 }
00477
00478
00479 if( tag == "+&" )
00480 {
00481 m_currentFormat.superscript = true;
00482 m_currentFormat.pos = m_text.length();
00483 m_formatList.append( m_currentFormat );
00484 }
00485
00486
00487 if( tag == "-&" )
00488 {
00489 m_currentFormat.superscript = false;
00490 m_currentFormat.pos = m_text.length();
00491 m_formatList.append( m_currentFormat );
00492 }
00493
00494
00495 if( tag == "+'" )
00496 {
00497 m_currentFormat.subscript = true;
00498 m_currentFormat.pos = m_text.length();
00499 m_formatList.append( m_currentFormat );
00500 }
00501
00502
00503 if( tag == "-'" )
00504 {
00505 m_currentFormat.subscript = false;
00506 m_currentFormat.pos = m_text.length();
00507 m_formatList.append( m_currentFormat );
00508 }
00509
00510
00511 if( tag == "+%" )
00512 {
00513 m_currentFormat.strikethrough = true;
00514 m_currentFormat.pos = m_text.length();
00515 m_formatList.append( m_currentFormat );
00516 }
00517
00518
00519 if( tag == "-%" )
00520 {
00521 m_currentFormat.strikethrough = false;
00522 m_currentFormat.pos = m_text.length();
00523 m_formatList.append( m_currentFormat );
00524 }
00525
00526
00527 if( tag == "+@" )
00528 m_layout.align = Qt::AlignLeft;
00529
00530
00531 if( tag == "+A" )
00532 m_layout.align = Qt::AlignRight;
00533
00534
00535 if( tag == "+B" )
00536 m_layout.align = Qt::AlignCenter;
00537
00538
00539 if( tag == "+C" )
00540 m_layout.align = Qt::AlignJustify;
00541
00542
00543 if( tag.left( 3 ) == ":S+" )
00544 {
00545 float ls = tag.right( tag.length() - 3 ).toFloat();
00546 m_layout.linespace = (ls == -1) ? AmiPro::LS_Single :
00547 (ls == -2) ? AmiPro::LS_OneAndHalf :
00548 (ls == -3) ? AmiPro::LS_Double : ls / 20.0;
00549 }
00550
00551
00552 if( tag.left( 2 ) == ":f" )
00553 {
00554 QString fontdesc = tag.right( tag.length()-2 );
00555 QStringList desc = QStringList::split( ",", fontdesc );
00556 if( desc.count() > 0 ) m_currentFormat.fontSize = desc[0].toFloat() / 20.0;
00557 if( desc.count() > 1 )
00558 {
00559 QString fontFamily = desc[1];
00560 if( fontFamily[0].isDigit() ) fontFamily.remove( 0, 1 );
00561 m_currentFormat.fontFamily = fontFamily;
00562 }
00563 if( desc.count() > 4 )
00564 {
00565 unsigned red = desc[2].toUInt();
00566 unsigned green = desc[3].toUInt();
00567 unsigned blue = desc[4].toUInt();
00568 m_currentFormat.fontColor.setRgb( red, green, blue );
00569 }
00570 m_formatList.append( m_currentFormat );
00571 }
00572
00573 return true;
00574 }
00575
00576
00577 AmiProFormat::AmiProFormat()
00578 {
00579 pos = len = 0;
00580 bold = italic = underline =
00581 word_underline = double_underline =
00582 subscript = superscript = strikethrough = FALSE;
00583 fontFamily = "";
00584 fontSize = 12;
00585 fontColor = Qt::black;
00586 }
00587
00588 void AmiProFormat::assign( const AmiProFormat& f )
00589 {
00590 pos = f.pos;
00591 len = f.len;
00592 bold = f.bold;
00593 italic = f.italic;
00594 underline = f.underline;
00595 word_underline = f.word_underline;
00596 double_underline = f.double_underline;
00597 subscript = f.subscript;
00598 superscript = f.superscript;
00599 strikethrough = f.strikethrough;
00600 fontFamily = f.fontFamily;
00601 fontSize = f.fontSize;
00602 fontColor = f.fontColor;
00603 }
00604
00605 AmiProFormat::AmiProFormat( const AmiProFormat& f )
00606 {
00607 assign( f );
00608 }
00609
00610 AmiProFormat& AmiProFormat::operator=( const AmiProFormat& f )
00611 {
00612 assign( f );
00613 return *this;
00614 }
00615
00616 void AmiProFormat::applyStyle( const AmiProStyle& style )
00617 {
00618 fontFamily = style.fontFamily;
00619 fontSize = style.fontSize;
00620 fontColor = style.fontColor;
00621 bold = style.bold;
00622 italic = style.italic;
00623 underline = style.underline;
00624 word_underline = style.word_underline;
00625 double_underline = style.double_underline;
00626 subscript = style.subscript;
00627 superscript = style.superscript;
00628 strikethrough = style.strikethrough;
00629 }
00630
00631
00632 AmiProLayout::AmiProLayout()
00633 {
00634 name = "";
00635 fontFamily = "";
00636 fontSize = 12;
00637 fontColor = Qt::black;
00638 bold = italic = underline =
00639 word_underline = double_underline =
00640 subscript = superscript = strikethrough = FALSE;
00641 align = Qt::AlignLeft;
00642 linespace = AmiPro::LS_Single;
00643 spaceBefore = spaceAfter = 0;
00644 }
00645
00646 void AmiProLayout::assign( const AmiProLayout &l )
00647 {
00648 name = l.name;
00649 fontFamily = l.fontFamily;
00650 fontSize = l.fontSize;
00651 fontColor = l.fontColor;
00652 bold = l.bold;
00653 italic = l.italic;
00654 underline = l.underline;
00655 word_underline = l.word_underline;
00656 double_underline = l.double_underline;
00657 subscript = l.subscript;
00658 superscript = l.superscript;
00659 strikethrough = l.strikethrough;
00660 align = l.align;
00661 linespace = l.linespace;
00662 spaceBefore = l.spaceBefore;
00663 spaceAfter = l.spaceAfter;
00664 }
00665
00666 AmiProLayout::AmiProLayout( const AmiProLayout& l )
00667 {
00668 assign( l );
00669 }
00670
00671 AmiProLayout& AmiProLayout::operator=( const AmiProLayout& l )
00672 {
00673 assign( l );
00674 return *this;
00675 }
00676
00677 void AmiProLayout::applyStyle( const AmiProStyle& style )
00678 {
00679 fontFamily = style.fontFamily;
00680 fontSize = style.fontSize;
00681 fontColor = style.fontColor;
00682 bold = style.bold;
00683 italic = style.italic;
00684 underline = style.underline;
00685 word_underline = style.word_underline;
00686 double_underline = style.double_underline;
00687 subscript = style.subscript;
00688 superscript = style.superscript;
00689 strikethrough = style.strikethrough;
00690 align = style.align;
00691 linespace = style.linespace;
00692 spaceBefore = style.spaceBefore;
00693 spaceAfter = style.spaceAfter;
00694 }
00695
00696
00697 AmiProStyle::AmiProStyle()
00698 {
00699 name = "Unnamed";
00700 fontFamily = "";
00701 fontSize = 12;
00702 fontColor = Qt::black;
00703 bold = italic = underline =
00704 word_underline = double_underline =
00705 subscript = superscript = strikethrough = FALSE;
00706 linespace = AmiPro::LS_Single;
00707 spaceBefore = spaceAfter = 0;
00708 }
00709
00710 void AmiProStyle::assign( const AmiProStyle& s )
00711 {
00712 name = s.name;
00713 fontFamily = s.fontFamily;
00714 fontSize = s.fontSize;
00715 fontColor = s.fontColor;
00716 bold = s.bold;
00717 italic = s.italic;
00718 underline = s.underline;
00719 word_underline = s.word_underline;
00720 double_underline = s.double_underline;
00721 subscript = s.subscript;
00722 superscript = s.superscript;
00723 strikethrough = s.strikethrough;
00724 align = s.align;
00725 linespace = s.linespace;
00726 spaceBefore = s.spaceBefore;
00727 spaceAfter = s.spaceAfter;
00728 }
00729
00730 AmiProStyle::AmiProStyle( const AmiProStyle& s )
00731 {
00732 assign( s );
00733 }
00734
00735 AmiProStyle& AmiProStyle::operator=( const AmiProStyle& s )
00736 {
00737 assign( s );
00738 return *this;
00739 }
00740
00741
00742 AmiProListener::AmiProListener()
00743 {
00744 }
00745
00746 AmiProListener::~AmiProListener()
00747 {
00748 }
00749
00750 #define DO_TRUE_DEFINITION(string) \
00751 bool AmiProListener::string \
00752 {\
00753 return true;\
00754 }
00755
00756 DO_TRUE_DEFINITION(doOpenDocument())
00757 DO_TRUE_DEFINITION(doCloseDocument())
00758 DO_TRUE_DEFINITION(doDefineStyle(const AmiProStyle& style))
00759 DO_TRUE_DEFINITION(doParagraph(const QString& text, AmiProFormatList formatList,
00760 AmiProLayout& ))
|