/* Copyright (C) 2000, S.R.Haque . This file is part of the KDE project This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. DESCRIPTION */ #include #include #include #include #include #include #include #include #include const int Msod::s_area = 30505; Msod::Msod( unsigned dpi) : KWmf(dpi) { m_dpi = dpi; m_images.setAutoDelete(true); m_opt = new Options(*this); m_shape.data = 0L; m_shape.length = 0; } Msod::~Msod() { delete [] m_shape.data; delete m_opt; } void Msod::drawShape( unsigned shapeType, TQ_UINT32 bytes, TQDataStream &operands) { static const char *funcTab[] = { "UNKNOWN", // Unknown "RECTANGLE", // Rectangle "ROUNDRECTANGLE", // Roundrectangle "ELLIPSE", // Ellipse "DIAMOND", // Diamond "ISOCELESTRIANGLE", // Isocelestriangle "RIGHTTRIANGLE", // Righttriangle "PARALLELOGRAM", // Parallelogram "TRAPEZOID", // Trapezoid "HEXAGON", // Hexagon "OCTAGON", // Octagon "PLUS", // Plus "STAR", // Star "ARROW", // Arrow "THICKARROW", // Thickarrow "HOMEPLATE", // Homeplate "CUBE", // Cube "BALLOON", // Balloon "SEAL", // Seal "ARC", // Arc "LINE", // Line "PLAQUE", // Plaque "CAN", // Can "DONUT", // Donut "TEXTSIMPLE", // Textsimple "TEXTOCTAGON", // Textoctagon "TEXTHEXAGON", // Texthexagon "TEXTCURVE", // Textcurve "TEXTWAVE", // Textwave "TEXTRING", // Textring "TEXTONCURVE", // Textoncurve "TEXTONRING", // Textonring "STRAIGHTCONNECTOR1", // Straightconnector1 "BENTCONNECTOR2", // Bentconnector2 "BENTCONNECTOR3", // Bentconnector3 "BENTCONNECTOR4", // Bentconnector4 "BENTCONNECTOR5", // Bentconnector5 "CURVEDCONNECTOR2", // Curvedconnector2 "CURVEDCONNECTOR3", // Curvedconnector3 "CURVEDCONNECTOR4", // Curvedconnector4 "CURVEDCONNECTOR5", // Curvedconnector5 "CALLOUT1", // Callout1 "CALLOUT2", // Callout2 "CALLOUT3", // Callout3 "ACCENTCALLOUT1", // Accentcallout1 "ACCENTCALLOUT2", // Accentcallout2 "ACCENTCALLOUT3", // Accentcallout3 "BORDERCALLOUT1", // bordercallout1 "BORDERCALLOUT2", // Bordercallout2 "BORDERCALLOUT3", // Bordercallout3 "ACCENTBORDERCALLOUT1", // Accentbordercallout1 "ACCENTBORDERCALLOUT2", // Accentbordercallout2 "ACCENTBORDERCALLOUT3", // Accentbordercallout3 "RIBBON", // Ribbon "RIBBON2", // Ribbon2 "CHEVRON", // Chevron "PENTAGON", // Pentagon "NOSMOKING", // Nosmoking "SEAL8", // Seal8 "SEAL16", // Seal16 "SEAL32", // Seal32 "WEDGERECTCALLOUT", // Wedgerectcallout "WEDGERRECTCALLOUT", // Wedgerrectcallout "WEDGEELLIPSECALLOUT", // Wedgeellipsecallout "WAVE", // Wave "FOLDEDCORNER", // Foldedcorner "LEFTARROW", // Leftarrow "DOWNARROW", // Downarrow "UPARROW", // Uparrow "LEFTRIGHTARROW", // Leftrightarrow "UPDOWNARROW", // Updownarrow "IRREGULARSEAL1", // Irregularseal1 "IRREGULARSEAL2", // Irregularseal2 "LIGHTNINGBOLT", // Lightningbolt "HEART", // Heart "PICTUREFRAME", // PictureFrame "QUADARROW", // Quadarrow "LEFTARROWCALLOUT", // Leftarrowcallout "RIGHTARROWCALLOUT", // Rightarrowcallout "UPARROWCALLOUT", // Uparrowcallout "DOWNARROWCALLOUT", // Downarrowcallout "LEFTRIGHTARROWCALLOUT", // Leftrightarrowcallout "UPDOWNARROWCALLOUT", // Updownarrowcallout "QUADARROWCALLOUT", // Quadarrowcallout "BEVEL", // Bevel "LEFTBRACKET", // Leftbracket "RIGHTBRACKET", // Rightbracket "LEFTBRACE", // Leftbrace "RIGHTBRACE", // Rightbrace "LEFTUPARROW", // Leftuparrow "BENTUPARROW", // Bentuparrow "BENTARROW", // Bentarrow "SEAL24", // Seal24 "STRIPEDRIGHTARROW", // Stripedrightarrow "NOTCHEDRIGHTARROW", // Notchedrightarrow "BLOCKARC", // Blockarc "SMILEYFACE", // Smileyface "VERTICALSCROLL", // Verticalscroll "HORIZONTALSCROLL", // Horizontalscroll "CIRCULARARROW", // Circulararrow "NOTCHEDCIRCULARARROW", // Notchedcirculararrow "UTURNARROW", // Uturnarrow "CURVEDRIGHTARROW", // Curvedrightarrow "CURVEDLEFTARROW", // Curvedleftarrow "CURVEDUPARROW", // Curveduparrow "CURVEDDOWNARROW", // Curveddownarrow "CLOUDCALLOUT", // Cloudcallout "ELLIPSERIBBON", // Ellipseribbon "ELLIPSERIBBON2", // Ellipseribbon2 "FLOWCHARTPROCESS", // Flowchartprocess "FLOWCHARTDECISION", // Flowchartdecision "FLOWCHARTINPUTOUTPUT", // Flowchartinputoutput "FLOWCHARTPREDEFINEDPROCESS", // Flowchartpredefinedprocess "FLOWCHARTINTERNALSTORAGE", // Flowchartinternalstorage "FLOWCHARTDOCUMENT", // Flowchartdocument "FLOWCHARTMULTIDOCUMENT", // Flowchartmultidocument "FLOWCHARTTERMINATOR", // Flowchartterminator "FLOWCHARTPREPARATION", // Flowchartpreparation "FLOWCHARTMANUALINPUT", // Flowchartmanualinput "FLOWCHARTMANUALOPERATION", // Flowchartmanualoperation "FLOWCHARTCONNECTOR", // Flowchartconnector "FLOWCHARTPUNCHEDCARD", // Flowchartpunchedcard "FLOWCHARTPUNCHEDTAPE", // Flowchartpunchedtape "FLOWCHARTSUMMINGJUNCTION", // Flowchartsummingjunction "FLOWCHARTOR", // Flowchartor "FLOWCHARTCOLLATE", // Flowchartcollate "FLOWCHARTSORT", // Flowchartsort "FLOWCHARTEXTRACT", // Flowchartextract "FLOWCHARTMERGE", // Flowchartmerge "FLOWCHARTOFFLINESTORAGE", // Flowchartofflinestorage "FLOWCHARTONLINESTORAGE", // Flowchartonlinestorage "FLOWCHARTMAGNETICTAPE", // Flowchartmagnetictape "FLOWCHARTMAGNETICDISK", // Flowchartmagneticdisk "FLOWCHARTMAGNETICDRUM", // Flowchartmagneticdrum "FLOWCHARTDISPLAY", // Flowchartdisplay "FLOWCHARTDELAY", // Flowchartdelay "TEXTPLAINTEXT", // Textplaintext "TEXTSTOP", // Textstop "TEXTTRIANGLE", // Texttriangle "TEXTTRIANGLEINVERTED", // Texttriangleinverted "TEXTCHEVRON", // Textchevron "TEXTCHEVRONINVERTED", // Textchevroninverted "TEXTRINGINSIDE", // Textringinside "TEXTRINGOUTSIDE", // Textringoutside "TEXTARCHUPCURVE", // Textarchupcurve "TEXTARCHDOWNCURVE", // Textarchdowncurve "TEXTCIRCLECURVE", // Textcirclecurve "TEXTBUTTONCURVE", // Textbuttoncurve "TEXTARCHUPPOUR", // Textarchuppour "TEXTARCHDOWNPOUR", // Textarchdownpour "TEXTCIRCLEPOUR", // Textcirclepour "TEXTBUTTONPOUR", // Textbuttonpour "TEXTCURVEUP", // Textcurveup "TEXTCURVEDOWN", // Textcurvedown "TEXTCASCADEUP", // Textcascadeup "TEXTCASCADEDOWN", // Textcascadedown "TEXTWAVE1", // Textwave1 "TEXTWAVE2", // Textwave2 "TEXTWAVE3", // Textwave3 "TEXTWAVE4", // Textwave4 "TEXTINFLATE", // Textinflate "TEXTDEFLATE", // Textdeflate "TEXTINFLATEBOTTOM", // Textinflatebottom "TEXTDEFLATEBOTTOM", // Textdeflatebottom "TEXTINFLATETOP", // Textinflatetop "TEXTDEFLATETOP", // Textdeflatetop "TEXTDEFLATEINFLATE", // Textdeflateinflate "TEXTDEFLATEINFLATEDEFLATE", // Textdeflateinflatedeflate "TEXTFADERIGHT", // Textfaderight "TEXTFADELEFT", // Textfadeleft "TEXTFADEUP", // Textfadeup "TEXTFADEDOWN", // Textfadedown "TEXTSLANTUP", // Textslantup "TEXTSLANTDOWN", // Textslantdown "TEXTCANUP", // Textcanup "TEXTCANDOWN", // Textcandown "FLOWCHARTALTERNATEPROCESS", // Flowchartalternateprocess "FLOWCHARTOFFPAGECONNECTOR", // Flowchartoffpageconnector "CALLOUT90", // Callout90 "ACCENTCALLOUT90", // Accentcallout90 "BORDERCALLOUT90", // Bordercallout90 "ACCENTBORDERCALLOUT90", // Accentbordercallout90 "LEFTRIGHTUPARROW", // Leftrightuparrow "SUN", // Sun "MOON", // Moon "BRACKETPAIR", // Bracketpair "BRACEPAIR", // Bracepair "SEAL4", // Seal4 "DOUBLEWAVE", // Doublewave "ACTIONBUTTONBLANK", // Actionbuttonblank "ACTIONBUTTONHOME", // Actionbuttonhome "ACTIONBUTTONHELP", // Actionbuttonhelp "ACTIONBUTTONINFORMATION", // Actionbuttoninformation "ACTIONBUTTONFORWARDNEXT", // Actionbuttonforwardnext "ACTIONBUTTONBACKPREVIOUS", // Actionbuttonbackprevious "ACTIONBUTTONEND", // Actionbuttonend "ACTIONBUTTONBEGINNING", // Actionbuttonbeginning "ACTIONBUTTONRETURN", // Actionbuttonreturn "ACTIONBUTTONDOCUMENT", // Actionbuttondocument "ACTIONBUTTONSOUND", // Actionbuttonsound "ACTIONBUTTONMOVIE", // Actionbuttonmovie "HOSTCONTROL", // Hostcontrol "TEXTBOX", // Textbox }; struct { TQ_UINT32 spid; // The shape id union { TQ_UINT32 info; struct { TQ_UINT32 fGroup : 1; // This shape is a group shape TQ_UINT32 fChild : 1; // Not a top-level shape TQ_UINT32 fPatriarch : 1; // This is the topmost group shape. // Exactly one of these per drawing. TQ_UINT32 fDeleted : 1; // The shape.has been deleted TQ_UINT32 fOleShape : 1; // The shape is an OLE object TQ_UINT32 fHaveMaster : 1; // Shape has a hspMaster property TQ_UINT32 fFlipH : 1; // Shape is flipped horizontally TQ_UINT32 fFlipV : 1; // Shape is flipped vertically TQ_UINT32 fConnector : 1; // Connector type of shape TQ_UINT32 fHaveAnchor : 1; // Shape has an anchor of some kind TQ_UINT32 fBackground : 1; // Background shape TQ_UINT32 fHaveSpt : 1; // Shape has a shape type property TQ_UINT32 reserved : 20; // Not yet used } fields; } grfPersistent; } data; // Scan lookup table for operation. operands >> data.spid; operands >> data.grfPersistent.info; bytes -= 8; kdDebug(s_area) << "shape-id: " << data.spid << " type: " << funcTab[shapeType] << " (" << shapeType << ")" << (data.grfPersistent.fields.fGroup ? " group" : "") << (data.grfPersistent.fields.fChild ? " child" : "") << (data.grfPersistent.fields.fPatriarch ? " patriarch" : "") << (data.grfPersistent.fields.fDeleted ? " deleted" : "") << (data.grfPersistent.fields.fOleShape ? " oleshape" : "") << (data.grfPersistent.fields.fHaveMaster ? " master" : "") << (data.grfPersistent.fields.fFlipH ? " flipv" : "") << (data.grfPersistent.fields.fConnector ? " connector" : "") << (data.grfPersistent.fields.fHaveAnchor ? " anchor" : "") << (data.grfPersistent.fields.fBackground ? " background" : "") << (data.grfPersistent.fields.fHaveSpt ? " spt" : "") << " operands: " << bytes << endl; if (data.grfPersistent.fields.fDeleted) return; if ((!m_isRequiredDrawing) && (m_requestedShapeId != data.spid)) return; // An active shape! Let's draw it... switch (shapeType) { case 0: if (m_opt->m_pVertices) { gotPolyline(m_dc, *m_opt->m_pVertices); } break; case 1: if (bytes > 7) { TQPoint topLeft; TQSize size; topLeft = normalisePoint(operands); size = normaliseSize(operands); TQRect rect(topLeft, size); TQPointArray points(4); points.setPoint(0, topLeft); points.setPoint(1, rect.topRight()); points.setPoint(2, rect.bottomRight()); points.setPoint(3, rect.bottomLeft()); gotRectangle(m_dc, points); } case 20: if (bytes > 7) { TQPoint lineFrom; TQPoint lineTo; lineTo = normalisePoint(operands); TQPointArray points(2); points.setPoint(0, lineFrom); points.setPoint(1, lineTo); gotPolyline(m_dc, points); } break; default: break; } } void Msod::invokeHandler( Header &op, TQ_UINT32 bytes, TQDataStream &operands) { typedef void (Msod::*method)(Header &op, TQ_UINT32 bytes, TQDataStream &operands); typedef struct { const char *name; TQ_UINT16 opcode; method handler; } opcodeEntry; static const opcodeEntry funcTab[] = { { "ALIGNRULE", 0xF013, &Msod::opAlignrule }, { "ANCHOR", 0xF00E, &Msod::opAnchor }, { "ARCRULE", 0xF014, &Msod::opArcrule }, { "BSE", 0xF007, &Msod::opBse }, { "BSTORECONTAINER", 0xF001, &Msod::opBstorecontainer }, { "CALLOUTRULE", 0xF017, &Msod::opCalloutrule }, { "CHILDANCHOR", 0xF00F, &Msod::opChildanchor }, { "CLIENTANCHOR", 0xF010, &Msod::opClientanchor }, { "CLIENTDATA", 0xF011, &Msod::opClientdata }, { "CLIENTRULE", 0xF015, &Msod::opClientrule }, { "CLIENTTEXTBOX", 0xF00D, &Msod::opClienttextbox }, { "CLSID", 0xF016, &Msod::opClsid }, { "COLORMRU", 0xF11A, &Msod::opColormru }, { "CONNECTORRULE", 0xF012, &Msod::opConnectorrule }, { "DELETEDPSPL", 0xF11D, &Msod::opDeletedpspl }, { "DG", 0xF008, &Msod::opDg }, { "DGCONTAINER", 0xF002, &Msod::opDgcontainer }, { "DGG", 0xF006, &Msod::opDgg }, { "DGGCONTAINER", 0xF000, &Msod::opDggcontainer }, { "OLEOBJECT", 0xF11F, &Msod::opOleobject }, { "OPT", 0xF00B, &Msod::opOpt }, { "REGROUPITEMS", 0xF118, &Msod::opRegroupitems }, { "SELECTION", 0xF119, &Msod::opSelection }, { "SOLVERCONTAINER", 0xF005, &Msod::opSolvercontainer }, { "SP", 0xF00A, &Msod::opSp }, { "SPCONTAINER", 0xF004, &Msod::opSpcontainer }, { "SPGR", 0xF009, &Msod::opSpgr }, { "SPGRCONTAINER", 0xF003, &Msod::opSpgrcontainer }, { "SPLITMENUCOLORS", 0xF11E, &Msod::opSplitmenucolors }, { "TEXTBOX", 0xF00C, &Msod::opTextbox }, { NULL, 0, 0 }, { "BLIP", 0, &Msod::opBlip } }; unsigned i; method result; // Scan lookup table for operation. for (i = 0; funcTab[i].name; i++) { if (funcTab[i].opcode == op.opcode.fields.fbt) { break; } } // Invoke handler. result = funcTab[i].handler; if (!result && (op.opcode.fields.fbt >= 0xF018) && (0xF117 >= op.opcode.fields.fbt)) result = funcTab[++i].handler; if (!result) { if (funcTab[i].name) kdWarning(s_area) << "invokeHandler: unsupported opcode: " << funcTab[i].name << " operands: " << bytes << endl; else kdWarning(s_area) << "invokeHandler: unsupported opcode: 0x" << TQString::number(op.opcode.fields.fbt, 16) << " operands: " << bytes << endl; // Skip data we cannot use. skip(bytes, operands); } else { kdDebug(s_area) << "invokeHandler: opcode: " << funcTab[i].name << " operands: " << bytes << endl; // We don't invoke the handler directly on the incoming operands, but // via a temporary datastream. This adds overhead, but eliminates the // need for the individual handlers to read *exactly* the right amount // of data (thus speeding development, and possibly adding some // future-proofing). if (bytes) { TQByteArray *record = new TQByteArray(bytes); TQDataStream *body; operands.readRawBytes(record->data(), bytes); body = new TQDataStream(*record, IO_ReadOnly); body->setByteOrder(TQDataStream::LittleEndian); (this->*result)(op, bytes, *body); delete body; delete record; } else { TQDataStream *body = new TQDataStream(); (this->*result)(op, bytes, *body); delete body; } } } TQPoint Msod::normalisePoint( TQDataStream &operands) { TQ_UINT16 x; TQ_UINT16 y; operands >> x >> y; return TQPoint(x / m_dpi, y / m_dpi); } TQSize Msod::normaliseSize( TQDataStream &operands) { TQ_UINT16 width; TQ_UINT16 height; operands >> width >> height; return TQSize(width / m_dpi, height / m_dpi); } bool Msod::parse( unsigned shapeId, const TQString &file, const char *delayStream) { TQFile in(file); if (!in.open(IO_ReadOnly)) { kdError(s_area) << "Unable to open input file!" << endl; in.close(); return false; } TQDataStream stream(&in); bool result = parse(shapeId, stream, in.size(), delayStream); in.close(); return result; } bool Msod::parse( unsigned shapeId, TQDataStream &stream, unsigned size, const char *delayStream) { stream.setByteOrder(TQDataStream::LittleEndian); // Great, I love TQt ! m_requestedShapeId = shapeId; m_isRequiredDrawing = false; m_delayStream = delayStream; // Read bits. walk(size, stream); return true; } void Msod::opAlignrule( Header &, TQ_UINT32, TQDataStream &) { } void Msod::opAnchor( Header &, TQ_UINT32, TQDataStream &) { } void Msod::opArcrule( Header &, TQ_UINT32, TQDataStream &) { } void Msod::opBlip(Header &, TQ_UINT32 bytes, TQDataStream &operands) { typedef enum { msobiWMF = 0x216, // Metafile header then compressed WMF. msobiEMF = 0x3D4, // Metafile header then compressed EMF. msobiPICT = 0x542, // Metafile header then compressed PICT. msobiPNG = 0x6E0, // One byte tag then PNG data. msobiJPEG = 0x46A, // One byte tag then JFIF data. msobiDIB = 0x7A8, // One byte tag then DIB data. msobiClient = 0x800 // Clients should set this bit. } MSOBI; typedef enum { msocompressionDeflate, msocompressionNone = 254, msocompressionTest } MSOBLIPCOMPRESSION; bool hasPrimaryId; TQ_UINT32 length = 0; struct { TQ_UINT32 cb; struct { TQ_UINT32 x; TQ_UINT32 y; TQ_UINT32 w; TQ_UINT32 h; } bounds; struct { TQ_UINT32 w; TQ_UINT32 h; } ptSize; TQ_UINT32 cbSave; TQ_UINT8 compression; TQ_UINT8 filter; } data; // Skip any explicit primary header (m_rgbUidprimary). switch (m_blipType) { case msoblipEMF: hasPrimaryId = (m_blipType ^ msobiEMF) != 0; break; case msoblipWMF: hasPrimaryId = (m_blipType ^ msobiWMF) != 0; break; case msoblipPICT: hasPrimaryId = (m_blipType ^ msobiPICT) != 0; break; case msoblipJPEG: hasPrimaryId = (m_blipType ^ msobiJPEG) != 0; break; case msoblipPNG: hasPrimaryId = (m_blipType ^ msobiPNG) != 0; break; case msoblipDIB: hasPrimaryId = (m_blipType ^ msobiDIB) != 0; break; default: hasPrimaryId = (m_blipType ^ msobiClient) != 0; break; } if (hasPrimaryId) { length += 16; skip(16, operands); } // Process the rest of the header. data.compression = msocompressionNone; switch (m_blipType) { case msoblipEMF: case msoblipWMF: case msoblipPICT: length += 34; operands >> data.cb; operands >> data.bounds.x >> data.bounds.y >> data.bounds.w >> data.bounds.h; operands >> data.ptSize.w >> data.ptSize.h; operands >> data.cbSave; operands >> data.compression >> data.filter; break; case msoblipJPEG: case msoblipPNG: case msoblipDIB: // Skip the "tag". length += 1; skip(1, operands); break; default: break; } // Work out the file type. Image *image = new Image(); switch (m_blipType) { case msoblipEMF: image->extension = "emf"; break; case msoblipWMF: image->extension = "wmf"; break; case msoblipPICT: image->extension = "pic"; break; case msoblipJPEG: image->extension = "jpg"; break; case msoblipPNG: image->extension = "png"; break; case msoblipDIB: image->extension = "dib"; break; default: image->extension = "img"; break; } image->length = bytes - length; image->data = new char[image->length]; operands.readRawBytes((char *)image->data, image->length); if (data.compression == msocompressionDeflate) { const char *tmp; uLongf destLen = data.cb; int result; tmp = new char[data.cb]; result = uncompress((TQ_UINT8 *)tmp, &destLen, (TQ_UINT8 *)image->data, image->length); if (result != Z_OK) { kdError(s_area) << "opBlip: uncompress failed: " << result << endl; } if (destLen != data.cb) { kdError(s_area) << "opBlip: uncompressed " << destLen << " instead of " << data.cb << endl; } delete [] image->data; image->data = tmp; image->length = destLen; } m_images.resize(m_images.size() + 1); m_images.insert(m_images.size() - 1, image); } // FBSE - File Blip Store Entry void Msod::opBse(Header &op, TQ_UINT32, TQDataStream &operands) { struct { TQ_UINT8 btWin32; // Required type on Win32. TQ_UINT8 btMacOS; // Required type on Mac. TQ_UINT8 rgbUid[16]; // Identifier of blip. TQ_UINT16 tag; // currently unused. TQ_UINT32 size; // Blip size in stream. TQ_UINT32 cRef; // Reference count on the blip. TQ_UINT32 foDelay; // File offset in the delay stream. TQ_UINT8 usage; // How this blip is used (MSOBLIPUSAGE). TQ_UINT8 cbName; // length of the blip name. TQ_UINT8 unused2; // for the future. TQ_UINT8 unused3; // for the future. } data; unsigned i; // Work out the type of the BLIP. m_blipType = static_cast(op.opcode.fields.inst); operands >> data.btWin32; operands >> data.btMacOS; for (i = 0; i < 16; i++) operands >> data.rgbUid[i]; operands >> data.tag >> data.size; operands >> data.cRef >> data.foDelay; operands >> data.usage >> data.cbName; operands >> data.unused2 >> data.unused2; // If the Blip is not in this drawing file, process it "manually". if (m_delayStream) { // The m_pib refers to images by number, which includes images // that are no longer here. Thus, we fake these out so that any // references to non-deleted images are still valid (!!!). if (data.size && data.cRef) { TQByteArray bytes; bytes.setRawData(m_delayStream + data.foDelay, data.size); TQDataStream stream(bytes, IO_ReadOnly); stream.setByteOrder(TQDataStream::LittleEndian); walk(data.size, stream); bytes.resetRawData(m_delayStream + data.foDelay, data.size); } else { m_images.resize(m_images.size() + 1); m_images.insert(m_images.size() - 1, 0L); } } } void Msod::opBstorecontainer(Header &, TQ_UINT32 bytes, TQDataStream &operands) { walk(bytes, operands); } void Msod::opCalloutrule( Header &, TQ_UINT32, TQDataStream &) { } void Msod::opChildanchor( Header &, TQ_UINT32, TQDataStream &) { } void Msod::opClientanchor(Header &, TQ_UINT32, TQDataStream &operands) { struct { TQ_UINT32 unknown; } data; operands >> data.unknown; kdDebug(s_area) << "client anchor: " << data.unknown << endl; } void Msod::opClientdata(Header &, TQ_UINT32, TQDataStream &operands) { struct { TQ_UINT32 unknown; } data; operands >> data.unknown; kdDebug(s_area) << "client data: " << data.unknown << endl; } void Msod::opClientrule( Header &, TQ_UINT32, TQDataStream &) { } void Msod::opClienttextbox( Header &, TQ_UINT32, TQDataStream &operands) { struct { TQ_UINT32 unknown; } data; operands >> data.unknown; kdDebug(s_area) << "client textbox: 0x" << TQString::number(data.unknown,16) << endl; } void Msod::opClsid( Header &, TQ_UINT32, TQDataStream &) { } void Msod::opColormru( Header &, TQ_UINT32, TQDataStream &) { } void Msod::opConnectorrule( Header &, TQ_UINT32, TQDataStream &) { } void Msod::opDeletedpspl( Header &, TQ_UINT32, TQDataStream &) { } // FDG - File DG void Msod::opDg(Header &, TQ_UINT32, TQDataStream &operands) { struct { TQ_UINT32 csp; // The number of shapes in this drawing. TQ_UINT32 spidCur; // The last shape ID given to an SP in this DG. } data; operands >> data.csp >> data.spidCur; kdDebug(s_area) << "drawing id: " << data.spidCur << endl; m_isRequiredDrawing = (m_requestedShapeId == data.spidCur); if (m_isRequiredDrawing) { kdDebug(s_area) << "found requested drawing" << endl; } } void Msod::opDgcontainer(Header &, TQ_UINT32 bytes, TQDataStream &operands) { walk(bytes, operands); } // FDGG - File DGG void Msod::opDgg(Header &, TQ_UINT32, TQDataStream &operands) { struct { TQ_UINT32 spidMax; // The current maximum shape ID. TQ_UINT32 cidcl; // The number of ID clusters (FIDCLs). TQ_UINT32 cspSaved; // The total number of shapes saved. // (including deleted shapes, if undo // information was saved). TQ_UINT32 cdgSaved; // The total number of drawings saved. } data; // File ID Cluster - used to save IDCLs struct { TQ_UINT32 dgid; // DG owning the SPIDs in this cluster TQ_UINT32 cspidCur; // number of SPIDs used so far } data1; unsigned i; operands >> data.spidMax >> data.cidcl >> data.cspSaved >> data.cdgSaved; kdDebug(s_area) << data.cspSaved << " shapes in " << data.cidcl - 1 << " clusters in " << data.cdgSaved << " drawings" << endl; for (i = 0; i < data.cidcl - 1; i++) { operands >> data1.dgid >> data1.cspidCur; } } void Msod::opDggcontainer(Header &, TQ_UINT32 bytes, TQDataStream &operands) { walk(bytes, operands); } void Msod::opOleobject( Header &, TQ_UINT32, TQDataStream &) { } void Msod::opOpt(Header &, TQ_UINT32 bytes, TQDataStream &operands) { m_opt->walk(bytes, operands); } void Msod::opRegroupitems( Header &, TQ_UINT32, TQDataStream &) { } void Msod::opSelection( Header &, TQ_UINT32, TQDataStream &) { } void Msod::opSolvercontainer(Header &, TQ_UINT32 bytes, TQDataStream &operands) { walk(bytes, operands); } void Msod::opSp(Header &op, TQ_UINT32 bytes, TQDataStream &operands) { // We want to defer the act of drawing a shape until we have seen any options // that may affect it. Thus, we merely store the data away, and let opSpContainer // do all the ahrd work. m_shape.type = op.opcode.fields.inst; m_shape.length = bytes; m_shape.data = new char [bytes]; operands.readRawBytes(m_shape.data, bytes); } void Msod::opSpcontainer(Header &, TQ_UINT32 bytes, TQDataStream &operands) { walk(bytes, operands); // Having gathered all the information for this shape, we can now draw it. TQByteArray a; a.setRawData(m_shape.data, m_shape.length); TQDataStream s(a, IO_ReadOnly); s.setByteOrder(TQDataStream::LittleEndian); // Great, I love TQt ! drawShape(m_shape.type, m_shape.length, s); a.resetRawData(m_shape.data, m_shape.length); delete [] m_shape.data; m_shape.data = 0L; } void Msod::opSpgr(Header &, TQ_UINT32, TQDataStream &operands) { struct { TQ_UINT32 x; TQ_UINT32 y; TQ_UINT32 w; TQ_UINT32 h; } data; operands >> data.x >> data.y >> data.w >> data.h; } void Msod::opSpgrcontainer(Header &, TQ_UINT32 bytes, TQDataStream &operands) { walk(bytes, operands); } void Msod::opSplitmenucolors(Header &, TQ_UINT32, TQDataStream &operands) { struct { TQ_UINT32 fill; TQ_UINT32 line; TQ_UINT32 shadow; TQ_UINT32 threeDee; } data; operands >> data.fill >> data.line >> data.shadow >> data.threeDee; } void Msod::opTextbox( Header &, TQ_UINT32, TQDataStream &) { } void Msod::skip(TQ_UINT32 bytes, TQDataStream &operands) { if ((int)bytes < 0) { kdError(s_area) << "skip: " << (int)bytes << endl; return; } if (bytes) { TQ_UINT32 i; TQ_UINT8 discard; kdDebug(s_area) << "skip: " << bytes << endl; for (i = 0; i < bytes; i++) { operands >> discard; } } } void Msod::walk(TQ_UINT32 bytes, TQDataStream &operands) { Header op; TQ_UINT32 length = 0; // Stop parsing when there are no more records. Note that we stop as soon // as we cannot get a complete header. while (length + 8 <= bytes) { operands >> op.opcode.info >> op.cbLength; // If we get some duff data, protect ourselves. if (length + op.cbLength + 8 > bytes) { op.cbLength = bytes - length - 8; } length += op.cbLength + 8; if (op.opcode.fields.fbt == 0x200) { // This appears to be an EOF marker. break; } // Package the arguments... invokeHandler(op, op.cbLength, operands); } // Eat unexpected data that the caller may expect us to consume. skip(bytes - length, operands); } Msod::Options::Options( Msod &parent) : m_parent(parent) { m_pVertices = 0L; initialise(); } Msod::Options::~Options() { delete m_pVertices; } double Msod::Options::from1616ToDouble(TQ_UINT32 value) { return (value >> 16) + 65535.0 / (double)(value & 0xffff); } void Msod::Options::initialise() { m_rotation = 0.0; m_lTxid = 0; m_pib = 0; m_pibName = TQString(); m_pibFlags = 0; m_pictureId = 0; m_fNoHitTestPicture = false; m_pictureGray = false; m_pictureBiLevel = false; m_pictureActive = false; m_geoLeft = 0; m_geoTop = 0; m_geoRight = 21600; m_geoBottom = 21600; m_shapePath = 1; delete m_pVertices; m_pVertices = 0L; m_fShadowOK = true; m_f3DOK = true; m_fLineOK = true; m_fGTextOK = false; m_fFillShadeShapeOK = false; m_fFillOK = true; m_fFilled = true; m_fHitTestFill = true; m_fillShape = true; m_fillUseRect = false; m_fNoFillHitTest = false; m_lineColor = 0; m_lineBackColor = 0xffffff; m_lineType = 0; m_lineWidth = 9525; m_fArrowheadsOK = false; m_fLine = true; m_fHitTestLine = true; m_lineFillShape = true; m_fNoLineDrawDash = false; m_bWMode = 1; m_fOleIcon = false; m_fPreferRelativeResize = false; m_fLockShapeType = false; m_fDeleteAttachedObject = false; m_fBackground = false; } void Msod::Options::walk(TQ_UINT32 bytes, TQDataStream &operands) { Header op; TQ_UINT16 length = 0; TQ_UINT16 complexLength = 0; // Reset all options to default values. initialise(); // First process all simple options, and add all complex options to a list. TQPtrList
complexOpts; complexOpts.setAutoDelete(true); bool unsupported; while (length + complexLength < (int)bytes) { operands >> op.opcode.info >> op.value; length += 6; // Defer processing of complex options. if (op.opcode.fields.fComplex) { complexLength += op.value; complexOpts.append(new Header(op)); continue; } // Now squirrel away the option value. unsupported = false; switch (op.opcode.fields.pid) { case 4: m_rotation = from1616ToDouble(op.value); break; case 128: m_lTxid = op.value; kdDebug(s_area) << "textbox: 0x" << TQString::number(op.value,16) << endl; break; case 260: if (op.opcode.fields.fBid) { m_pib = op.value; if (m_parent.m_isRequiredDrawing) { Image *image = m_parent.m_images[m_pib - 1]; // If it is an embedded WMF we don't bother with the // part; we just extract it as more vector graphics. if (image->extension == "wmf") { TQByteArray a; a.setRawData(image->data, image->length); TQDataStream s(a, IO_ReadOnly); m_parent.KWmf::parse(s, image->length); a.resetRawData(image->data, image->length); } else { m_parent.gotPicture( m_pib, image->extension, image->length, image->data); } } } else { kdError(s_area) << "Cannot handle IMsoBlip" << endl; } break; case 262: m_pibFlags = op.value; break; case 267: m_pictureId = op.value; break; case 319: m_fNoHitTestPicture = (op.value & 0x0008) != 0; m_pictureGray = (op.value & 0x0004) != 0; m_pictureBiLevel = (op.value & 0x0002) != 0; m_pictureActive = (op.value & 0x0001) != 0; break; case 320: m_geoLeft = op.value; break; case 321: m_geoTop = op.value; break; case 322: m_geoRight = op.value; break; case 323: m_geoBottom = op.value; break; case 324: m_shapePath = op.value; break; case 383: m_fShadowOK = (op.value & 0x0020) != 0; m_f3DOK = (op.value & 0x0010) != 0; m_fLineOK = (op.value & 0x0008) != 0; m_fGTextOK = (op.value & 0x0004) != 0; m_fFillShadeShapeOK = (op.value & 0x0002) != 0; m_fFillOK = (op.value & 0x0001) != 0; break; case 447: m_fFilled = (op.value & 0x0010) != 0; m_fHitTestFill = (op.value & 0x0008) != 0; m_fillShape = (op.value & 0x0004) != 0; m_fillUseRect = (op.value & 0x0002) != 0; m_fNoFillHitTest = (op.value & 0x0001) != 0; break; case 448: m_lineColor = op.value; break; case 450: m_lineBackColor = op.value; break; case 452: m_lineType = op.value; break; case 459: m_lineWidth = op.value; break; case 511: m_fArrowheadsOK = (op.value & 0x0010) != 0; m_fLine = (op.value & 0x0008) != 0; m_fHitTestLine = (op.value & 0x0004) != 0; m_lineFillShape = (op.value & 0x0002) != 0; m_fNoLineDrawDash = (op.value & 0x0001) != 0; break; case 772: m_bWMode = op.value; break; case 831: m_fOleIcon = (op.value & 0x0010) != 0; m_fPreferRelativeResize = (op.value & 0x0008) != 0; m_fLockShapeType = (op.value & 0x0004) != 0; m_fDeleteAttachedObject = (op.value & 0x0002) != 0; m_fBackground = (op.value & 0x0001) != 0; break; default: unsupported = true; kdWarning(s_area) << "unsupported simple option: " << op.opcode.fields.pid << endl; break; } if (!unsupported) kdDebug(s_area) << "simple option: " << op.opcode.fields.pid << endl; } // Now empty the list of complex options. while (complexOpts.count()) { TQ_INT16 t16; unsigned i; op = *complexOpts.getFirst(); complexOpts.removeFirst(); unsupported = false; switch (op.opcode.fields.pid) { case 261: while (true) { operands >> t16; if (!t16) break; m_pibName += TQChar(t16); }; break; case 325: m_pVertices = new TQPointArray(op.value / 4); for (i = 0; i < m_pVertices->count(); i++) { m_pVertices->setPoint(i, m_parent.normalisePoint(operands)); }; break; case 326: operands >> t16; i = t16; operands >> t16; operands >> t16; m_parent.skip(i * t16, operands); break; default: unsupported = true; kdWarning(s_area) << "unsupported complex option: " << op.opcode.fields.pid << " operands: " << op.value << endl; m_parent.skip(op.value, operands); break; } if (!unsupported) kdDebug(s_area) << "complex option: " << op.opcode.fields.pid << " operands: " << op.value << endl; complexLength -= op.value; } }