bool SvmParser::parse(const QByteArray &data) { // Check the signature "VCLMTF" if (!data.startsWith("VCLMTF")) return false; QBuffer buffer((QByteArray *) &data); buffer.open(QIODevice::ReadOnly); QDataStream mainStream(&buffer); mainStream.setByteOrder(QDataStream::LittleEndian); // Start reading from the stream: read past the signature and get the header. soakBytes(mainStream, 6); SvmHeader header(mainStream); #if DEBUG_SVMPARSER debugVectorImage << "================ SVM HEADER ================"; debugVectorImage << "version, length:" << header.versionCompat.version << header.versionCompat.length; debugVectorImage << "compressionMode:" << header.compressionMode; debugVectorImage << "mapMode:" << "Origin" << header.mapMode.origin << "scaleX" << header.mapMode.scaleX.numerator << header.mapMode.scaleX.denominator << (qreal(header.mapMode.scaleX.numerator) / header.mapMode.scaleX.denominator) << "scaleY" << header.mapMode.scaleY.numerator << header.mapMode.scaleY.denominator << (qreal(header.mapMode.scaleY.numerator) / header.mapMode.scaleY.denominator); debugVectorImage << "size:" << header.width << header.height; debugVectorImage << "actionCount:" << header.actionCount; debugVectorImage << "================ SVM HEADER ================"; #endif mBackend->init(header); #if DEBUG_SVMPARSER { QPolygon polygon; polygon << QPoint(0, 0); polygon << QPoint(header.width, header.height); mBackend->polyLine(mContext, polygon); } #endif // Parse all actions and call the appropriate backend callback for // the graphics drawing actions. The context actions will // manipulate the graphics context, which is maintained here. for (uint action = 0; action < header.actionCount; ++action) { quint16 actionType; quint16 version; quint32 totalSize; // Here starts the Action itself. The first two bytes is the action type. mainStream >> actionType; // The VersionCompat object mainStream >> version; mainStream >> totalSize; char *rawData = new char[totalSize]; mainStream.readRawData(rawData, totalSize); QByteArray dataArray(rawData, totalSize); QDataStream stream(&dataArray, QIODevice::ReadOnly); stream.setByteOrder(QDataStream::LittleEndian); // Debug #if DEBUG_SVMPARSER { QString name; if (actionType == 0) name = actionNames[0].actionName; else if (100 <= actionType && actionType <= META_LAST_ACTION) name = actionNames[actionType - 99].actionName; else if (actionType == 512) name = "META_COMMENT_ACTION"; else name = "(out of bounds)"; debugVectorImage << name << "(" << actionType << ")" << "version" << version << "totalSize" << totalSize; } #endif // Parse all actions. switch (actionType) { case META_NULL_ACTION: break; case META_PIXEL_ACTION: break; case META_POINT_ACTION: break; case META_LINE_ACTION: break; case META_RECT_ACTION: { QRect rect; parseRect(stream, rect); debugVectorImage << "Rect:" << rect; mBackend->rect(mContext, rect); } break; case META_ROUNDRECT_ACTION: break; case META_ELLIPSE_ACTION: break; case META_ARC_ACTION: break; case META_PIE_ACTION: break; case META_CHORD_ACTION: break; case META_POLYLINE_ACTION: { QPolygon polygon; parsePolygon(stream, polygon); debugVectorImage << "Polyline:" << polygon; mBackend->polyLine(mContext, polygon); // FIXME: Version 2: Lineinfo, Version 3: polyflags if (version > 1) soakBytes(stream, totalSize - 2 - 4 * 2 * polygon.size()); } break; case META_POLYGON_ACTION: { QPolygon polygon; parsePolygon(stream, polygon); debugVectorImage << "Polygon:" << polygon; mBackend->polygon(mContext, polygon); // FIXME: Version 2: Lineinfo, Version 3: polyflags if (version > 1) soakBytes(stream, totalSize - 2 - 4 * 2 * polygon.size()); } break; case META_POLYPOLYGON_ACTION: { quint16 polygonCount; stream >> polygonCount; //debugVectorImage << "Number of polygons:" << polygonCount; QList<QPolygon> polygons; for (quint16 i = 0 ; i < polygonCount ; i++) { QPolygon polygon; parsePolygon(stream, polygon); polygons << polygon; //debugVectorImage << "Polygon:" << polygon; } if (version > 1) { quint16 complexPolygonCount; stream >> complexPolygonCount; //debugVectorImage << "Number of complex polygons:" << complexPolygonCount; // Parse the so called "complex polygons". For // each one, there is an index and a polygon. The // index tells which of the original polygons to // replace. for (quint16 i = 0; i < complexPolygonCount; i++) { quint16 complexPolygonIndex; stream >> complexPolygonIndex; QPolygon polygon; parsePolygon(stream, polygon); //debugVectorImage << "polygon index:" << complexPolygonIndex << polygon; // FIXME: The so called complex polygons have something to do // with modifying the polygons, but I have not yet been // able to understand how. So until I do, we'll disable // this. //polygons[complexPolygonIndex] = polygon; } } mBackend->polyPolygon(mContext, polygons); } break; case META_TEXT_ACTION: break; case META_TEXTARRAY_ACTION: { QPoint startPoint; QString string; quint16 startIndex; quint16 len; quint32 dxArrayLen; qint32 *dxArray = 0; stream >> startPoint; parseString(stream, string); stream >> startIndex; stream >> len; stream >> dxArrayLen; if (dxArrayLen > 0) { quint32 maxDxArrayLen = totalSize - stream.device()->pos(); if (dxArrayLen > maxDxArrayLen) { debugVectorImage << "Defined dxArrayLen= " << dxArrayLen << "exceeds availalable size" << maxDxArrayLen; dxArrayLen = maxDxArrayLen; } dxArray = new qint32[dxArrayLen]; for (uint i = 0; i < dxArrayLen; ++i) stream >> dxArray[i]; } if (version > 1) { quint16 len2; stream >> len2; // FIXME: More here } #if 0 debugVectorImage << "Text: " << startPoint << string << startIndex << len; if (dxArrayLen > 0) { debugVectorImage << "dxArrayLen:" << dxArrayLen; for (uint i = 0; i < dxArrayLen; ++i) debugVectorImage << dxArray[i]; } else debugVectorImage << "dxArrayLen = 0"; #endif mBackend->textArray(mContext, startPoint, string, startIndex, len, dxArrayLen, dxArray); if (dxArrayLen) delete[] dxArray; }
bool Parser::readRecord( QDataStream &stream ) { if ( ! mOutput ) { qWarning() << "Output device not set"; return false; } quint32 type; quint32 size; stream >> type; stream >> size; { QString name; if (0 < type && type <= EMR_LASTRECORD) name = EmfRecords[type].name; else name = "(out of bounds)"; #if DEBUG_EMFPARSER kDebug(31000) << "Record length" << size << "type " << hex << type << "(" << dec << type << ")" << name; #endif } #if DEBUG_EMFPARSER == 2 soakBytes(stream, size - 8); #else switch ( type ) { case EMR_POLYLINE: { QRect bounds; stream >> bounds; quint32 count; stream >> count; QList<QPoint> aPoints; for (quint32 i = 0; i < count; ++i) { QPoint point; stream >> point; aPoints.append( point ); } mOutput->polyLine( bounds, aPoints ); } break; case EMR_SETWINDOWEXTEX: { QSize size; //stream >> size; qint32 width, height; stream >> width >> height; //kDebug(31000) << "SETWINDOWEXTEX" << width << height; size = QSize(width, height); mOutput->setWindowExtEx( size ); } break; case EMR_SETWINDOWORGEX: { QPoint origin; stream >> origin; mOutput->setWindowOrgEx( origin ); } break; case EMR_SETVIEWPORTEXTEX: { QSize size; stream >> size; mOutput->setViewportExtEx( size ); } break; case EMR_SETVIEWPORTORGEX: { QPoint origin; stream >> origin; mOutput->setViewportOrgEx( origin ); } break; case EMR_SETBRUSHORGEX: { QPoint origin; stream >> origin; #if DEBUG_EMFPARSER kDebug(33100) << "EMR_SETBRUSHORGEX" << origin; #endif } break; case EMR_EOF: { mOutput->eof(); soakBytes( stream, size-8 ); // because we already took 8. return false; } break; case EMR_SETPIXELV: { QPoint point; quint8 red, green, blue, reserved; stream >> point; stream >> red >> green >> blue >> reserved; mOutput->setPixelV( point, red, green, blue, reserved ); } break; case EMR_SETMAPMODE: { quint32 mapMode; stream >> mapMode; mOutput->setMapMode( mapMode ); } break; case EMR_SETBKMODE: { quint32 backgroundMode; stream >> backgroundMode; mOutput->setBkMode( backgroundMode ); } break; case EMR_SETPOLYFILLMODE: { quint32 PolygonFillMode; stream >> PolygonFillMode; mOutput->setPolyFillMode( PolygonFillMode ); } break; case EMR_SETROP2: { quint32 ROP2Mode; stream >> ROP2Mode; //kDebug(33100) << "EMR_SETROP2" << ROP2Mode; } break; case EMR_SETSTRETCHBLTMODE: { quint32 stretchMode; stream >> stretchMode; mOutput->setStretchBltMode( stretchMode ); } break; case EMR_SETTEXTALIGN: { quint32 textAlignMode; stream >> textAlignMode; mOutput->setTextAlign( textAlignMode ); } break; case EMR_SETTEXTCOLOR: { quint8 red, green, blue, reserved; stream >> red >> green >> blue >> reserved; mOutput->setTextColor( red, green, blue, reserved ); } break; case EMR_SETBKCOLOR: { quint8 red, green, blue, reserved; stream >> red >> green >> blue >> reserved; mOutput->setBkColor( red, green, blue, reserved ); } break; case EMR_MOVETOEX: { quint32 x, y; stream >> x >> y; mOutput->moveToEx( x, y ); //kDebug(33100) << "xx EMR_MOVETOEX" << x << y; } break; case EMR_SETMETARGN: { // Takes no arguments mOutput->setMetaRgn(); } break; case EMR_INTERSECTCLIPRECT: { QRect clip; stream >> clip; //kDebug(33100) << "EMR_INTERSECTCLIPRECT" << clip; } break; case EMR_SAVEDC: { mOutput->saveDC(); } break; case EMR_RESTOREDC: { qint32 savedDC; stream >> savedDC; mOutput->restoreDC( savedDC ); } break; case EMR_SETWORLDTRANSFORM: { stream.setFloatingPointPrecision(QDataStream::SinglePrecision); float M11, M12, M21, M22, Dx, Dy; stream >> M11; stream >> M12; stream >> M21; stream >> M22; stream >> Dx; stream >> Dy; //kDebug(31000) << "Set world transform" << M11 << M12 << M21 << M22 << Dx << Dy; mOutput->setWorldTransform( M11, M12, M21, M22, Dx, Dy ); } break; case EMR_MODIFYWORLDTRANSFORM: { stream.setFloatingPointPrecision(QDataStream::SinglePrecision); float M11, M12, M21, M22, Dx, Dy; stream >> M11; stream >> M12; stream >> M21; stream >> M22; stream >> Dx; stream >> Dy; //kDebug(31000) << "stream position after the matrix: " << stream.device()->pos(); quint32 ModifyWorldTransformMode; stream >> ModifyWorldTransformMode; mOutput->modifyWorldTransform( ModifyWorldTransformMode, M11, M12, M21, M22, Dx, Dy ); } break; case EMR_SELECTOBJECT: quint32 ihObject; stream >> ihObject; mOutput->selectObject( ihObject ); break; case EMR_CREATEPEN: { quint32 ihPen; stream >> ihPen; quint32 penStyle; stream >> penStyle; quint32 x, y; stream >> x; stream >> y; // unused quint8 red, green, blue, reserved; stream >> red >> green >> blue; stream >> reserved; // unused; mOutput->createPen( ihPen, penStyle, x, y, red, green, blue, reserved ); break; } case EMR_CREATEBRUSHINDIRECT: { quint32 ihBrush; stream >> ihBrush; quint32 BrushStyle; stream >> BrushStyle; quint8 red, green, blue, reserved; stream >> red >> green >> blue; stream >> reserved; // unused; quint32 BrushHatch; stream >> BrushHatch; mOutput->createBrushIndirect( ihBrush, BrushStyle, red, green, blue, reserved, BrushHatch ); break; } case EMR_DELETEOBJECT: { quint32 ihObject; stream >> ihObject; mOutput->deleteObject( ihObject ); } break; case EMR_ELLIPSE: { QRect box; stream >> box; mOutput->ellipse( box ); } break; case EMR_RECTANGLE: { QRect box; stream >> box; mOutput->rectangle( box ); //kDebug(33100) << "xx EMR_RECTANGLE" << box; } break; case EMR_ARC: { QRect box; QPoint start, end; stream >> box; stream >> start >> end; mOutput->arc( box, start, end ); } break; case EMR_CHORD: { QRect box; QPoint start, end; stream >> box; stream >> start >> end; mOutput->chord( box, start, end ); } break; case EMR_PIE: { QRect box; QPoint start, end; stream >> box; stream >> start >> end; mOutput->pie( box, start, end ); } break; case EMR_SELECTPALLETTE: { quint32 ihPal; stream >> ihPal; #if DEBUG_EMFPARSER kDebug(33100) << "EMR_SELECTPALLETTE" << ihPal; #endif } break; case EMR_SETMITERLIMIT: { stream.setFloatingPointPrecision(QDataStream::SinglePrecision); float miterLimit; stream >> miterLimit; #if DEBUG_EMFPARSER kDebug(33100) << "EMR_SETMITERLIMIT" << miterLimit; #endif } break; case EMR_BEGINPATH: mOutput->beginPath(); break; case EMR_ENDPATH: mOutput->endPath(); break; case EMR_CLOSEFIGURE: mOutput->closeFigure(); break; case EMR_FILLPATH: { QRect bounds; stream >> bounds; mOutput->fillPath( bounds ); //kDebug(33100) << "xx EMR_FILLPATH" << bounds; } break; case EMR_STROKEANDFILLPATH: { QRect bounds; stream >> bounds; mOutput->strokeAndFillPath( bounds ); //kDebug(33100) << "xx EMR_STROKEANDFILLPATHPATH" << bounds; } break; case EMR_STROKEPATH: { QRect bounds; stream >> bounds; mOutput->strokePath( bounds ); //kDebug(33100) << "xx EMR_STROKEPATH" << bounds; } break; case EMR_SETCLIPPATH: { quint32 regionMode; stream >> regionMode; mOutput->setClipPath( regionMode ); } break; case EMR_LINETO: { quint32 x, y; stream >> x >> y; QPoint finishPoint( x, y ); mOutput->lineTo( finishPoint ); //kDebug(33100) << "xx EMR_LINETO" << x << y; } break; case EMR_ARCTO: { QRect box; stream >> box; QPoint start; stream >> start; QPoint end; stream >> end; mOutput->arcTo( box, start, end ); } break; case EMR_COMMENT: { quint32 dataSize; stream >> dataSize; quint32 maybeIdentifier; stream >> maybeIdentifier; if ( maybeIdentifier == 0x2B464D45 ) { // EMFPLUS //kDebug(33100) << "EMR_COMMENT_EMFPLUS"; soakBytes( stream, size-16 ); // because we already took 16. } else if ( maybeIdentifier == 0x00000000 ) { //kDebug(33100) << "EMR_EMFSPOOL"; soakBytes( stream, size-16 ); // because we already took 16. } else if ( maybeIdentifier == 0x43494447 ) { quint32 commentType; stream >> commentType; //kDebug(33100) << "EMR_COMMENT_PUBLIC" << commentType; soakBytes( stream, size-20 ); // because we already took 20. } else { //kDebug(33100) << "EMR_COMMENT" << dataSize << maybeIdentifier; soakBytes( stream, size-16 ); // because we already took 16. } }