Warning, file /office/calligra/filters/karbon/xfig/XFigParser.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     This file is part of the Calligra project, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2012 Friedrich W. H. Kossebau <kossebau@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include "XFigParser.h"
0010 
0011 // filter
0012 #include "XFigDocument.h"
0013 // Qt
0014 #include <QTextStream>
0015 #include <QTextCodec>
0016 #include <QIODevice>
0017 #include <QFont>
0018 #include <QScopedPointer>
0019 
0020 #include <QDebug>
0021 
0022 
0023 enum XFig3_2TextFlag {
0024     XFig3_2TextNotScaled =  1 << 0,
0025     XFig3_2TextForLaTeX =   1 << 1,
0026     XFig3_2TextPostScriptFont = 1 << 2,
0027     XFig3_2TextHidden =     1 << 3
0028 };
0029 
0030 enum XFig3_2ObjectCode
0031 {
0032     XFig3_2CompoundObjectEndId = -6,
0033     XFig3_2ColorObjectId = 0,
0034     XFig3_2EllipseObjectId = 1,
0035     XFig3_2PolylineObjectId = 2,
0036     XFig3_2SplineObjectId = 3,
0037     XFig3_2TextObjectId = 4,
0038     XFig3_2ArcObjectId = 5,
0039     XFig3_2CompoundObjectId = 6
0040 };
0041 
0042 enum XFig3_2ArcSubTypeCode
0043 {
0044     XFig3_2ArcOpenEndedId = 1,
0045     XFig3_2ArcPieWedgeId= 2
0046 };
0047 
0048 enum XFig3_2PolylineSubTypeCode
0049 {
0050     XFig3_2PolylinePolylineId = 1,
0051     XFig3_2PolylineBoxId = 2,
0052     XFig3_2PolylinePolygonId = 3,
0053     XFig3_2PolylineArcBoxId = 4,
0054     XFig3_2PolylinePictureBoundingBoxId = 5
0055 };
0056 
0057 enum XFig3_2SplineSubtypeCode
0058 {
0059     XFig3_2SplineOpenApproximatedId  = 0,
0060     XFig3_2SplineClosedApproximatedId  = 1,
0061     XFig3_2SplineOpenInterpolatedId  = 2,
0062     XFig3_2SplineClosedInterpolatedId  = 3,
0063     XFig3_2SplineOpenXId  = 4,
0064     XFig3_2SplineClosedXId  = 5
0065 };
0066 
0067 enum XFig3_2TextAlignment {
0068     XFig3_2TextLeftAligned = 0,
0069     XFig3_2TextCenterAligned = 1,
0070     XFig3_2TextRightAligned = 2
0071 };
0072 
0073 static const int arrowHeadTypeMapSize = 15;
0074 static const
0075 struct { XFigArrowHeadType style[2]; }
0076 arrowHeadTypeMap[arrowHeadTypeMapSize] =
0077 {
0078     { {XFigArrowHeadStick,                     XFigArrowHeadStick} },
0079     { {XFigArrowHeadHollowTriangle,            XFigArrowHeadFilledTriangle} },
0080     { {XFigArrowHeadHollowConcaveSpear,        XFigArrowHeadFilledConcaveSpear} },
0081     { {XFigArrowHeadHollowConvexSpear,         XFigArrowHeadFilledConvexSpear} },
0082     { {XFigArrowHeadHollowDiamond,             XFigArrowHeadFilledDiamond} },
0083     { {XFigArrowHeadHollowCircle,              XFigArrowHeadFilledCircle} },
0084     { {XFigArrowHeadHollowHalfCircle,          XFigArrowHeadFilledHalfCircle} },
0085     { {XFigArrowHeadHollowSquare,              XFigArrowHeadFilledSquare} },
0086     { {XFigArrowHeadHollowReverseTriangle,     XFigArrowHeadFilledReverseTriangle} },
0087     { {XFigArrowHeadTopHalfFilledConcaveSpear, XFigArrowHeadBottomHalfFilledConcaveSpear} },
0088     { {XFigArrowHeadHollowTopHalfTriangle,     XFigArrowHeadFilledTopHalfTriangle} },
0089     { {XFigArrowHeadHollowTopHalfConcaveSpear, XFigArrowHeadFilledTopHalfConcaveSpear} },
0090     { {XFigArrowHeadHollowTopHalfConvexSpear,  XFigArrowHeadFilledTopHalfConvexSpear} },
0091     { {XFigArrowHeadWye,                       XFigArrowHeadBar} },
0092     { {XFigArrowHeadTwoProngFork,              XFigArrowHeadReverseTwoProngFork} }
0093 };
0094 
0095 static inline
0096 XFigArrowHeadType
0097 arrowHeadType( int type3_2, int style3_2 )
0098 {
0099     XFigArrowHeadType result = XFigArrowHeadStick;
0100     if ((0<=type3_2) && (type3_2<arrowHeadTypeMapSize) &&
0101         ((style3_2 == 0) || (style3_2 == 1))) {
0102         result = arrowHeadTypeMap[type3_2].style[style3_2];
0103     }
0104     return result;
0105 }
0106 
0107 enum XFig3_2LineType
0108 {
0109     XFig3_2LineDefault = -1,
0110     XFig3_2LineSolid = 0,
0111     XFig3_2LineDashed = 1,
0112     XFig3_2LineDotted = 2,
0113     XFig3_2LineDashDotted = 3,
0114     XFig3_2LineDashDoubleDotted = 4,
0115     XFig3_2LineDashTrippleDotted = 5
0116 };
0117 
0118 static const
0119 struct { int type3_2; XFigLineType type; }
0120 lineTypeMap[] =
0121 {
0122     { XFig3_2LineDefault, XFigLineDefault },
0123     { XFig3_2LineSolid, XFigLineSolid },
0124     { XFig3_2LineDashed,XFigLineDashed  },
0125     { XFig3_2LineDotted, XFigLineDotted },
0126     { XFig3_2LineDashDotted, XFigLineDashDotted },
0127     { XFig3_2LineDashDoubleDotted,XFigLineDashDoubleDotted  },
0128     { XFig3_2LineDashTrippleDotted, XFigLineDashTrippleDotted }
0129 };
0130 static const int lineTypeMapSize = sizeof(lineTypeMap)/sizeof(lineTypeMap[0]);
0131 
0132 static inline
0133 XFigLineType
0134 lineType( int type3_2 )
0135 {
0136     XFigLineType result = XFigLineDefault;
0137     for (int i = 0; i<lineTypeMapSize; ++i) {
0138         if (lineTypeMap[i].type3_2 == type3_2) {
0139             result = lineTypeMap[i].type;
0140             break;
0141         }
0142     }
0143     return result;
0144 }
0145 
0146 enum XFig3_2CapType
0147 {
0148     XFig3_2CapButt = 0,
0149     XFig3_2CapRound = 1,
0150     XFig3_2CapProjecting = 2,
0151 };
0152 
0153 static const
0154 struct { int type3_2; XFigCapType type; }
0155 capTypeMap[] =
0156 {
0157     {XFig3_2CapButt, XFigCapButt },
0158     {XFig3_2CapRound, XFigCapRound},
0159     {XFig3_2CapProjecting,XFigCapProjecting}
0160 };
0161 static const int capTypeMapSize = sizeof(capTypeMap)/sizeof(capTypeMap[0]);
0162 
0163 static inline
0164 XFigCapType
0165 capType( int type3_2 )
0166 {
0167     XFigCapType result = XFigCapButt;
0168     for (int i = 0; i<capTypeMapSize; ++i) {
0169         if (capTypeMap[i].type3_2 == type3_2) {
0170             result = capTypeMap[i].type;
0171             break;
0172         }
0173     }
0174     return result;
0175 }
0176 
0177 enum XFig3_2JoinType
0178 {
0179     XFig3_2JoinMiter = 0,
0180     XFig3_2JoinRound = 1,
0181     XFig3_2JoinBevel = 2,
0182 };
0183 
0184 static const
0185 struct { int type3_2; XFigJoinType type; }
0186 joinTypeMap[] =
0187 {
0188     {XFig3_2JoinMiter, XFigJoinMiter},
0189     {XFig3_2JoinRound, XFigJoinRound},
0190     {XFig3_2JoinBevel, XFigJoinBevel}
0191 };
0192 static const int joinTypeMapSize = sizeof(joinTypeMap)/sizeof(joinTypeMap[0]);
0193 
0194 static inline
0195 XFigJoinType
0196 joinType( int type3_2 )
0197 {
0198     XFigJoinType result = XFigJoinMiter;
0199     for (int i = 0; i<joinTypeMapSize; ++i) {
0200         if (joinTypeMap[i].type3_2 == type3_2) {
0201             result = joinTypeMap[i].type;
0202             break;
0203         }
0204     }
0205     return result;
0206 }
0207 
0208 static inline
0209 XFigFillType fillType(int type3_2)
0210 {
0211     return
0212         ((0 <= type3_2) && (type3_2 <= 40)) ?  XFigFillSolid :
0213         ((41 <= type3_2) && (type3_2 <= 62)) ? XFigFillPattern :
0214         /*(type3_2 == -1) ?*/                  XFigFillNone;
0215 }
0216 
0217 enum XFig3_2FillPatternType
0218 {
0219     XFig3_2FillLeftDiagonal30Degree = 41,
0220     XFig3_2FillRightDiagonal30Degree = 42,
0221     XFig3_2FillCrossHatch30Degree = 43,
0222     XFig3_2FillLeftDiagonal45Degree = 44,
0223     XFig3_2FillRightDiagonal45Degree = 45,
0224     XFig3_2FillCrossHatch45Degree = 46,
0225     XFig3_2FillHorizontalBricks = 47,
0226     XFig3_2FillVerticalBricks = 48,
0227     XFig3_2FillHorizontalLines = 49,
0228     XFig3_2FillVerticalLines = 50,
0229     XFig3_2FillCrossHatch = 51,
0230     XFig3_2FillHorizontalShinglesSkewedRight = 52,
0231     XFig3_2FillHorizontalShinglesSkewedLeft = 53,
0232     XFig3_2FillVerticalShinglesSkewedDown = 54,
0233     XFig3_2FillVerticalShinglesSkewedUp = 55,
0234     XFig3_2FillFishScales = 56,
0235     XFig3_2FillSmallFishScales = 57,
0236     XFig3_2FillCircles = 58,
0237     XFig3_2FillHexagons = 59,
0238     XFig3_2FillOctagons = 60,
0239     XFig3_2FillHorizontalTireTreads = 61,
0240     XFig3_2FillVerticalTireTreads = 62
0241 };
0242 static const
0243 struct { XFig3_2FillPatternType type3_2; XFigFillPatternType type; }
0244 fillPatternTypeMap[] =
0245 {
0246     {XFig3_2FillLeftDiagonal30Degree, XFigFillLeftDiagonal30Degree},
0247     {XFig3_2FillRightDiagonal30Degree, XFigFillRightDiagonal30Degree},
0248     {XFig3_2FillCrossHatch30Degree, XFigFillCrossHatch30Degree},
0249     {XFig3_2FillLeftDiagonal45Degree, XFigFillLeftDiagonal45Degree},
0250     {XFig3_2FillRightDiagonal45Degree, XFigFillRightDiagonal45Degree},
0251     {XFig3_2FillCrossHatch45Degree, XFigFillCrossHatch45Degree},
0252     {XFig3_2FillHorizontalBricks, XFigFillHorizontalBricks},
0253     {XFig3_2FillVerticalBricks, XFigFillVerticalBricks},
0254     {XFig3_2FillHorizontalLines, XFigFillHorizontalLines},
0255     {XFig3_2FillVerticalLines, XFigFillVerticalLines},
0256     {XFig3_2FillCrossHatch, XFigFillCrossHatch},
0257     {XFig3_2FillHorizontalShinglesSkewedRight, XFigFillHorizontalShinglesSkewedRight},
0258     {XFig3_2FillHorizontalShinglesSkewedLeft, XFigFillHorizontalShinglesSkewedLeft},
0259     {XFig3_2FillVerticalShinglesSkewedDown, XFigFillVerticalShinglesSkewedDown},
0260     {XFig3_2FillVerticalShinglesSkewedUp, XFigFillVerticalShinglesSkewedUp},
0261     {XFig3_2FillFishScales, XFigFillFishScales},
0262     {XFig3_2FillSmallFishScales, XFigFillSmallFishScales},
0263     {XFig3_2FillCircles, XFigFillCircles},
0264     {XFig3_2FillHexagons, XFigFillHexagons},
0265     {XFig3_2FillOctagons, XFigFillOctagons},
0266     {XFig3_2FillHorizontalTireTreads, XFigFillHorizontalTireTreads},
0267     {XFig3_2FillVerticalTireTreads, XFigFillVerticalTireTreads}
0268 };
0269 static const int fillPatternTypeMapSize = sizeof(fillPatternTypeMap)/sizeof(fillPatternTypeMap[0]);
0270 
0271 static inline
0272 XFigFillPatternType fillPatternType(int type3_2)
0273 {
0274     XFigFillPatternType result = XFigFillLeftDiagonal30Degree;
0275     for (int i = 0; i<fillPatternTypeMapSize; ++i) {
0276         if (fillPatternTypeMap[i].type3_2 == type3_2) {
0277             result = fillPatternTypeMap[i].type;
0278             break;
0279         }
0280     }
0281     return result;
0282 }
0283 
0284 static const
0285 struct XFig3_2PostScriptFontData {
0286     const char* family;
0287     QFont::Weight weight;
0288     QFont::Style style;
0289 } postScriptFontDataTable[35] = {
0290     { "times", QFont::Normal, QFont::StyleNormal },         // Times Roman
0291     { "times", QFont::Normal, QFont::StyleItalic },         // Times Italic
0292     { "times", QFont::Bold, QFont::StyleNormal },           // Times Bold
0293     { "times", QFont::Bold, QFont::StyleItalic },           // Times Bold Italic
0294     { "avantgarde", QFont::Normal, QFont::StyleNormal },    // AvantGarde Book
0295     { "avantgarde", QFont::Normal, QFont::StyleOblique },   // AvantGarde Book Oblique
0296     { "avantgarde", QFont::DemiBold, QFont::StyleNormal },  // AvantGarde Demi
0297     { "avantgarde", QFont::DemiBold, QFont::StyleOblique }, // AvantGarde Demi Oblique
0298     { "bookman", QFont::Light, QFont::StyleNormal },        // Bookman Light
0299     { "bookman", QFont::Light, QFont::StyleItalic },        // Bookman Light Italic
0300     { "bookman", QFont::DemiBold, QFont::StyleNormal },     // Bookman Demi
0301     { "bookman", QFont::DemiBold, QFont::StyleItalic },     // Bookman Demi Italic
0302     { "courier", QFont::Normal, QFont::StyleNormal },       // Courier
0303     { "courier", QFont::Normal, QFont::StyleOblique },      // Courier Oblique
0304     { "courier", QFont::Bold, QFont::StyleNormal },         // Courier Bold
0305     { "courier", QFont::Bold, QFont::StyleOblique },        // Courier Bold Oblique
0306     { "helvetica", QFont::Normal, QFont::StyleNormal },     // Helvetica
0307     { "helvetica", QFont::Normal, QFont::StyleOblique },    // Helvetica Oblique
0308     { "helvetica", QFont::Bold, QFont::StyleNormal },       // Helvetica Bold
0309     { "helvetica", QFont::Bold, QFont::StyleOblique },      // Helvetica Bold Oblique
0310     { "helvetica", QFont::Normal, QFont::StyleNormal },     // Helvetica Narrow
0311     { "helvetica", QFont::Normal, QFont::StyleOblique },    // Helvetica Narrow Oblique
0312     { "helvetica", QFont::Bold, QFont::StyleNormal },       // Helvetica Narrow Bold
0313     { "helvetica", QFont::Bold, QFont::StyleOblique },      // Helvetica Narrow Bold Oblique
0314     { "newcenturyschoolbook", QFont::Normal, QFont::StyleNormal }, // New Century Schoolbook
0315     { "newcenturyschoolbook", QFont::Normal, QFont::StyleItalic }, // New Century Italic
0316     { "newcenturyschoolbook", QFont::Bold, QFont::StyleNormal },   // New Century Bold
0317     { "newcenturyschoolbook", QFont::Bold, QFont::StyleItalic },   // New Century Bold Italic
0318     { "palatino", QFont::Normal, QFont::StyleNormal },      // Palatino Roman
0319     { "palatino", QFont::Normal, QFont::StyleItalic },      // Palatino Italic
0320     { "palatino", QFont::Bold, QFont::StyleNormal },        // Palatino Bold
0321     { "palatino", QFont::Bold, QFont::StyleItalic },        // Palatino Bold Italic
0322     { "symbol", QFont::Normal, QFont::StyleNormal },        // Symbol
0323     { "zapfchancery", QFont::Normal, QFont::StyleNormal },  // Zapf Chancery Medium Italic
0324     { "zapfdingbats", QFont::Normal, QFont::StyleNormal },  // Zapf Dingbats
0325 };
0326 
0327 enum XFig3_2LatexFontType{
0328     XFig3_2LatexFontDefault = 0,
0329     XFig3_2LatexFontRoman = 1,
0330     XFig3_2LatexFontBold = 2,
0331     XFig3_2LatexFontItalic = 3,
0332     XFig3_2LatexFontSansSerif = 4,
0333     XFig3_2LatexFontTypewriter = 5
0334 };
0335 
0336 static const
0337 struct PaperSizeIdMap {
0338     const char* stringId;
0339     XFigPageSizeType type;
0340 } paperSizeTable[] = {
0341     { "Letter",  XFigPageSizeLetter },
0342     { "Legal",   XFigPageSizeLegal },
0343     { "Ledger",  XFigPageSizeTabloid },
0344     { "Tabloid", XFigPageSizeTabloid },
0345 
0346     { "A", XFigPageSizeA },
0347     { "B", XFigPageSizeB },
0348     { "C", XFigPageSizeC },
0349     { "D", XFigPageSizeD },
0350     { "E", XFigPageSizeE },
0351 
0352     { "A9", XFigPageSizeA9 },
0353     { "A8", XFigPageSizeA8 },
0354     { "A7", XFigPageSizeA7 },
0355     { "A6", XFigPageSizeA6 },
0356     { "A5", XFigPageSizeA5 },
0357     { "A4", XFigPageSizeA4 },
0358     { "A3", XFigPageSizeA3 },
0359     { "A2", XFigPageSizeA2 },
0360     { "A1", XFigPageSizeA1 },
0361     { "A0", XFigPageSizeA0 },
0362 
0363     { "B10", XFigPageSizeB10 },
0364     { "B9",  XFigPageSizeB9 },
0365     { "B8",  XFigPageSizeB8 },
0366     { "B7",  XFigPageSizeB7 },
0367     { "B6",  XFigPageSizeB6 },
0368     { "B5",  XFigPageSizeB5 },
0369     { "B4",  XFigPageSizeB4 },
0370     { "B3",  XFigPageSizeB3 },
0371     { "B2",  XFigPageSizeB2 },
0372     { "B1",  XFigPageSizeB1 },
0373     { "B0",  XFigPageSizeB0 }
0374 };
0375 static const int paperSizeCount = sizeof(paperSizeTable)/sizeof(paperSizeTable[0]);
0376 
0377 static inline
0378 XFigPageSizeType
0379 pageSizeType( const QString& stringId )
0380 {
0381     XFigPageSizeType result = XFigPageSizeUnknown;
0382     for( int i = 0; i<paperSizeCount; ++i) {
0383         const PaperSizeIdMap& idMap = paperSizeTable[i];
0384         if (stringId == QLatin1String(idMap.stringId)) {
0385             result = idMap.type;
0386             break;
0387         }
0388     }
0389     return result;
0390 }
0391 
0392 XFigDocument*
0393 XFigParser::parse( QIODevice* device )
0394 {
0395     XFigParser parser(device);
0396     XFigDocument* document = parser.takeDocument();
0397     return document;
0398 }
0399 
0400 
0401 XFigParser::XFigParser( QIODevice* device )
0402   : m_Document(0)
0403   , m_XFigStreamLineReader( device )
0404 {
0405     if( (device == 0) || (m_XFigStreamLineReader.hasError()) )
0406         return;
0407 
0408     const QTextCodec* codec = QTextCodec::codecForName("ISO 8859-1");
0409     m_TextDecoder = codec->makeDecoder();
0410 
0411     // setup
0412     if (! parseHeader())
0413         return;
0414 
0415     XFigPage* page = new XFigPage;
0416 
0417     while (! m_XFigStreamLineReader.readNextObjectLine()) {
0418         const int objectCode = m_XFigStreamLineReader.objectCode();
0419         const QString objectComment = m_XFigStreamLineReader.comment();
0420 
0421         if (objectCode == XFig3_2ColorObjectId) {
0422             parseColorObject();
0423         } else if ((XFig3_2EllipseObjectId<=objectCode) && (objectCode<=XFig3_2CompoundObjectId)) {
0424             XFigAbstractObject* object =
0425                 (objectCode == XFig3_2EllipseObjectId) ?  parseEllipse() :
0426                 (objectCode == XFig3_2PolylineObjectId) ? parsePolyline() :
0427                 (objectCode == XFig3_2SplineObjectId) ?   parseSpline() :
0428                 (objectCode == XFig3_2TextObjectId) ?     parseText() :
0429                 (objectCode == XFig3_2ArcObjectId) ?      parseArc() :
0430                 /*else XFig3_2CompoundObjectId)*/         parseCompoundObject();
0431             if (object != 0) {
0432                 object->setComment(objectComment);
0433                 page->addObject(object);
0434             }
0435         } else {
0436             // should not occur
0437             qWarning() << "unknown object type:" << objectCode;
0438         }
0439     }
0440 
0441     m_Document->addPage( page );
0442 }
0443 
0444 XFigParser::~XFigParser()
0445 {
0446     delete m_TextDecoder;
0447     delete m_Document;
0448 }
0449 
0450 bool
0451 XFigParser::parseHeader()
0452 {
0453     // start to parse
0454     m_XFigStreamLineReader.readNextLine(XFigStreamLineReader::TakeComment);
0455     const QString versionString = m_XFigStreamLineReader.line();
0456     if (! versionString.startsWith(QLatin1String("#FIG 3.")) ||
0457         (versionString.length() < 8)) {
0458         qWarning() << "ERROR: no xfig file or wrong header";
0459         return false;
0460     }
0461 
0462     const QChar minorVersion = versionString.at(7);
0463     if (minorVersion == QLatin1Char('2')) {
0464         m_XFigVersion = 320;
0465     } else if (minorVersion == QLatin1Char('1')) {
0466         m_XFigVersion = 310;
0467     } else {
0468         qWarning() << "ERROR: unsupported xfig version";
0469         return false;
0470     }
0471 
0472     m_Document = new XFigDocument;
0473 
0474     // assume header is broken by default
0475     bool isHeaderCorrect = false;
0476     do {
0477         // orientation
0478         if (m_XFigStreamLineReader.readNextLine()) {
0479             const QString orientationString = m_XFigStreamLineReader.line().trimmed();
0480             const XFigPageOrientation pageOrientation =
0481                 (orientationString == QLatin1String("Landscape")) ? XFigPageLandscape :
0482                 (orientationString == QLatin1String("Portrait")) ?  XFigPagePortrait :
0483                                                                     XFigPageOrientationUnknown;
0484 // qDebug()<<"orientation:"<<orientationString<<pageOrientation;
0485             if (pageOrientation == XFigPageOrientationUnknown)
0486                 qWarning() << "ERROR: invalid orientation";
0487 
0488             m_Document->setPageOrientation( pageOrientation );
0489         } else {
0490             break;
0491         }
0492 
0493         // justification, ("Center" or "Flush Left")
0494         if (! m_XFigStreamLineReader.readNextLine()) {
0495             break;
0496         }
0497 
0498         // units
0499         if (m_XFigStreamLineReader.readNextLine()) {
0500             const QString unitTypeString = m_XFigStreamLineReader.line().trimmed();
0501             const XFigUnitType unitType =
0502                 (unitTypeString == QLatin1String("Metric")) ? XFigUnitMetric :
0503                 (unitTypeString == QLatin1String("Inches")) ? XFigUnitInches :
0504                                                             XFigUnitTypeUnknown;
0505 //     qDebug() << "unittype:"<<unitTypeString<<unitType;
0506             if (unitType == XFigUnitTypeUnknown)
0507                 qWarning() << "ERROR: invalid units";
0508 
0509             m_Document->setUnitType( unitType );
0510         } else {
0511             break;
0512         }
0513 
0514         if (m_XFigVersion == 320) {
0515             if (m_XFigStreamLineReader.readNextLine()) {
0516                 const QString pageSizeString = m_XFigStreamLineReader.line().trimmed();
0517                 const XFigPageSizeType pageSizeType = ::pageSizeType(pageSizeString);
0518 // qDebug() << "pagesize:"<<pageSizeString<<pageSizeType;
0519                 m_Document->setPageSizeType(pageSizeType);
0520             } else {
0521                 break;
0522             }
0523 
0524             // export and print magnification, %
0525             if (m_XFigStreamLineReader.readNextLine()) {
0526                 const QString magnificationString = m_XFigStreamLineReader.line();
0527                 const float magnification = magnificationString.toFloat();
0528                 // TODO
0529                 Q_UNUSED(magnification);
0530 // qDebug() << "magnification:"<<magnificationString<<magnification;
0531             } else {
0532                 break;
0533             }
0534 
0535             // singe or multiple page
0536             if (m_XFigStreamLineReader.readNextLine()) {
0537                 const QString singleOrMultiplePagesString = m_XFigStreamLineReader.line().trimmed();
0538                 // multiple pages not yet supported
0539                 if (singleOrMultiplePagesString != QLatin1String("Single")) {
0540                     break;
0541                 }
0542             } else {
0543                 break;
0544             }
0545 
0546             // transparent color for GIF export: -3=background, -2=None, -1=Default, 0-31 for standard colors, 32- for user colors
0547             if (m_XFigStreamLineReader.readNextLine()) {
0548                 const QString transparentColorString = m_XFigStreamLineReader.line();
0549                 const int transparentColor = transparentColorString.toInt();
0550                 // TODO
0551                 Q_UNUSED(transparentColor);
0552 // qDebug() << "transparentColor:"<<transparentColorString<<transparentColor;
0553             } else {
0554                 break;
0555             }
0556         }
0557 
0558         // resolution and coordinate system
0559         if (m_XFigStreamLineReader.readNextLine(XFigStreamLineReader::CollectComments)) {
0560             qint32 coordinateSystemType;
0561             qint32 resolution;
0562             QString line = m_XFigStreamLineReader.line();
0563             QTextStream textStream(&line, QIODevice::ReadOnly);
0564             textStream >> resolution >> coordinateSystemType;
0565 
0566             const XFigCoordSystemOriginType coordSystemOriginType =
0567                 (coordinateSystemType == 1) ? XFigCoordSystemOriginLowerLeft :
0568                 (coordinateSystemType == 2) ? XFigCoordSystemOriginUpperLeft :
0569                                             XFigCoordSystemOriginTypeUnknown;
0570             m_Document->setCoordSystemOriginType( coordSystemOriginType ); // said to be ignored and always upper-left
0571             m_Document->setResolution(resolution);
0572             m_Document->setComment(m_XFigStreamLineReader.comment());
0573 
0574 //     qDebug() << "resolution+coordinateSystemType:"<<resolution<<coordinateSystemType;
0575         } else {
0576             break;
0577         }
0578         isHeaderCorrect = true;
0579     } while (false);
0580 
0581     if (! isHeaderCorrect) {
0582         delete m_Document;
0583         m_Document = 0;
0584     }
0585 
0586     return isHeaderCorrect;
0587 }
0588 
0589 
0590 static inline
0591 int
0592 parseTwoDigitHexValue(QTextStream& textStream)
0593 {
0594     int result = 0;
0595 
0596     char digit[2];
0597     textStream >> digit[1] >> digit[0];
0598 
0599     int faktor = 1;
0600     for (int i = 0; i < 2; i++) {
0601         const int value =
0602             ('0' <= digit[i]  && digit[i] <= '9') ? digit[i] - '0' :
0603             ('A' <= digit[i]  && digit[i] <= 'F') ? digit[i] - 'A' + 10 :
0604             ('a' <= digit[i]  && digit[i] <= 'f') ? digit[i] - 'a' + 10 :
0605             /* bogus data */                        0;
0606         result += value * faktor;
0607         faktor = 16;
0608     }
0609 
0610     return result;
0611 };
0612 
0613 void XFigParser::parseColorObject()
0614 {
0615     int colorNumber;
0616 
0617     QString line = m_XFigStreamLineReader.line();
0618     QTextStream textStream(&line, QIODevice::ReadOnly);
0619     textStream >> colorNumber;
0620     if ((colorNumber < 32) || (543 < colorNumber)) {
0621         qWarning() << "bad colorNumber:" << colorNumber;
0622         return;
0623     }
0624 
0625     QChar hashChar;
0626     textStream >> ws >> hashChar;
0627     const int red = parseTwoDigitHexValue(textStream);
0628     const int green = parseTwoDigitHexValue(textStream);
0629     const int blue = parseTwoDigitHexValue(textStream);
0630 
0631     m_Document->setUserColor(colorNumber, QColor(red, green, blue));
0632 }
0633 
0634 XFigAbstractObject*
0635 XFigParser::parseArc()
0636 {
0637 // qDebug()<<"arc";
0638 
0639     QScopedPointer<XFigArcObject> arcObject(new XFigArcObject);
0640 
0641     int sub_type, line_style, thickness, pen_color, fill_color,
0642     depth, pen_style, area_fill, cap_style, direction,
0643     forwardArrow, backwardArrow, x1, y1, x2, y2, x3, y3;
0644     float center_x, center_y;
0645     float style_val;
0646 
0647     // first line
0648     QString line = m_XFigStreamLineReader.line();
0649     QTextStream textStream(&line, QIODevice::ReadOnly);
0650     textStream
0651         >> sub_type >> line_style >> thickness >> pen_color >> fill_color
0652         >> depth >> pen_style >> area_fill >> style_val >> cap_style
0653         >> direction >> forwardArrow >> backwardArrow
0654         >> center_x >> center_y >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
0655 
0656     if (forwardArrow > 0) {
0657         QScopedPointer<XFigArrowHead> arrowHead(parseArrowHead());
0658         if (arrowHead.isNull()) {
0659             return 0;
0660         }
0661         arcObject->setForwardArrow(arrowHead.take());
0662     }
0663 
0664     if (backwardArrow > 0) {
0665         QScopedPointer<XFigArrowHead> arrowHead(parseArrowHead());
0666         if (arrowHead.isNull()) {
0667             return 0;
0668         }
0669         arcObject->setBackwardArrow(arrowHead.take());
0670     }
0671 
0672     const XFigArcObject::Subtype subtype =
0673         (sub_type==1) ?   XFigArcObject::OpenEnded :
0674         /*(sub_type==2)*/ XFigArcObject::PieWedgeClosed;
0675     arcObject->setSubtype(subtype);
0676     const XFigArcObject::Direction arcDirection =
0677         (direction==1) ?   XFigArcObject::CounterClockwise :
0678         /*(direction==0)*/ XFigArcObject::Clockwise;
0679     arcObject->setDirection(arcDirection);
0680     arcObject->setCenterPoint(XFigPoint(center_x, center_y));
0681     arcObject->setPoints(XFigPoint(x1, y1), XFigPoint(x2, y2), XFigPoint(x3, y3));
0682     arcObject->setCapType(capType(cap_style));
0683     arcObject->setDepth( depth );
0684     const XFigFillType fillType = ::fillType(area_fill);
0685     if (fillType == XFigFillSolid) {
0686         arcObject->setFillTinting(area_fill);
0687     } else if (fillType == XFigFillPattern) {
0688         arcObject->setFillPatternType(::fillPatternType(area_fill));
0689     } else {
0690         arcObject->setFillNone();
0691     }
0692     arcObject->setFillColorId(fill_color);
0693     arcObject->setLine( lineType(line_style), thickness, style_val, pen_color );
0694 
0695     return arcObject.take();
0696 }
0697 
0698 XFigAbstractObject*
0699 XFigParser::parseEllipse()
0700 {
0701 // qDebug()<<"ellipse";
0702 
0703     QScopedPointer<XFigEllipseObject> ellipseObject(new XFigEllipseObject);
0704 
0705     qint32 sub_type, line_style, thickness, pen_color, fill_color,
0706            depth, pen_style/*not used*/, area_fill, direction/*always 1*/,
0707            center_x, center_y, radius_x, radius_y, start_x, start_y, end_x, end_y;
0708     float style_val, angle;
0709 
0710     // ellipse data line
0711     QString line = m_XFigStreamLineReader.line();
0712     QTextStream textStream(&line, QIODevice::ReadOnly);
0713     textStream
0714         >> sub_type >> line_style >> thickness >> pen_color >> fill_color
0715         >> depth >> pen_style >> area_fill >> style_val >> direction
0716         >> angle >> center_x >> center_y >> radius_x >> radius_y
0717         >> start_x >> start_y >> end_x >> end_y;
0718 
0719     const XFigEllipseObject::Subtype subtype =
0720         (sub_type==1) ?   XFigEllipseObject::EllipseByRadii :
0721         (sub_type==2) ?   XFigEllipseObject::EllipseByDiameter :
0722         (sub_type==3) ?   XFigEllipseObject::CircleByRadius :
0723         /*(sub_type==4)*/ XFigEllipseObject::CircleByDiameter;
0724     ellipseObject->setSubtype(subtype);
0725     ellipseObject->setCenterPoint(XFigPoint(center_x, center_y));
0726     ellipseObject->setStartEnd(XFigPoint(start_x,start_y), XFigPoint(end_x,end_y));
0727     ellipseObject->setRadii(radius_x, radius_y);
0728     ellipseObject->setXAxisAngle(angle);
0729 
0730     ellipseObject->setDepth( depth );
0731     const XFigFillType fillType = ::fillType(area_fill);
0732     if (fillType == XFigFillSolid) {
0733         ellipseObject->setFillTinting(area_fill);
0734     } else if (fillType == XFigFillPattern) {
0735         ellipseObject->setFillPatternType(::fillPatternType(area_fill));
0736     } else {
0737         ellipseObject->setFillNone();
0738     }
0739     ellipseObject->setFillColorId(fill_color);
0740     ellipseObject->setLine( lineType(line_style), thickness, style_val, pen_color );
0741 
0742     return ellipseObject.take();
0743 }
0744 
0745 XFigAbstractObject*
0746 XFigParser::parsePolyline()
0747 {
0748 // qDebug()<<"polyline";
0749 
0750     QScopedPointer<XFigAbstractPolylineObject> abstractPolylineObject(0);
0751 
0752     qint32 sub_type, line_style, thickness, pen_color, fill_color,
0753            depth, pen_style, area_fill, join_style, cap_style, radius,
0754            forward_arrow, backward_arrow, npoints;
0755     float style_val;
0756 
0757     // polyline data line
0758     QString line = m_XFigStreamLineReader.line();
0759     QTextStream textStream(&line, QIODevice::ReadOnly);
0760     textStream
0761         >> sub_type >> line_style >> thickness >> pen_color >> fill_color
0762         >> depth >> pen_style >> area_fill >> style_val >> join_style
0763         >> cap_style >> radius >> forward_arrow >> backward_arrow
0764         >> npoints;
0765 // qDebug() << sub_type << line_style << thickness << pen_color << fill_color << depth << pen_style
0766 //          << area_fill << style_val << join_style << cap_style << radius << forward_arrow << backward_arrow << npoints;
0767 
0768     // ignore line with useless point number
0769     if (npoints < 1) {
0770         return 0;
0771     }
0772 
0773     if (sub_type==XFig3_2PolylinePolylineId) {
0774         XFigPolylineObject* polylineObject = new XFigPolylineObject;
0775         polylineObject->setCapType(capType(cap_style));
0776         abstractPolylineObject.reset(polylineObject);
0777     } else if (sub_type==XFig3_2PolylinePolygonId) {
0778         abstractPolylineObject.reset(new XFigPolygonObject);
0779     } else if (sub_type==XFig3_2PolylineBoxId) {
0780         abstractPolylineObject.reset(new XFigBoxObject);
0781     } else if (sub_type==XFig3_2PolylineArcBoxId) {
0782         XFigBoxObject* boxObject = new XFigBoxObject;
0783         boxObject->setRadius(radius);
0784         abstractPolylineObject.reset(boxObject);
0785     } else if (sub_type==XFig3_2PolylinePictureBoundingBoxId) {
0786         XFigPictureBoxObject* pictureBoxObject = new XFigPictureBoxObject;
0787         if (! m_XFigStreamLineReader.readNextLine()) {
0788             return 0;
0789         }
0790 
0791         QString line = m_XFigStreamLineReader.line();
0792         QTextStream textStream(&line, QIODevice::ReadOnly);
0793 
0794         int flipped;
0795         QString fileName;
0796         textStream >> flipped >> fileName;
0797 
0798         pictureBoxObject->setIsFlipped( flipped != 0 );
0799         pictureBoxObject->setFileName( fileName );
0800 
0801         abstractPolylineObject.reset(pictureBoxObject);
0802     } else {
0803     }
0804 
0805     if (forward_arrow > 0) {
0806         QScopedPointer<XFigArrowHead> arrowHead(parseArrowHead());
0807         if (arrowHead.isNull()) {
0808             return 0;
0809         }
0810 
0811         if (abstractPolylineObject->typeId() == XFigAbstractObject::PolylineId) {
0812             XFigPolylineObject* polylineObject =
0813                 static_cast<XFigPolylineObject*>(abstractPolylineObject.data());
0814             polylineObject->setForwardArrow(arrowHead.take());
0815         }
0816     }
0817 
0818     if (backward_arrow > 0) {
0819         QScopedPointer<XFigArrowHead> arrowHead(parseArrowHead());
0820         if (arrowHead.isNull()) {
0821             return 0;
0822         }
0823 
0824         if (abstractPolylineObject->typeId() == XFigAbstractObject::PolylineId) {
0825             XFigPolylineObject* polylineObject =
0826                 static_cast<XFigPolylineObject*>(abstractPolylineObject.data());
0827             polylineObject->setBackwardArrow(arrowHead.take());
0828         }
0829     }
0830 
0831     // points line
0832     const QVector<XFigPoint> points = parsePoints(npoints);
0833     if (points.count() != npoints) {
0834         return 0;
0835     }
0836 
0837     // check box:
0838     if ((abstractPolylineObject->typeId()==XFigAbstractObject::BoxId) &&
0839         (points.count()!=5)) {
0840         qWarning() << "box object does not have 5 points, but points:" << points.count();
0841         return 0;
0842     }
0843     abstractPolylineObject->setPoints(points);
0844     abstractPolylineObject->setDepth(depth);
0845     const XFigFillType fillType = ::fillType(area_fill);
0846     if (fillType == XFigFillSolid) {
0847         abstractPolylineObject->setFillTinting(area_fill);
0848     } else if (fillType == XFigFillPattern) {
0849         abstractPolylineObject->setFillPatternType(::fillPatternType(area_fill));
0850     } else {
0851         abstractPolylineObject->setFillNone();
0852     }
0853     abstractPolylineObject->setFillColorId(fill_color);
0854     abstractPolylineObject->setLine(lineType(line_style), thickness, style_val, pen_color);
0855     abstractPolylineObject->setJoinType(joinType(join_style));
0856 
0857     return abstractPolylineObject.take();
0858 }
0859 
0860 XFigAbstractObject*
0861 XFigParser::parseSpline()
0862 {
0863 // qDebug()<<"spline";
0864 
0865     qint32 sub_type, line_style, thickness, pen_color, fill_color, depth,
0866            pen_style, area_fill, cap_style, forward_arrow, backward_arrow, npoints;
0867     float style_val;
0868 
0869     // this should be a spline
0870     QString line = m_XFigStreamLineReader.line();
0871     QTextStream textStream(&line, QIODevice::ReadOnly);
0872     textStream
0873         >> sub_type >> line_style >> thickness >> pen_color >> fill_color
0874         >>  depth >> pen_style >> area_fill >> style_val >> cap_style
0875         >> forward_arrow >> backward_arrow >> npoints;
0876 // qDebug() << sub_type << line_style << thickness << pen_color << fill_color << depth << pen_style
0877 //          << area_fill << style_val << cap_style << forward_arrow << backward_arrow << npoints;
0878 
0879     // ignore line with useless point number
0880     if (npoints < 1) {
0881         return 0;
0882     }
0883 
0884     // TODO: no idea yet how to translate the xfig splines to odf ones
0885     // thus simply creating polygones/polylines for now :/
0886     QScopedPointer<XFigAbstractPolylineObject> abstractPolylineObject(0);
0887 
0888     if ((sub_type==XFig3_2SplineOpenApproximatedId) ||
0889         (sub_type==XFig3_2SplineOpenInterpolatedId) ||
0890         (sub_type==XFig3_2SplineOpenXId)) {
0891         XFigPolylineObject* polylineObject = new XFigPolylineObject;
0892         polylineObject->setCapType(capType(cap_style));
0893         abstractPolylineObject.reset(polylineObject);
0894     } else {
0895         abstractPolylineObject.reset(new XFigPolygonObject);
0896     }
0897 
0898     if (forward_arrow > 0) {
0899         QScopedPointer<XFigArrowHead> arrowHead(parseArrowHead());
0900         if (arrowHead.isNull()) {
0901             return 0;
0902         }
0903 
0904         if (abstractPolylineObject->typeId() == XFigAbstractObject::PolylineId) {
0905             XFigPolylineObject* polylineObject =
0906                 static_cast<XFigPolylineObject*>(abstractPolylineObject.data());
0907             polylineObject->setForwardArrow(arrowHead.take());
0908         }
0909     }
0910 
0911     if (backward_arrow > 0) {
0912         QScopedPointer<XFigArrowHead> arrowHead(parseArrowHead());
0913         if (arrowHead.isNull()) {
0914             return 0;
0915         }
0916 
0917         if (abstractPolylineObject->typeId() == XFigAbstractObject::PolylineId) {
0918             XFigPolylineObject* polylineObject =
0919                 static_cast<XFigPolylineObject*>(abstractPolylineObject.data());
0920             polylineObject->setBackwardArrow(arrowHead.take());
0921         }
0922     }
0923 
0924     // points line
0925     const QVector<XFigPoint> points = parsePoints(npoints);
0926     if (points.count() != npoints) {
0927         return 0;
0928     }
0929 
0930     // control points line
0931     parseFactors(npoints);
0932 
0933     abstractPolylineObject->setPoints(points);
0934     abstractPolylineObject->setDepth(depth);
0935     const XFigFillType fillType = ::fillType(area_fill);
0936     if (fillType == XFigFillSolid) {
0937         abstractPolylineObject->setFillTinting(area_fill);
0938     } else if (fillType == XFigFillPattern) {
0939         abstractPolylineObject->setFillPatternType(::fillPatternType(area_fill));
0940     } else {
0941         abstractPolylineObject->setFillNone();
0942     }
0943     abstractPolylineObject->setFillColorId(fill_color);
0944     abstractPolylineObject->setLine(lineType(line_style), thickness, style_val, pen_color);
0945     abstractPolylineObject->setJoinType(XFigJoinRound);
0946 
0947     return abstractPolylineObject.take();
0948 }
0949 
0950 XFigAbstractObject*
0951 XFigParser::parseText()
0952 {
0953 // qDebug()<<"text";
0954 
0955     QScopedPointer<XFigTextObject> textObject(new XFigTextObject);
0956 
0957     qint32 sub_type, color, depth, pen_style, font, font_flags, x, y;
0958     float font_size, angle, height, length;
0959 
0960     QString line = m_XFigStreamLineReader.line();
0961     QTextStream textStream(&line, QIODevice::ReadOnly);
0962     textStream
0963         >> sub_type >> color >> depth >> pen_style >> font >> font_size
0964         >> angle >> font_flags >> height >> length >> x >> y;
0965 
0966     const XFigTextAlignment textAlignment =
0967         (sub_type == XFig3_2TextCenterAligned) ? XFigTextCenterAligned :
0968         (sub_type == XFig3_2TextRightAligned) ?  XFigTextRightAligned :
0969         /*(sub_type == XFig3_2TextLeftAligned)*/ XFigTextLeftAligned;
0970     textObject->setTextAlignment(textAlignment);
0971     textObject->setBaselineStartPoint(XFigPoint(x,y));
0972     textObject->setSize(length, height);
0973     textObject->setXAxisAngle(angle);
0974     textObject->setColorId(color);
0975     textObject->setDepth(depth);
0976     textObject->setIsHidden(font_flags&XFig3_2TextHidden);
0977 
0978     XFigFontData fontData;
0979     if (font_flags&XFig3_2TextPostScriptFont) {
0980         if (font == -1) {
0981             /* default means */;
0982         } else {
0983             if ((0<=font) && (font<=34)) {
0984                 const XFig3_2PostScriptFontData& postScriptFontData = postScriptFontDataTable[font];
0985                 fontData.mFamily = QLatin1String(postScriptFontData.family);
0986                 fontData.mWeight = postScriptFontData.weight;
0987                 fontData.mStyle = postScriptFontData.style;
0988             }
0989         }
0990     } else {
0991         // LaTeX font
0992         if (font == XFig3_2LatexFontSansSerif) {
0993             fontData.mFamily = QLatin1String("helvetica");
0994         } else if (font == XFig3_2LatexFontTypewriter) {
0995             fontData.mFamily = QLatin1String("courier");
0996         } else if ((XFig3_2LatexFontDefault<=font) && (font<=XFig3_2LatexFontItalic)) {
0997             fontData.mFamily = QLatin1String("times");
0998             if (font==XFig3_2LatexFontBold) {
0999                 fontData.mWeight = QFont::Bold;
1000             } else if (font==XFig3_2LatexFontItalic) {
1001                 fontData.mStyle = QFont::StyleItalic;
1002             }
1003         }
1004     }
1005     fontData.mSize = font_size;
1006     textObject->setFontData(fontData);
1007 
1008     // read text
1009     // skip one space char used as separator
1010     const QString textData = line.mid(textStream.pos()+1);
1011 
1012     // TODO: improve this, not really sane yet
1013     QString text;
1014     for (int i = 0; i < textData.length(); ++i) {
1015         const QChar textChar = textData.at(i);
1016         if (textChar == QLatin1Char('\\')) {
1017 
1018             if ((i+3) >= textData.length()) {
1019                 // encoded char, especially end marker not possible, is broken
1020                 break;
1021             }
1022             // read digits and check this is really about an octal encoded char
1023             int digitValues[3];
1024             bool isOctalEncodedChar = true;
1025             for (int d = 0; d < 3; ++d) {
1026                 const int digitValue = textData.at(i+1+d).digitValue();
1027                 if ((digitValue < 0) || (7 < digitValue)) {
1028                     isOctalEncodedChar = false;
1029                     break;
1030                 }
1031                 digitValues[d] = digitValue;
1032             }
1033             if (isOctalEncodedChar) {
1034                 unsigned char charValue =
1035                     digitValues[0] * 64 +
1036                     digitValues[1] * 8 +
1037                     digitValues[2];
1038                 // \001 is used as end marker
1039                 if (charValue == 1) {
1040                     break;
1041                 }
1042                 const char encodedChar = static_cast<char>(charValue);
1043                 text.append( m_TextDecoder->toUnicode(&encodedChar,1) );
1044 
1045                 // digits are consumed
1046                 i += 3;
1047             } else if (textData.at(i+1) == QLatin1Char('\\')) {
1048                 text.append( textChar );
1049                 // double \ is consumed
1050                 ++i;
1051             }
1052         } else {
1053             text.append( textChar );
1054         }
1055     }
1056     textObject->setText(text);
1057 
1058     return textObject.take();
1059 }
1060 
1061 XFigAbstractObject*
1062 XFigParser::parseCompoundObject()
1063 {
1064 // qDebug()<<"compound";
1065 
1066     QScopedPointer<XFigCompoundObject> compoundObject(new XFigCompoundObject);
1067 
1068     {
1069         qint32 upperLeftX, upperLeftY, lowerRightX, lowerRightY;
1070 
1071         QString line = m_XFigStreamLineReader.line();
1072         QTextStream textStream(&line, QIODevice::ReadOnly);
1073         textStream >> upperLeftX >> upperLeftY >> lowerRightX >> lowerRightY;
1074 
1075         const XFigBoundingBox boundingBox( XFigPoint(upperLeftX, upperLeftY),
1076                                     XFigPoint(lowerRightX, lowerRightY) );
1077         compoundObject->setBoundingBox( boundingBox );
1078     }
1079 
1080     while (! m_XFigStreamLineReader.readNextObjectLine()) {
1081         const int objectCode = m_XFigStreamLineReader.objectCode();
1082         const QString objectComment = m_XFigStreamLineReader.comment();
1083 
1084         // end reached?
1085         if (objectCode == XFig3_2CompoundObjectEndId) {
1086             break;
1087         }
1088 
1089         if (objectCode == XFig3_2ColorObjectId) {
1090             parseColorObject();
1091         } else if ((XFig3_2EllipseObjectId<=objectCode) && (objectCode<=XFig3_2CompoundObjectId)) {
1092             XFigAbstractObject* object =
1093                 (objectCode == XFig3_2EllipseObjectId) ?  parseEllipse() :
1094                 (objectCode == XFig3_2PolylineObjectId) ? parsePolyline() :
1095                 (objectCode == XFig3_2SplineObjectId) ?   parseSpline() :
1096                 (objectCode == XFig3_2TextObjectId) ?     parseText() :
1097                 (objectCode == XFig3_2ArcObjectId) ?      parseArc() :
1098                 /*else XFig3_2CompoundObjectId)*/         parseCompoundObject();
1099             if (object != 0) {
1100                 object->setComment(objectComment);
1101                 compoundObject->addObject(object);
1102             }
1103         } else {
1104             // should not occur
1105             qWarning() << "unknown object type:" << objectCode;
1106         }
1107     }
1108 // qDebug()<<"compound end";
1109 
1110     return compoundObject.take();
1111 }
1112 
1113 XFigArrowHead* XFigParser::parseArrowHead()
1114 {
1115     if (! m_XFigStreamLineReader.readNextLine()) {
1116         return 0;
1117     }
1118 
1119     QString line = m_XFigStreamLineReader.line();
1120     QTextStream textStream(&line, QIODevice::ReadOnly);
1121 
1122     int arrow_type, arrow_style;
1123     float arrow_thickness, arrow_width, arrow_height;
1124     textStream
1125         >> arrow_type >> arrow_style >> arrow_thickness
1126         >> arrow_width >> arrow_height;
1127 
1128     XFigArrowHead* arrowHead = new XFigArrowHead;
1129     arrowHead->setType(arrowHeadType(arrow_type, arrow_style));
1130     arrowHead->setThickness(arrow_thickness );
1131     arrowHead->setSize(arrow_width, arrow_height);
1132 
1133     return arrowHead;
1134 }
1135 
1136 QVector<XFigPoint> XFigParser::parsePoints(int pointCount)
1137 {
1138     QVector<XFigPoint> result;
1139 
1140     QString pointsText;
1141     QTextStream pointsTextStream(&pointsText, QIODevice::ReadOnly);
1142     for (int i = 0; i < pointCount; i++) {
1143         if (pointsTextStream.atEnd()) {
1144             if (! m_XFigStreamLineReader.readNextLine()) {
1145                 return QVector<XFigPoint>();
1146             }
1147 
1148             pointsText = m_XFigStreamLineReader.line();
1149             pointsTextStream.setString(&pointsText, QIODevice::ReadOnly);
1150         }
1151 
1152         qint32 x;
1153         qint32 y;
1154         pointsTextStream >> x >> y;
1155 // qDebug() << "point:" << i << x << y;
1156 
1157         result.append(XFigPoint(x, y));
1158 
1159         pointsTextStream.skipWhiteSpace();
1160     }
1161 
1162     return result;
1163 }
1164 
1165 QVector<double> XFigParser::parseFactors(int pointCount)
1166 {
1167     QVector<double> result;
1168 
1169     QString factorsText;
1170     QTextStream factorsTextStream(&factorsText, QIODevice::ReadOnly);
1171     for (int i = 0; i < pointCount; i++) {
1172         if (factorsTextStream.atEnd()) {
1173             if (! m_XFigStreamLineReader.readNextLine()) {
1174                 return QVector<double>();
1175             }
1176 
1177             factorsText = m_XFigStreamLineReader.line();
1178             factorsTextStream.setString(&factorsText, QIODevice::ReadOnly);
1179         }
1180 
1181         double factor;
1182         factorsTextStream >> factor;
1183 // qDebug() << "factor:" << i << factor;
1184 
1185         result.append(factor);
1186 
1187         factorsTextStream.skipWhiteSpace();
1188     }
1189 
1190     return result;
1191 }