Example #1
0
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;
            }
Example #2
0
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.
            }
        }