msod.cpp
1/*
2 Copyright (C) 2000, S.R.Haque <shaheedhaque@hotmail.com>.
3 This file is part of the KDE project
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19
20DESCRIPTION
21*/
22
23#include <kdebug.h>
24#include <tqdatastream.h>
25#include <tqfile.h>
26#include <tqptrlist.h>
27#include <tqpointarray.h>
28#include <tqrect.h>
29#include <tqsize.h>
30#include <msod.h>
31#include <zlib.h>
32
33const int Msod::s_area = 30505;
34
35Msod::Msod(
36 unsigned dpi) :
37 KWmf(dpi)
38{
39 m_dpi = dpi;
40 m_images.setAutoDelete(true);
41 m_opt = new Options(*this);
42 m_shape.data = 0L;
43 m_shape.length = 0;
44}
45
46Msod::~Msod()
47{
48 delete [] m_shape.data;
49 delete m_opt;
50}
51
52void Msod::drawShape(
53 unsigned shapeType,
54 TQ_UINT32 bytes,
55 TQDataStream &operands)
56{
57 static const char *funcTab[] =
58 {
59 "UNKNOWN", // Unknown
60 "RECTANGLE", // Rectangle
61 "ROUNDRECTANGLE", // Roundrectangle
62 "ELLIPSE", // Ellipse
63 "DIAMOND", // Diamond
64 "ISOCELESTRIANGLE", // Isocelestriangle
65 "RIGHTTRIANGLE", // Righttriangle
66 "PARALLELOGRAM", // Parallelogram
67 "TRAPEZOID", // Trapezoid
68 "HEXAGON", // Hexagon
69 "OCTAGON", // Octagon
70 "PLUS", // Plus
71 "STAR", // Star
72 "ARROW", // Arrow
73 "THICKARROW", // Thickarrow
74 "HOMEPLATE", // Homeplate
75 "CUBE", // Cube
76 "BALLOON", // Balloon
77 "SEAL", // Seal
78 "ARC", // Arc
79 "LINE", // Line
80 "PLAQUE", // Plaque
81 "CAN", // Can
82 "DONUT", // Donut
83 "TEXTSIMPLE", // Textsimple
84 "TEXTOCTAGON", // Textoctagon
85 "TEXTHEXAGON", // Texthexagon
86 "TEXTCURVE", // Textcurve
87 "TEXTWAVE", // Textwave
88 "TEXTRING", // Textring
89 "TEXTONCURVE", // Textoncurve
90 "TEXTONRING", // Textonring
91 "STRAIGHTCONNECTOR1", // Straightconnector1
92 "BENTCONNECTOR2", // Bentconnector2
93 "BENTCONNECTOR3", // Bentconnector3
94 "BENTCONNECTOR4", // Bentconnector4
95 "BENTCONNECTOR5", // Bentconnector5
96 "CURVEDCONNECTOR2", // Curvedconnector2
97 "CURVEDCONNECTOR3", // Curvedconnector3
98 "CURVEDCONNECTOR4", // Curvedconnector4
99 "CURVEDCONNECTOR5", // Curvedconnector5
100 "CALLOUT1", // Callout1
101 "CALLOUT2", // Callout2
102 "CALLOUT3", // Callout3
103 "ACCENTCALLOUT1", // Accentcallout1
104 "ACCENTCALLOUT2", // Accentcallout2
105 "ACCENTCALLOUT3", // Accentcallout3
106 "BORDERCALLOUT1", // bordercallout1
107 "BORDERCALLOUT2", // Bordercallout2
108 "BORDERCALLOUT3", // Bordercallout3
109 "ACCENTBORDERCALLOUT1", // Accentbordercallout1
110 "ACCENTBORDERCALLOUT2", // Accentbordercallout2
111 "ACCENTBORDERCALLOUT3", // Accentbordercallout3
112 "RIBBON", // Ribbon
113 "RIBBON2", // Ribbon2
114 "CHEVRON", // Chevron
115 "PENTAGON", // Pentagon
116 "NOSMOKING", // Nosmoking
117 "SEAL8", // Seal8
118 "SEAL16", // Seal16
119 "SEAL32", // Seal32
120 "WEDGERECTCALLOUT", // Wedgerectcallout
121 "WEDGERRECTCALLOUT", // Wedgerrectcallout
122 "WEDGEELLIPSECALLOUT", // Wedgeellipsecallout
123 "WAVE", // Wave
124 "FOLDEDCORNER", // Foldedcorner
125 "LEFTARROW", // Leftarrow
126 "DOWNARROW", // Downarrow
127 "UPARROW", // Uparrow
128 "LEFTRIGHTARROW", // Leftrightarrow
129 "UPDOWNARROW", // Updownarrow
130 "IRREGULARSEAL1", // Irregularseal1
131 "IRREGULARSEAL2", // Irregularseal2
132 "LIGHTNINGBOLT", // Lightningbolt
133 "HEART", // Heart
134 "PICTUREFRAME", // PictureFrame
135 "QUADARROW", // Quadarrow
136 "LEFTARROWCALLOUT", // Leftarrowcallout
137 "RIGHTARROWCALLOUT", // Rightarrowcallout
138 "UPARROWCALLOUT", // Uparrowcallout
139 "DOWNARROWCALLOUT", // Downarrowcallout
140 "LEFTRIGHTARROWCALLOUT", // Leftrightarrowcallout
141 "UPDOWNARROWCALLOUT", // Updownarrowcallout
142 "QUADARROWCALLOUT", // Quadarrowcallout
143 "BEVEL", // Bevel
144 "LEFTBRACKET", // Leftbracket
145 "RIGHTBRACKET", // Rightbracket
146 "LEFTBRACE", // Leftbrace
147 "RIGHTBRACE", // Rightbrace
148 "LEFTUPARROW", // Leftuparrow
149 "BENTUPARROW", // Bentuparrow
150 "BENTARROW", // Bentarrow
151 "SEAL24", // Seal24
152 "STRIPEDRIGHTARROW", // Stripedrightarrow
153 "NOTCHEDRIGHTARROW", // Notchedrightarrow
154 "BLOCKARC", // Blockarc
155 "SMILEYFACE", // Smileyface
156 "VERTICALSCROLL", // Verticalscroll
157 "HORIZONTALSCROLL", // Horizontalscroll
158 "CIRCULARARROW", // Circulararrow
159 "NOTCHEDCIRCULARARROW", // Notchedcirculararrow
160 "UTURNARROW", // Uturnarrow
161 "CURVEDRIGHTARROW", // Curvedrightarrow
162 "CURVEDLEFTARROW", // Curvedleftarrow
163 "CURVEDUPARROW", // Curveduparrow
164 "CURVEDDOWNARROW", // Curveddownarrow
165 "CLOUDCALLOUT", // Cloudcallout
166 "ELLIPSERIBBON", // Ellipseribbon
167 "ELLIPSERIBBON2", // Ellipseribbon2
168 "FLOWCHARTPROCESS", // Flowchartprocess
169 "FLOWCHARTDECISION", // Flowchartdecision
170 "FLOWCHARTINPUTOUTPUT", // Flowchartinputoutput
171 "FLOWCHARTPREDEFINEDPROCESS", // Flowchartpredefinedprocess
172 "FLOWCHARTINTERNALSTORAGE", // Flowchartinternalstorage
173 "FLOWCHARTDOCUMENT", // Flowchartdocument
174 "FLOWCHARTMULTIDOCUMENT", // Flowchartmultidocument
175 "FLOWCHARTTERMINATOR", // Flowchartterminator
176 "FLOWCHARTPREPARATION", // Flowchartpreparation
177 "FLOWCHARTMANUALINPUT", // Flowchartmanualinput
178 "FLOWCHARTMANUALOPERATION", // Flowchartmanualoperation
179 "FLOWCHARTCONNECTOR", // Flowchartconnector
180 "FLOWCHARTPUNCHEDCARD", // Flowchartpunchedcard
181 "FLOWCHARTPUNCHEDTAPE", // Flowchartpunchedtape
182 "FLOWCHARTSUMMINGJUNCTION", // Flowchartsummingjunction
183 "FLOWCHARTOR", // Flowchartor
184 "FLOWCHARTCOLLATE", // Flowchartcollate
185 "FLOWCHARTSORT", // Flowchartsort
186 "FLOWCHARTEXTRACT", // Flowchartextract
187 "FLOWCHARTMERGE", // Flowchartmerge
188 "FLOWCHARTOFFLINESTORAGE", // Flowchartofflinestorage
189 "FLOWCHARTONLINESTORAGE", // Flowchartonlinestorage
190 "FLOWCHARTMAGNETICTAPE", // Flowchartmagnetictape
191 "FLOWCHARTMAGNETICDISK", // Flowchartmagneticdisk
192 "FLOWCHARTMAGNETICDRUM", // Flowchartmagneticdrum
193 "FLOWCHARTDISPLAY", // Flowchartdisplay
194 "FLOWCHARTDELAY", // Flowchartdelay
195 "TEXTPLAINTEXT", // Textplaintext
196 "TEXTSTOP", // Textstop
197 "TEXTTRIANGLE", // Texttriangle
198 "TEXTTRIANGLEINVERTED", // Texttriangleinverted
199 "TEXTCHEVRON", // Textchevron
200 "TEXTCHEVRONINVERTED", // Textchevroninverted
201 "TEXTRINGINSIDE", // Textringinside
202 "TEXTRINGOUTSIDE", // Textringoutside
203 "TEXTARCHUPCURVE", // Textarchupcurve
204 "TEXTARCHDOWNCURVE", // Textarchdowncurve
205 "TEXTCIRCLECURVE", // Textcirclecurve
206 "TEXTBUTTONCURVE", // Textbuttoncurve
207 "TEXTARCHUPPOUR", // Textarchuppour
208 "TEXTARCHDOWNPOUR", // Textarchdownpour
209 "TEXTCIRCLEPOUR", // Textcirclepour
210 "TEXTBUTTONPOUR", // Textbuttonpour
211 "TEXTCURVEUP", // Textcurveup
212 "TEXTCURVEDOWN", // Textcurvedown
213 "TEXTCASCADEUP", // Textcascadeup
214 "TEXTCASCADEDOWN", // Textcascadedown
215 "TEXTWAVE1", // Textwave1
216 "TEXTWAVE2", // Textwave2
217 "TEXTWAVE3", // Textwave3
218 "TEXTWAVE4", // Textwave4
219 "TEXTINFLATE", // Textinflate
220 "TEXTDEFLATE", // Textdeflate
221 "TEXTINFLATEBOTTOM", // Textinflatebottom
222 "TEXTDEFLATEBOTTOM", // Textdeflatebottom
223 "TEXTINFLATETOP", // Textinflatetop
224 "TEXTDEFLATETOP", // Textdeflatetop
225 "TEXTDEFLATEINFLATE", // Textdeflateinflate
226 "TEXTDEFLATEINFLATEDEFLATE", // Textdeflateinflatedeflate
227 "TEXTFADERIGHT", // Textfaderight
228 "TEXTFADELEFT", // Textfadeleft
229 "TEXTFADEUP", // Textfadeup
230 "TEXTFADEDOWN", // Textfadedown
231 "TEXTSLANTUP", // Textslantup
232 "TEXTSLANTDOWN", // Textslantdown
233 "TEXTCANUP", // Textcanup
234 "TEXTCANDOWN", // Textcandown
235 "FLOWCHARTALTERNATEPROCESS", // Flowchartalternateprocess
236 "FLOWCHARTOFFPAGECONNECTOR", // Flowchartoffpageconnector
237 "CALLOUT90", // Callout90
238 "ACCENTCALLOUT90", // Accentcallout90
239 "BORDERCALLOUT90", // Bordercallout90
240 "ACCENTBORDERCALLOUT90", // Accentbordercallout90
241 "LEFTRIGHTUPARROW", // Leftrightuparrow
242 "SUN", // Sun
243 "MOON", // Moon
244 "BRACKETPAIR", // Bracketpair
245 "BRACEPAIR", // Bracepair
246 "SEAL4", // Seal4
247 "DOUBLEWAVE", // Doublewave
248 "ACTIONBUTTONBLANK", // Actionbuttonblank
249 "ACTIONBUTTONHOME", // Actionbuttonhome
250 "ACTIONBUTTONHELP", // Actionbuttonhelp
251 "ACTIONBUTTONINFORMATION", // Actionbuttoninformation
252 "ACTIONBUTTONFORWARDNEXT", // Actionbuttonforwardnext
253 "ACTIONBUTTONBACKPREVIOUS", // Actionbuttonbackprevious
254 "ACTIONBUTTONEND", // Actionbuttonend
255 "ACTIONBUTTONBEGINNING", // Actionbuttonbeginning
256 "ACTIONBUTTONRETURN", // Actionbuttonreturn
257 "ACTIONBUTTONDOCUMENT", // Actionbuttondocument
258 "ACTIONBUTTONSOUND", // Actionbuttonsound
259 "ACTIONBUTTONMOVIE", // Actionbuttonmovie
260 "HOSTCONTROL", // Hostcontrol
261 "TEXTBOX", // Textbox
262 };
263 struct
264 {
265 TQ_UINT32 spid; // The shape id
266 union
267 {
268 TQ_UINT32 info;
269 struct
270 {
271 TQ_UINT32 fGroup : 1; // This shape is a group shape
272 TQ_UINT32 fChild : 1; // Not a top-level shape
273 TQ_UINT32 fPatriarch : 1; // This is the topmost group shape.
274 // Exactly one of these per drawing.
275 TQ_UINT32 fDeleted : 1; // The shape.has been deleted
276 TQ_UINT32 fOleShape : 1; // The shape is an OLE object
277 TQ_UINT32 fHaveMaster : 1; // Shape has a hspMaster property
278 TQ_UINT32 fFlipH : 1; // Shape is flipped horizontally
279 TQ_UINT32 fFlipV : 1; // Shape is flipped vertically
280 TQ_UINT32 fConnector : 1; // Connector type of shape
281 TQ_UINT32 fHaveAnchor : 1; // Shape has an anchor of some kind
282 TQ_UINT32 fBackground : 1; // Background shape
283 TQ_UINT32 fHaveSpt : 1; // Shape has a shape type property
284 TQ_UINT32 reserved : 20; // Not yet used
285 } fields;
286 } grfPersistent;
287 } data;
288
289 // Scan lookup table for operation.
290
291 operands >> data.spid;
292 operands >> data.grfPersistent.info;
293 bytes -= 8;
294 kdDebug(s_area) << "shape-id: " << data.spid << " type: " << funcTab[shapeType] << " (" << shapeType << ")" <<
295 (data.grfPersistent.fields.fGroup ? " group" : "") <<
296 (data.grfPersistent.fields.fChild ? " child" : "") <<
297 (data.grfPersistent.fields.fPatriarch ? " patriarch" : "") <<
298 (data.grfPersistent.fields.fDeleted ? " deleted" : "") <<
299 (data.grfPersistent.fields.fOleShape ? " oleshape" : "") <<
300 (data.grfPersistent.fields.fHaveMaster ? " master" : "") <<
301 (data.grfPersistent.fields.fFlipH ? " flipv" : "") <<
302 (data.grfPersistent.fields.fConnector ? " connector" : "") <<
303 (data.grfPersistent.fields.fHaveAnchor ? " anchor" : "") <<
304 (data.grfPersistent.fields.fBackground ? " background" : "") <<
305 (data.grfPersistent.fields.fHaveSpt ? " spt" : "") <<
306 " operands: " << bytes << endl;
307 if (data.grfPersistent.fields.fDeleted)
308 return;
309 if ((!m_isRequiredDrawing) && (m_requestedShapeId != data.spid))
310 return;
311
312 // An active shape! Let's draw it...
313
314 switch (shapeType)
315 {
316 case 0:
317 if (m_opt->m_pVertices)
318 {
319 gotPolyline(m_dc, *m_opt->m_pVertices);
320 }
321 break;
322 case 1:
323 if (bytes > 7)
324 {
325 TQPoint topLeft;
326 TQSize size;
327
328 topLeft = normalisePoint(operands);
329 size = normaliseSize(operands);
330
331 TQRect rect(topLeft, size);
332 TQPointArray points(4);
333
334 points.setPoint(0, topLeft);
335 points.setPoint(1, rect.topRight());
336 points.setPoint(2, rect.bottomRight());
337 points.setPoint(3, rect.bottomLeft());
338 gotRectangle(m_dc, points);
339 }
340 case 20:
341 if (bytes > 7)
342 {
343 TQPoint lineFrom;
344 TQPoint lineTo;
345
346 lineTo = normalisePoint(operands);
347
348 TQPointArray points(2);
349
350 points.setPoint(0, lineFrom);
351 points.setPoint(1, lineTo);
352 gotPolyline(m_dc, points);
353 }
354 break;
355 default:
356 break;
357 }
358}
359
360void Msod::invokeHandler(
361 Header &op,
362 TQ_UINT32 bytes,
363 TQDataStream &operands)
364{
365 typedef void (Msod::*method)(Header &op, TQ_UINT32 bytes, TQDataStream &operands);
366
367 typedef struct
368 {
369 const char *name;
370 TQ_UINT16 opcode;
371 method handler;
372 } opcodeEntry;
373
374 static const opcodeEntry funcTab[] =
375 {
376 { "ALIGNRULE", 0xF013, &Msod::opAlignrule },
377 { "ANCHOR", 0xF00E, &Msod::opAnchor },
378 { "ARCRULE", 0xF014, &Msod::opArcrule },
379 { "BSE", 0xF007, &Msod::opBse },
380 { "BSTORECONTAINER", 0xF001, &Msod::opBstorecontainer },
381 { "CALLOUTRULE", 0xF017, &Msod::opCalloutrule },
382 { "CHILDANCHOR", 0xF00F, &Msod::opChildanchor },
383 { "CLIENTANCHOR", 0xF010, &Msod::opClientanchor },
384 { "CLIENTDATA", 0xF011, &Msod::opClientdata },
385 { "CLIENTRULE", 0xF015, &Msod::opClientrule },
386 { "CLIENTTEXTBOX", 0xF00D, &Msod::opClienttextbox },
387 { "CLSID", 0xF016, &Msod::opClsid },
388 { "COLORMRU", 0xF11A, &Msod::opColormru },
389 { "CONNECTORRULE", 0xF012, &Msod::opConnectorrule },
390 { "DELETEDPSPL", 0xF11D, &Msod::opDeletedpspl },
391 { "DG", 0xF008, &Msod::opDg },
392 { "DGCONTAINER", 0xF002, &Msod::opDgcontainer },
393 { "DGG", 0xF006, &Msod::opDgg },
394 { "DGGCONTAINER", 0xF000, &Msod::opDggcontainer },
395 { "OLEOBJECT", 0xF11F, &Msod::opOleobject },
396 { "OPT", 0xF00B, &Msod::opOpt },
397 { "REGROUPITEMS", 0xF118, &Msod::opRegroupitems },
398 { "SELECTION", 0xF119, &Msod::opSelection },
399 { "SOLVERCONTAINER", 0xF005, &Msod::opSolvercontainer },
400 { "SP", 0xF00A, &Msod::opSp },
401 { "SPCONTAINER", 0xF004, &Msod::opSpcontainer },
402 { "SPGR", 0xF009, &Msod::opSpgr },
403 { "SPGRCONTAINER", 0xF003, &Msod::opSpgrcontainer },
404 { "SPLITMENUCOLORS", 0xF11E, &Msod::opSplitmenucolors },
405 { "TEXTBOX", 0xF00C, &Msod::opTextbox },
406 { NULL, 0, 0 },
407 { "BLIP", 0, &Msod::opBlip }
408 };
409 unsigned i;
410 method result;
411
412 // Scan lookup table for operation.
413
414 for (i = 0; funcTab[i].name; i++)
415 {
416 if (funcTab[i].opcode == op.opcode.fields.fbt)
417 {
418 break;
419 }
420 }
421
422 // Invoke handler.
423
424 result = funcTab[i].handler;
425 if (!result && (op.opcode.fields.fbt >= 0xF018) && (0xF117 >= op.opcode.fields.fbt))
426 result = funcTab[++i].handler;
427 if (!result)
428 {
429 if (funcTab[i].name)
430 kdWarning(s_area) << "invokeHandler: unsupported opcode: " <<
431 funcTab[i].name <<
432 " operands: " << bytes << endl;
433 else
434 kdWarning(s_area) << "invokeHandler: unsupported opcode: 0x" <<
435 TQString::number(op.opcode.fields.fbt, 16) <<
436 " operands: " << bytes << endl;
437
438 // Skip data we cannot use.
439
440 skip(bytes, operands);
441 }
442 else
443 {
444 kdDebug(s_area) << "invokeHandler: opcode: " << funcTab[i].name <<
445 " operands: " << bytes << endl;
446
447 // We don't invoke the handler directly on the incoming operands, but
448 // via a temporary datastream. This adds overhead, but eliminates the
449 // need for the individual handlers to read *exactly* the right amount
450 // of data (thus speeding development, and possibly adding some
451 // future-proofing).
452
453 if (bytes)
454 {
455 TQByteArray *record = new TQByteArray(bytes);
456 TQDataStream *body;
457
458 operands.readRawBytes(record->data(), bytes);
459 body = new TQDataStream(*record, IO_ReadOnly);
460 body->setByteOrder(TQDataStream::LittleEndian);
461 (this->*result)(op, bytes, *body);
462 delete body;
463 delete record;
464 }
465 else
466 {
467 TQDataStream *body = new TQDataStream();
468
469 (this->*result)(op, bytes, *body);
470 delete body;
471 }
472 }
473}
474
475TQPoint Msod::normalisePoint(
476 TQDataStream &operands)
477{
478 TQ_UINT16 x;
479 TQ_UINT16 y;
480
481 operands >> x >> y;
482 return TQPoint(x / m_dpi, y / m_dpi);
483}
484
485TQSize Msod::normaliseSize(
486 TQDataStream &operands)
487{
488 TQ_UINT16 width;
489 TQ_UINT16 height;
490
491 operands >> width >> height;
492 return TQSize(width / m_dpi, height / m_dpi);
493}
494
495bool Msod::parse(
496 unsigned shapeId,
497 const TQString &file,
498 const char *delayStream)
499{
500 TQFile in(file);
501 if (!in.open(IO_ReadOnly))
502 {
503 kdError(s_area) << "Unable to open input file!" << endl;
504 in.close();
505 return false;
506 }
507 TQDataStream stream(&in);
508 bool result = parse(shapeId, stream, in.size(), delayStream);
509 in.close();
510 return result;
511}
512
513bool Msod::parse(
514 unsigned shapeId,
515 TQDataStream &stream,
516 unsigned size,
517 const char *delayStream)
518{
519 stream.setByteOrder(TQDataStream::LittleEndian); // Great, I love TQt !
520 m_requestedShapeId = shapeId;
521 m_isRequiredDrawing = false;
522 m_delayStream = delayStream;
523
524 // Read bits.
525
526 walk(size, stream);
527 return true;
528}
529
530void Msod::opAlignrule(
531 Header &,
532 TQ_UINT32,
533 TQDataStream &)
534{
535}
536
537void Msod::opAnchor(
538 Header &,
539 TQ_UINT32,
540 TQDataStream &)
541{
542}
543
544void Msod::opArcrule(
545 Header &,
546 TQ_UINT32,
547 TQDataStream &)
548{
549}
550
551void Msod::opBlip(Header &, TQ_UINT32 bytes, TQDataStream &operands)
552{
553 typedef enum
554 {
555 msobiWMF = 0x216, // Metafile header then compressed WMF.
556 msobiEMF = 0x3D4, // Metafile header then compressed EMF.
557 msobiPICT = 0x542, // Metafile header then compressed PICT.
558 msobiPNG = 0x6E0, // One byte tag then PNG data.
559 msobiJPEG = 0x46A, // One byte tag then JFIF data.
560 msobiDIB = 0x7A8, // One byte tag then DIB data.
561 msobiClient = 0x800 // Clients should set this bit.
562 } MSOBI;
563 typedef enum
564 {
565 msocompressionDeflate,
566 msocompressionNone = 254,
567 msocompressionTest
568 } MSOBLIPCOMPRESSION;
569
570 bool hasPrimaryId;
571 TQ_UINT32 length = 0;
572 struct
573 {
574 TQ_UINT32 cb;
575 struct
576 {
577 TQ_UINT32 x;
578 TQ_UINT32 y;
579 TQ_UINT32 w;
580 TQ_UINT32 h;
581 } bounds;
582 struct
583 {
584 TQ_UINT32 w;
585 TQ_UINT32 h;
586 } ptSize;
587 TQ_UINT32 cbSave;
588 TQ_UINT8 compression;
589 TQ_UINT8 filter;
590 } data;
591
592 // Skip any explicit primary header (m_rgbUidprimary).
593
594 switch (m_blipType)
595 {
596 case msoblipEMF:
597 hasPrimaryId = (m_blipType ^ msobiEMF) != 0;
598 break;
599 case msoblipWMF:
600 hasPrimaryId = (m_blipType ^ msobiWMF) != 0;
601 break;
602 case msoblipPICT:
603 hasPrimaryId = (m_blipType ^ msobiPICT) != 0;
604 break;
605 case msoblipJPEG:
606 hasPrimaryId = (m_blipType ^ msobiJPEG) != 0;
607 break;
608 case msoblipPNG:
609 hasPrimaryId = (m_blipType ^ msobiPNG) != 0;
610 break;
611 case msoblipDIB:
612 hasPrimaryId = (m_blipType ^ msobiDIB) != 0;
613 break;
614 default:
615 hasPrimaryId = (m_blipType ^ msobiClient) != 0;
616 break;
617 }
618 if (hasPrimaryId)
619 {
620 length += 16;
621 skip(16, operands);
622 }
623
624 // Process the rest of the header.
625
626 data.compression = msocompressionNone;
627 switch (m_blipType)
628 {
629 case msoblipEMF:
630 case msoblipWMF:
631 case msoblipPICT:
632 length += 34;
633 operands >> data.cb;
634 operands >> data.bounds.x >> data.bounds.y >> data.bounds.w >> data.bounds.h;
635 operands >> data.ptSize.w >> data.ptSize.h;
636 operands >> data.cbSave;
637 operands >> data.compression >> data.filter;
638 break;
639 case msoblipJPEG:
640 case msoblipPNG:
641 case msoblipDIB:
642 // Skip the "tag".
643 length += 1;
644 skip(1, operands);
645 break;
646 default:
647 break;
648 }
649
650 // Work out the file type.
651
652 Image *image = new Image();
653 switch (m_blipType)
654 {
655 case msoblipEMF:
656 image->extension = "emf";
657 break;
658 case msoblipWMF:
659 image->extension = "wmf";
660 break;
661 case msoblipPICT:
662 image->extension = "pic";
663 break;
664 case msoblipJPEG:
665 image->extension = "jpg";
666 break;
667 case msoblipPNG:
668 image->extension = "png";
669 break;
670 case msoblipDIB:
671 image->extension = "dib";
672 break;
673 default:
674 image->extension = "img";
675 break;
676 }
677 image->length = bytes - length;
678 image->data = new char[image->length];
679 operands.readRawBytes((char *)image->data, image->length);
680 if (data.compression == msocompressionDeflate)
681 {
682 const char *tmp;
683 uLongf destLen = data.cb;
684 int result;
685
686 tmp = new char[data.cb];
687 result = uncompress((TQ_UINT8 *)tmp, &destLen, (TQ_UINT8 *)image->data, image->length);
688 if (result != Z_OK)
689 {
690 kdError(s_area) << "opBlip: uncompress failed: " << result << endl;
691 }
692 if (destLen != data.cb)
693 {
694 kdError(s_area) << "opBlip: uncompressed " << destLen << " instead of " << data.cb << endl;
695 }
696 delete [] image->data;
697 image->data = tmp;
698 image->length = destLen;
699 }
700 m_images.resize(m_images.size() + 1);
701 m_images.insert(m_images.size() - 1, image);
702}
703
704// FBSE - File Blip Store Entry
705
706void Msod::opBse(Header &op, TQ_UINT32, TQDataStream &operands)
707{
708 struct
709 {
710 TQ_UINT8 btWin32; // Required type on Win32.
711 TQ_UINT8 btMacOS; // Required type on Mac.
712 TQ_UINT8 rgbUid[16]; // Identifier of blip.
713 TQ_UINT16 tag; // currently unused.
714 TQ_UINT32 size; // Blip size in stream.
715 TQ_UINT32 cRef; // Reference count on the blip.
716 TQ_UINT32 foDelay; // File offset in the delay stream.
717 TQ_UINT8 usage; // How this blip is used (MSOBLIPUSAGE).
718 TQ_UINT8 cbName; // length of the blip name.
719 TQ_UINT8 unused2; // for the future.
720 TQ_UINT8 unused3; // for the future.
721 } data;
722 unsigned i;
723
724 // Work out the type of the BLIP.
725
726 m_blipType = static_cast<MSOBLIPTYPE>(op.opcode.fields.inst);
727 operands >> data.btWin32;
728 operands >> data.btMacOS;
729 for (i = 0; i < 16; i++)
730 operands >> data.rgbUid[i];
731 operands >> data.tag >> data.size;
732 operands >> data.cRef >> data.foDelay;
733 operands >> data.usage >> data.cbName;
734 operands >> data.unused2 >> data.unused2;
735
736 // If the Blip is not in this drawing file, process it "manually".
737
738 if (m_delayStream)
739 {
740 // The m_pib refers to images by number, which includes images
741 // that are no longer here. Thus, we fake these out so that any
742 // references to non-deleted images are still valid (!!!).
743
744 if (data.size && data.cRef)
745 {
746 TQByteArray bytes;
747 bytes.setRawData(m_delayStream + data.foDelay, data.size);
748 TQDataStream stream(bytes, IO_ReadOnly);
749 stream.setByteOrder(TQDataStream::LittleEndian);
750 walk(data.size, stream);
751 bytes.resetRawData(m_delayStream + data.foDelay, data.size);
752 }
753 else
754 {
755 m_images.resize(m_images.size() + 1);
756 m_images.insert(m_images.size() - 1, 0L);
757 }
758 }
759}
760
761void Msod::opBstorecontainer(Header &, TQ_UINT32 bytes, TQDataStream &operands)
762{
763 walk(bytes, operands);
764}
765
766void Msod::opCalloutrule(
767 Header &,
768 TQ_UINT32,
769 TQDataStream &)
770{
771}
772
773void Msod::opChildanchor(
774 Header &,
775 TQ_UINT32,
776 TQDataStream &)
777{
778}
779
780void Msod::opClientanchor(Header &, TQ_UINT32, TQDataStream &operands)
781{
782 struct
783 {
784 TQ_UINT32 unknown;
785 } data;
786
787 operands >> data.unknown;
788 kdDebug(s_area) << "client anchor: " << data.unknown << endl;
789}
790
791void Msod::opClientdata(Header &, TQ_UINT32, TQDataStream &operands)
792{
793 struct
794 {
795 TQ_UINT32 unknown;
796 } data;
797
798 operands >> data.unknown;
799 kdDebug(s_area) << "client data: " << data.unknown << endl;
800}
801
802void Msod::opClientrule(
803 Header &,
804 TQ_UINT32,
805 TQDataStream &)
806{
807}
808
809void Msod::opClienttextbox(
810 Header &,
811 TQ_UINT32,
812 TQDataStream &operands)
813{
814 struct
815 {
816 TQ_UINT32 unknown;
817 } data;
818
819 operands >> data.unknown;
820 kdDebug(s_area) << "client textbox: 0x" << TQString::number(data.unknown,16) << endl;
821}
822
823void Msod::opClsid(
824 Header &,
825 TQ_UINT32,
826 TQDataStream &)
827{
828}
829
830void Msod::opColormru(
831 Header &,
832 TQ_UINT32,
833 TQDataStream &)
834{
835}
836
837void Msod::opConnectorrule(
838 Header &,
839 TQ_UINT32,
840 TQDataStream &)
841{
842}
843
844void Msod::opDeletedpspl(
845 Header &,
846 TQ_UINT32,
847 TQDataStream &)
848{
849}
850
851// FDG - File DG
852
853void Msod::opDg(Header &, TQ_UINT32, TQDataStream &operands)
854{
855 struct
856 {
857 TQ_UINT32 csp; // The number of shapes in this drawing.
858 TQ_UINT32 spidCur; // The last shape ID given to an SP in this DG.
859 } data;
860
861 operands >> data.csp >> data.spidCur;
862 kdDebug(s_area) << "drawing id: " << data.spidCur << endl;
863 m_isRequiredDrawing = (m_requestedShapeId == data.spidCur);
864 if (m_isRequiredDrawing)
865 {
866 kdDebug(s_area) << "found requested drawing" << endl;
867 }
868}
869
870void Msod::opDgcontainer(Header &, TQ_UINT32 bytes, TQDataStream &operands)
871{
872 walk(bytes, operands);
873}
874
875// FDGG - File DGG
876
877void Msod::opDgg(Header &, TQ_UINT32, TQDataStream &operands)
878{
879 struct
880 {
881 TQ_UINT32 spidMax; // The current maximum shape ID.
882 TQ_UINT32 cidcl; // The number of ID clusters (FIDCLs).
883 TQ_UINT32 cspSaved; // The total number of shapes saved.
884 // (including deleted shapes, if undo
885 // information was saved).
886 TQ_UINT32 cdgSaved; // The total number of drawings saved.
887 } data;
888
889 // File ID Cluster - used to save IDCLs
890
891 struct
892 {
893 TQ_UINT32 dgid; // DG owning the SPIDs in this cluster
894 TQ_UINT32 cspidCur; // number of SPIDs used so far
895 } data1;
896 unsigned i;
897
898 operands >> data.spidMax >> data.cidcl >> data.cspSaved >> data.cdgSaved;
899 kdDebug(s_area) << data.cspSaved << " shapes in " <<
900 data.cidcl - 1 << " clusters in " <<
901 data.cdgSaved << " drawings" << endl;
902 for (i = 0; i < data.cidcl - 1; i++)
903 {
904 operands >> data1.dgid >> data1.cspidCur;
905 }
906}
907
908void Msod::opDggcontainer(Header &, TQ_UINT32 bytes, TQDataStream &operands)
909{
910 walk(bytes, operands);
911}
912
913void Msod::opOleobject(
914 Header &,
915 TQ_UINT32,
916 TQDataStream &)
917{
918}
919
920void Msod::opOpt(Header &, TQ_UINT32 bytes, TQDataStream &operands)
921{
922 m_opt->walk(bytes, operands);
923}
924
925void Msod::opRegroupitems(
926 Header &,
927 TQ_UINT32,
928 TQDataStream &)
929{
930}
931
932void Msod::opSelection(
933 Header &,
934 TQ_UINT32,
935 TQDataStream &)
936{
937}
938
939void Msod::opSolvercontainer(Header &, TQ_UINT32 bytes, TQDataStream &operands)
940{
941 walk(bytes, operands);
942}
943
944void Msod::opSp(Header &op, TQ_UINT32 bytes, TQDataStream &operands)
945{
946 // We want to defer the act of drawing a shape until we have seen any options
947 // that may affect it. Thus, we merely store the data away, and let opSpContainer
948 // do all the ahrd work.
949
950 m_shape.type = op.opcode.fields.inst;
951 m_shape.length = bytes;
952 m_shape.data = new char [bytes];
953 operands.readRawBytes(m_shape.data, bytes);
954}
955
956void Msod::opSpcontainer(Header &, TQ_UINT32 bytes, TQDataStream &operands)
957{
958 walk(bytes, operands);
959
960 // Having gathered all the information for this shape, we can now draw it.
961
962 TQByteArray a;
963
964 a.setRawData(m_shape.data, m_shape.length);
965 TQDataStream s(a, IO_ReadOnly);
966 s.setByteOrder(TQDataStream::LittleEndian); // Great, I love TQt !
967 drawShape(m_shape.type, m_shape.length, s);
968 a.resetRawData(m_shape.data, m_shape.length);
969 delete [] m_shape.data;
970 m_shape.data = 0L;
971}
972
973void Msod::opSpgr(Header &, TQ_UINT32, TQDataStream &operands)
974{
975 struct
976 {
977 TQ_UINT32 x;
978 TQ_UINT32 y;
979 TQ_UINT32 w;
980 TQ_UINT32 h;
981 } data;
982
983 operands >> data.x >> data.y >> data.w >> data.h;
984}
985
986void Msod::opSpgrcontainer(Header &, TQ_UINT32 bytes, TQDataStream &operands)
987{
988 walk(bytes, operands);
989}
990
991void Msod::opSplitmenucolors(Header &, TQ_UINT32, TQDataStream &operands)
992{
993 struct
994 {
995 TQ_UINT32 fill;
996 TQ_UINT32 line;
997 TQ_UINT32 shadow;
998 TQ_UINT32 threeDee;
999 } data;
1000
1001 operands >> data.fill >> data.line >> data.shadow >> data.threeDee;
1002}
1003
1004void Msod::opTextbox(
1005 Header &,
1006 TQ_UINT32,
1007 TQDataStream &)
1008{
1009}
1010
1011void Msod::skip(TQ_UINT32 bytes, TQDataStream &operands)
1012{
1013 if ((int)bytes < 0)
1014 {
1015 kdError(s_area) << "skip: " << (int)bytes << endl;
1016 return;
1017 }
1018 if (bytes)
1019 {
1020 TQ_UINT32 i;
1021 TQ_UINT8 discard;
1022
1023 kdDebug(s_area) << "skip: " << bytes << endl;
1024 for (i = 0; i < bytes; i++)
1025 {
1026 operands >> discard;
1027 }
1028 }
1029}
1030
1031void Msod::walk(TQ_UINT32 bytes, TQDataStream &operands)
1032{
1033 Header op;
1034 TQ_UINT32 length = 0;
1035
1036 // Stop parsing when there are no more records. Note that we stop as soon
1037 // as we cannot get a complete header.
1038 while (length + 8 <= bytes)
1039 {
1040 operands >> op.opcode.info >> op.cbLength;
1041
1042 // If we get some duff data, protect ourselves.
1043 if (length + op.cbLength + 8 > bytes)
1044 {
1045 op.cbLength = bytes - length - 8;
1046 }
1047 length += op.cbLength + 8;
1048 if (op.opcode.fields.fbt == 0x200)
1049 {
1050 // This appears to be an EOF marker.
1051 break;
1052 }
1053
1054 // Package the arguments...
1055
1056 invokeHandler(op, op.cbLength, operands);
1057 }
1058
1059 // Eat unexpected data that the caller may expect us to consume.
1060 skip(bytes - length, operands);
1061}
1062
1063Msod::Options::Options(
1064 Msod &parent) :
1065 m_parent(parent)
1066{
1067 m_pVertices = 0L;
1068 initialise();
1069}
1070
1071Msod::Options::~Options()
1072{
1073 delete m_pVertices;
1074}
1075
1076double Msod::Options::from1616ToDouble(TQ_UINT32 value)
1077{
1078 return (value >> 16) + 65535.0 / (double)(value & 0xffff);
1079}
1080
1081void Msod::Options::initialise()
1082{
1083 m_rotation = 0.0;
1084
1085 m_lTxid = 0;
1086
1087 m_pib = 0;
1088 m_pibName = TQString();
1089 m_pibFlags = 0;
1090 m_pictureId = 0;
1091 m_fNoHitTestPicture = false;
1092 m_pictureGray = false;
1093 m_pictureBiLevel = false;
1094 m_pictureActive = false;
1095
1096 m_geoLeft = 0;
1097 m_geoTop = 0;
1098 m_geoRight = 21600;
1099 m_geoBottom = 21600;
1100 m_shapePath = 1;
1101 delete m_pVertices;
1102 m_pVertices = 0L;
1103 m_fShadowOK = true;
1104 m_f3DOK = true;
1105 m_fLineOK = true;
1106 m_fGTextOK = false;
1107 m_fFillShadeShapeOK = false;
1108 m_fFillOK = true;
1109
1110 m_fFilled = true;
1111 m_fHitTestFill = true;
1112 m_fillShape = true;
1113 m_fillUseRect = false;
1114 m_fNoFillHitTest = false;
1115
1116 m_lineColor = 0;
1117 m_lineBackColor = 0xffffff;
1118 m_lineType = 0;
1119 m_lineWidth = 9525;
1120
1121 m_fArrowheadsOK = false;
1122 m_fLine = true;
1123 m_fHitTestLine = true;
1124 m_lineFillShape = true;
1125 m_fNoLineDrawDash = false;
1126
1127 m_bWMode = 1;
1128
1129 m_fOleIcon = false;
1130 m_fPreferRelativeResize = false;
1131 m_fLockShapeType = false;
1132 m_fDeleteAttachedObject = false;
1133 m_fBackground = false;
1134}
1135
1136void Msod::Options::walk(TQ_UINT32 bytes, TQDataStream &operands)
1137{
1138 Header op;
1139 TQ_UINT16 length = 0;
1140 TQ_UINT16 complexLength = 0;
1141
1142 // Reset all options to default values.
1143
1144 initialise();
1145
1146 // First process all simple options, and add all complex options to a list.
1147
1148 TQPtrList<Header> complexOpts;
1149 complexOpts.setAutoDelete(true);
1150 bool unsupported;
1151 while (length + complexLength < (int)bytes)
1152 {
1153 operands >> op.opcode.info >> op.value;
1154 length += 6;
1155
1156 // Defer processing of complex options.
1157
1158 if (op.opcode.fields.fComplex)
1159 {
1160 complexLength += op.value;
1161 complexOpts.append(new Header(op));
1162 continue;
1163 }
1164
1165 // Now squirrel away the option value.
1166
1167 unsupported = false;
1168 switch (op.opcode.fields.pid)
1169 {
1170 case 4:
1171 m_rotation = from1616ToDouble(op.value);
1172 break;
1173 case 128:
1174 m_lTxid = op.value;
1175 kdDebug(s_area) << "textbox: 0x" << TQString::number(op.value,16) << endl;
1176 break;
1177 case 260:
1178 if (op.opcode.fields.fBid)
1179 {
1180 m_pib = op.value;
1181 if (m_parent.m_isRequiredDrawing)
1182 {
1183 Image *image = m_parent.m_images[m_pib - 1];
1184
1185 // If it is an embedded WMF we don't bother with the
1186 // part; we just extract it as more vector graphics.
1187
1188 if (image->extension == "wmf")
1189 {
1190 TQByteArray a;
1191 a.setRawData(image->data, image->length);
1192 TQDataStream s(a, IO_ReadOnly);
1193 m_parent.KWmf::parse(s, image->length);
1194 a.resetRawData(image->data, image->length);
1195 }
1196 else
1197 {
1198 m_parent.gotPicture(
1199 m_pib,
1200 image->extension,
1201 image->length,
1202 image->data);
1203 }
1204 }
1205 }
1206 else
1207 {
1208 kdError(s_area) << "Cannot handle IMsoBlip" << endl;
1209 }
1210 break;
1211 case 262:
1212 m_pibFlags = op.value;
1213 break;
1214 case 267:
1215 m_pictureId = op.value;
1216 break;
1217 case 319:
1218 m_fNoHitTestPicture = (op.value & 0x0008) != 0;
1219 m_pictureGray = (op.value & 0x0004) != 0;
1220 m_pictureBiLevel = (op.value & 0x0002) != 0;
1221 m_pictureActive = (op.value & 0x0001) != 0;
1222 break;
1223 case 320:
1224 m_geoLeft = op.value;
1225 break;
1226 case 321:
1227 m_geoTop = op.value;
1228 break;
1229 case 322:
1230 m_geoRight = op.value;
1231 break;
1232 case 323:
1233 m_geoBottom = op.value;
1234 break;
1235 case 324:
1236 m_shapePath = op.value;
1237 break;
1238 case 383:
1239 m_fShadowOK = (op.value & 0x0020) != 0;
1240 m_f3DOK = (op.value & 0x0010) != 0;
1241 m_fLineOK = (op.value & 0x0008) != 0;
1242 m_fGTextOK = (op.value & 0x0004) != 0;
1243 m_fFillShadeShapeOK = (op.value & 0x0002) != 0;
1244 m_fFillOK = (op.value & 0x0001) != 0;
1245 break;
1246 case 447:
1247 m_fFilled = (op.value & 0x0010) != 0;
1248 m_fHitTestFill = (op.value & 0x0008) != 0;
1249 m_fillShape = (op.value & 0x0004) != 0;
1250 m_fillUseRect = (op.value & 0x0002) != 0;
1251 m_fNoFillHitTest = (op.value & 0x0001) != 0;
1252 break;
1253 case 448:
1254 m_lineColor = op.value;
1255 break;
1256 case 450:
1257 m_lineBackColor = op.value;
1258 break;
1259 case 452:
1260 m_lineType = op.value;
1261 break;
1262 case 459:
1263 m_lineWidth = op.value;
1264 break;
1265 case 511:
1266 m_fArrowheadsOK = (op.value & 0x0010) != 0;
1267 m_fLine = (op.value & 0x0008) != 0;
1268 m_fHitTestLine = (op.value & 0x0004) != 0;
1269 m_lineFillShape = (op.value & 0x0002) != 0;
1270 m_fNoLineDrawDash = (op.value & 0x0001) != 0;
1271 break;
1272 case 772:
1273 m_bWMode = op.value;
1274 break;
1275 case 831:
1276 m_fOleIcon = (op.value & 0x0010) != 0;
1277 m_fPreferRelativeResize = (op.value & 0x0008) != 0;
1278 m_fLockShapeType = (op.value & 0x0004) != 0;
1279 m_fDeleteAttachedObject = (op.value & 0x0002) != 0;
1280 m_fBackground = (op.value & 0x0001) != 0;
1281 break;
1282 default:
1283 unsupported = true;
1284 kdWarning(s_area) << "unsupported simple option: " <<
1285 op.opcode.fields.pid << endl;
1286 break;
1287 }
1288 if (!unsupported)
1289 kdDebug(s_area) << "simple option: " <<
1290 op.opcode.fields.pid << endl;
1291 }
1292
1293 // Now empty the list of complex options.
1294
1295 while (complexOpts.count())
1296 {
1297 TQ_INT16 t16;
1298 unsigned i;
1299
1300 op = *complexOpts.getFirst();
1301 complexOpts.removeFirst();
1302 unsupported = false;
1303 switch (op.opcode.fields.pid)
1304 {
1305 case 261:
1306 while (true)
1307 {
1308 operands >> t16;
1309 if (!t16)
1310 break;
1311 m_pibName += TQChar(t16);
1312 };
1313 break;
1314 case 325:
1315 m_pVertices = new TQPointArray(op.value / 4);
1316 for (i = 0; i < m_pVertices->count(); i++)
1317 {
1318 m_pVertices->setPoint(i, m_parent.normalisePoint(operands));
1319 };
1320 break;
1321 case 326:
1322 operands >> t16;
1323 i = t16;
1324 operands >> t16;
1325 operands >> t16;
1326 m_parent.skip(i * t16, operands);
1327 break;
1328 default:
1329 unsupported = true;
1330 kdWarning(s_area) << "unsupported complex option: " <<
1331 op.opcode.fields.pid << " operands: " << op.value << endl;
1332 m_parent.skip(op.value, operands);
1333 break;
1334 }
1335 if (!unsupported)
1336 kdDebug(s_area) << "complex option: " <<
1337 op.opcode.fields.pid << " operands: " << op.value << endl;
1338 complexLength -= op.value;
1339 }
1340}