1 /* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */
2
3 /* libmwaw
4 * Version: MPL 2.0 / LGPLv2+
5 *
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 2.0 (the "License"); you may not use this file except in compliance with
8 * the License or as specified alternatively below. You may obtain a copy of
9 * the License at http://www.mozilla.org/MPL/
10 *
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
15 *
16 * Major Contributor(s):
17 * Copyright (C) 2002 William Lachance (wrlach@gmail.com)
18 * Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net)
19 * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
20 * Copyright (C) 2006, 2007 Andrew Ziem
21 * Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr)
22 *
23 *
24 * All Rights Reserved.
25 *
26 * For minor contributions see the git repository.
27 *
28 * Alternatively, the contents of this file may be used under the terms of
29 * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
30 * in which case the provisions of the LGPLv2+ are applicable
31 * instead of those above.
32 */
33
34 #include <cmath>
35 #include <iomanip>
36 #include <iostream>
37 #include <limits>
38 #include <sstream>
39
40 #include <librevenge/librevenge.h>
41
42 #include "MWAWGraphicListener.hxx"
43 #include "MWAWGraphicShape.hxx"
44 #include "MWAWGraphicStyle.hxx"
45 #include "MWAWHeader.hxx"
46 #include "MWAWParagraph.hxx"
47 #include "MWAWPictBitmap.hxx"
48 #include "MWAWPictData.hxx"
49 #include "MWAWPrinter.hxx"
50 #include "MWAWPosition.hxx"
51 #include "MWAWSubDocument.hxx"
52
53 #include "MacDrawParser.hxx"
54
55 /** Internal: the structures of a MacDrawParser */
56 namespace MacDrawParserInternal
57 {
58 // generic class used to store shape in MWAWDrawParser
59 struct Shape {
60 //! the different shape
61 enum Type { Basic, Bitmap, Group, GroupEnd, Text, Unknown };
62
63 //! constructor
ShapeMacDrawParserInternal::Shape64 Shape()
65 : m_type(Unknown)
66 , m_box()
67 , m_style()
68 , m_shape()
69 , m_id(-1)
70 , m_nextId(-1)
71 , m_font()
72 , m_paragraph()
73 , m_textEntry()
74 , m_childList()
75 , m_numBytesByRow(0)
76 , m_bitmapDim()
77 , m_bitmapFileDim()
78 , m_bitmapEntry()
79 , m_isSent(false)
80 {
81 }
82
83 //! return the shape bdbox
getBdBoxMacDrawParserInternal::Shape84 MWAWBox2f getBdBox() const
85 {
86 return m_type==Basic ? m_shape.getBdBox() : m_box;
87 }
88 //! the graphic type
89 Type m_type;
90 //! the shape bdbox
91 MWAWBox2f m_box;
92 //! the graphic style
93 MWAWGraphicStyle m_style;
94 //! the graphic shape ( for basic geometric form )
95 MWAWGraphicShape m_shape;
96 //! the shape id
97 int m_id;
98 //! the following id (if set)
99 int m_nextId;
100 //! the font ( for a text box)
101 MWAWFont m_font;
102 //! the paragraph ( for a text box)
103 MWAWParagraph m_paragraph;
104 //! the textbox entry (main text)
105 MWAWEntry m_textEntry;
106 //! the child list ( for a group )
107 std::vector<size_t> m_childList;
108 //! the number of bytes by row (for a bitmap)
109 int m_numBytesByRow;
110 //! the bitmap dimension (in page)
111 MWAWBox2i m_bitmapDim;
112 //! the bitmap dimension (in the file)
113 MWAWBox2i m_bitmapFileDim;
114 //! the bitmap entry (data)
115 MWAWEntry m_bitmapEntry;
116 //! a flag used to know if the object is sent to the listener or not
117 mutable bool m_isSent;
118 };
119
120 ////////////////////////////////////////
121 //! Internal: the state of a MacDrawParser
122 struct State {
123 //! constructor
StateMacDrawParserInternal::State124 State()
125 : m_version(0)
126 , m_patternList()
127 , m_shapeList()
128 {
129 }
130 //! returns a pattern if posible
getPatternMacDrawParserInternal::State131 bool getPattern(int id, MWAWGraphicStyle::Pattern &pat)
132 {
133 if (m_patternList.empty()) initPatterns();
134 if (id<=0 || id>int(m_patternList.size())) {
135 MWAW_DEBUG_MSG(("MacDrawParserInternal::getPattern: can not find pattern %d\n", id));
136 return false;
137 }
138 pat=m_patternList[size_t(id-1)];
139 return true;
140 }
141 //! init the patterns list
142 void initPatterns();
143 //! the file version
144 int m_version;
145 //! the patterns list
146 std::vector<MWAWGraphicStyle::Pattern> m_patternList;
147 //! the shape list
148 std::vector<Shape> m_shapeList;
149 };
150
initPatterns()151 void State::initPatterns()
152 {
153 if (!m_patternList.empty()) return;
154 for (int i=0; i<35; ++i) {
155 static uint16_t const patterns0[] = {
156 0x0000,0x0000,0x0000,0x0000, 0xffff,0xffff,0xffff,0xffff,
157 0xbbee,0xbbee,0xbbee,0xbbee, 0x55aa,0x55aa,0x55aa,0x55aa,
158 0x8822,0x8822,0x8822,0x8822, 0x8800,0x2200,0x8800,0x2200,
159 0x8000,0x0800,0x8000,0x0800, 0x0800,0x0000,0x8000,0x0000,
160 0x8080,0x413e,0x0808,0x14e3, 0x081c,0x2241,0x8001,0x0204,
161 0xff80,0x8080,0xff08,0x0808, 0x0180,0x4020,0x1008,0x0402,
162 0x81c0,0x6030,0x180c,0x0603, 0x1188,0x4400,0x1188,0x4400,
163 0x1188,0x4422,0x1188,0x4422, 0x3399,0xcc66,0x3399,0xcc66,
164 0x0180,0x4000,0x0204,0x0800, 0x6600,0x0000,0x9900,0x0000,
165 0xff00,0x0000,0xff00,0x0000, 0x5020,0x2020,0x5088,0x2788,
166 0x849f,0x8080,0x0404,0xe784, 0x0101,0x01ff,0x0101,0x01ff,
167 0x5588,0x5522,0x5588,0x5522, 0x8001,0x0204,0x0810,0x2040,
168 0xc081,0x0306,0x0c18,0x3060, 0x8811,0x2200,0x8811,0x2200,
169 0x8811,0x2244,0x8811,0x2244, 0xcc99,0x3366,0xcc99,0x3366,
170 0x2050,0x0000,0x0205,0x0000, 0x0808,0x0808,0x0808,0x0808,
171 0x0404,0x4040,0x0404,0x4040, 0x0384,0x4830,0x0c02,0x0101,
172 0x0a11,0xa040,0x00b1,0x4a4a, 0x4040,0x40ff,0x4040,0x4040,
173 0x4122,0x1408,0x1422,0x4180
174 };
175 static uint16_t const patterns1[] = {
176 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff,
177 0x77dd, 0x77dd, 0x77dd, 0x77dd, 0xaa55, 0xaa55, 0xaa55, 0xaa55,
178 0x8822, 0x8822, 0x8822, 0x8822, 0x8800, 0x2200, 0x8800, 0x2200,
179 0x8000, 0x0800, 0x8000, 0x0800, 0x8000, 0x0000, 0x0800, 0x0000,
180 0x8080, 0x413e, 0x0808, 0x14e3, 0xff80, 0x8080, 0xff08, 0x0808,
181 0x8142, 0x2418, 0x8142, 0x2418, 0x8040, 0x2010, 0x0804, 0x0201,
182 0xe070, 0x381c, 0x0e07, 0x83c1, 0x77bb, 0xddee, 0x77bb, 0xddee,
183 0x8844, 0x2211, 0x8844, 0x2211, 0x99cc, 0x6633, 0x99cc, 0x6633,
184 0x2040, 0x8000, 0x0804, 0x0200, 0xff00, 0xff00, 0xff00, 0xff00,
185 0xff00, 0x0000, 0xff00, 0x0000, 0xcc00, 0x0000, 0x3300, 0x0000,
186 0xf0f0, 0xf0f0, 0x0f0f, 0x0f0f, 0xff88, 0x8888, 0xff88, 0x8888,
187 0xaa44, 0xaa11, 0xaa44, 0xaa11, 0x0102, 0x0408, 0x1020, 0x4080,
188 0x8307, 0x0e1c, 0x3870, 0xe0c1, 0xeedd, 0xbb77, 0xeedd, 0xbb77,
189 0x1122, 0x4488, 0x1122, 0x4488, 0x3366, 0xcc99, 0x3366, 0xcc99,
190 0x40a0, 0x0000, 0x040a, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa,
191 0x8888, 0x8888, 0x8888, 0x8888, 0x0101, 0x1010, 0x0101, 0x1010,
192 0x0008, 0x142a, 0x552a, 0x1408, 0xff80, 0x8080, 0x8080, 0x8080,
193 0x8244, 0x2810, 0x2844, 0x8201
194 };
195 MWAWGraphicStyle::Pattern pat;
196 pat.m_dim=MWAWVec2i(8,8);
197 pat.m_data.resize(8);
198 pat.m_colors[0]=MWAWColor::white();
199 pat.m_colors[1]=MWAWColor::black();
200
201 uint16_t const *patPtr=m_version==0 ? &patterns0[4*i] : &patterns1[4*i];
202 for (size_t j=0; j<8; j+=2, ++patPtr) {
203 pat.m_data[j]=uint8_t((*patPtr)>>8);
204 pat.m_data[j+1]=uint8_t((*patPtr)&0xFF);
205 }
206 if (i==0) m_patternList.push_back(pat); // none pattern
207 m_patternList.push_back(pat);
208 }
209 }
210
211 ////////////////////////////////////////
212 //! Internal: the subdocument of a MacDrawParser
213 class SubDocument final : public MWAWSubDocument
214 {
215 public:
SubDocument(MacDrawParser & pars,MWAWInputStreamPtr const & input,int zoneId)216 SubDocument(MacDrawParser &pars, MWAWInputStreamPtr const &input, int zoneId)
217 : MWAWSubDocument(&pars, input, MWAWEntry())
218 , m_id(zoneId)
219 {
220 }
221
222 //! destructor
~SubDocument()223 ~SubDocument() final {}
224
225 //! operator!=
operator !=(MWAWSubDocument const & doc) const226 bool operator!=(MWAWSubDocument const &doc) const final
227 {
228 if (MWAWSubDocument::operator!=(doc)) return true;
229 auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
230 if (!sDoc) return true;
231 if (m_id != sDoc->m_id) return true;
232 return false;
233 }
234
235 //! the parser function
236 void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
237
238 protected:
239 //! the subdocument id
240 int m_id;
241 private:
242 SubDocument(SubDocument const &orig) = delete;
243 SubDocument &operator=(SubDocument const &orig) = delete;
244 };
245
parse(MWAWListenerPtr & listener,libmwaw::SubDocumentType)246 void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType)
247 {
248 if (!listener || !listener->canWriteText()) {
249 MWAW_DEBUG_MSG(("MacDrawParserInternal::SubDocument::parse: no listener\n"));
250 return;
251 }
252 auto *parser=dynamic_cast<MacDrawParser *>(m_parser);
253 if (!parser) {
254 MWAW_DEBUG_MSG(("MacDrawParserInternal::SubDocument::parse: no parser\n"));
255 return;
256 }
257 long pos = m_input->tell();
258 parser->sendText(m_id);
259 m_input->seek(pos, librevenge::RVNG_SEEK_SET);
260 }
261
262 }
263
264 ////////////////////////////////////////////////////////////
265 // constructor/destructor, ...
266 ////////////////////////////////////////////////////////////
MacDrawParser(MWAWInputStreamPtr const & input,MWAWRSRCParserPtr const & rsrcParser,MWAWHeader * header)267 MacDrawParser::MacDrawParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header)
268 : MWAWGraphicParser(input, rsrcParser, header)
269 , m_state()
270 {
271 init();
272 }
273
~MacDrawParser()274 MacDrawParser::~MacDrawParser()
275 {
276 }
277
init()278 void MacDrawParser::init()
279 {
280 resetGraphicListener();
281 setAsciiName("main-1");
282
283 m_state.reset(new MacDrawParserInternal::State);
284
285 getPageSpan().setMargins(0.1);
286 }
287
288 ////////////////////////////////////////////////////////////
289 // the parser
290 ////////////////////////////////////////////////////////////
parse(librevenge::RVNGDrawingInterface * docInterface)291 void MacDrawParser::parse(librevenge::RVNGDrawingInterface *docInterface)
292 {
293 if (!getInput().get() || !checkHeader(nullptr)) throw(libmwaw::ParseException());
294 bool ok = false;
295 try {
296 // create the asciiFile
297 ascii().setStream(getInput());
298 ascii().open(asciiName());
299 checkHeader(nullptr);
300 ok = createZones();
301 if (ok) {
302 createDocument(docInterface);
303 // reimplementme, ie. if the link chain is breaked, we will loose some shape
304 for (size_t i=0; i<m_state->m_shapeList.size(); ++i) {
305 MacDrawParserInternal::Shape const &shape=m_state->m_shapeList[i];
306 if (shape.m_isSent) continue;
307 send(shape);
308 if (shape.m_nextId>0 && shape.m_nextId>int(i))
309 i=size_t(shape.m_nextId-1);
310 }
311 }
312 ascii().reset();
313 }
314 catch (...) {
315 MWAW_DEBUG_MSG(("MacDrawParser::parse: exception catched when parsing\n"));
316 ok = false;
317 }
318
319 resetGraphicListener();
320 if (!ok) throw(libmwaw::ParseException());
321 }
322
323 ////////////////////////////////////////////////////////////
324 // create the document
325 ////////////////////////////////////////////////////////////
createDocument(librevenge::RVNGDrawingInterface * documentInterface)326 void MacDrawParser::createDocument(librevenge::RVNGDrawingInterface *documentInterface)
327 {
328 if (!documentInterface) return;
329 if (getGraphicListener()) {
330 MWAW_DEBUG_MSG(("MacDrawParser::createDocument: listener already exist\n"));
331 return;
332 }
333
334 // create the page list
335 MWAWPageSpan ps(getPageSpan());
336 ps.setPageSpan(1);
337 std::vector<MWAWPageSpan> pageList(1,ps);
338 MWAWGraphicListenerPtr listen(new MWAWGraphicListener(*getParserState(), pageList, documentInterface));
339 setGraphicListener(listen);
340 listen->startDocument();
341 }
342
343 ////////////////////////////////////////////////////////////
344 //
345 // Intermediate level
346 //
347 ////////////////////////////////////////////////////////////
createZones()348 bool MacDrawParser::createZones()
349 {
350 MWAWInputStreamPtr input = getInput();
351 readPrefs();
352 input->seek(512,librevenge::RVNG_SEEK_SET);
353 long pos=input->tell();
354 while (!input->isEnd()) {
355 if (readObject()<0)
356 break;
357 pos=input->tell();
358 }
359 input->seek(pos, librevenge::RVNG_SEEK_SET);
360
361 if (!input->isEnd()) {
362 pos=input->tell();
363 MWAW_DEBUG_MSG(("MacDrawParser::createZones: find extra data\n"));
364 ascii().addPos(pos);
365 ascii().addNote("Entries(Data):##");
366 }
367 return !m_state->m_shapeList.empty();
368 }
369
readObject()370 int MacDrawParser::readObject()
371 {
372 MWAWInputStreamPtr input = getInput();
373 if (input->isEnd()) return -1;
374 long pos=input->tell();
375 libmwaw::DebugStream f;
376 f << "Entries(Object):";
377
378 if (!input->checkPosition(pos+4+4)) {
379 MWAW_DEBUG_MSG(("MacDrawParser::readObject: the zone seems to small\n"));
380 f << "###";
381 ascii().addPos(pos);
382 ascii().addNote(f.str().c_str());
383 return -1;
384 }
385 size_t shapeId= m_state->m_shapeList.size();
386 m_state->m_shapeList.push_back(MacDrawParserInternal::Shape());
387 auto &shape=m_state->m_shapeList.back();
388 shape.m_id=int(shapeId);
389 shape.m_nextId=shape.m_id+1; // default value
390 auto type=static_cast<int>(input->readULong(1));
391 switch (type) {
392 case 0:
393 shape.m_type=MacDrawParserInternal::Shape::GroupEnd;
394 f << "end[group],";
395 break;
396 case 1:
397 shape.m_type=MacDrawParserInternal::Shape::Text;
398 f << "text,";
399 break;
400 case 2:
401 shape.m_type=MacDrawParserInternal::Shape::Basic;
402 shape.m_shape.m_type=MWAWGraphicShape::Line;
403 f << "line[axis],";
404 break;
405 case 3:
406 shape.m_type=MacDrawParserInternal::Shape::Basic;
407 shape.m_shape.m_type=MWAWGraphicShape::Line;
408 f << "line,";
409 break;
410 case 4:
411 shape.m_type=MacDrawParserInternal::Shape::Basic;
412 shape.m_shape.m_type=MWAWGraphicShape::Rectangle;
413 f << "rect,";
414 break;
415 case 5:
416 shape.m_type=MacDrawParserInternal::Shape::Basic;
417 shape.m_shape.m_type=MWAWGraphicShape::Rectangle;
418 f << "roundrect,";
419 break;
420 case 6:
421 shape.m_type=MacDrawParserInternal::Shape::Basic;
422 shape.m_shape.m_type=MWAWGraphicShape::Circle;
423 f << "circle,";
424 break;
425 case 7:
426 shape.m_type=MacDrawParserInternal::Shape::Basic;
427 shape.m_shape.m_type=MWAWGraphicShape::Arc;
428 f << "arc,";
429 break;
430 case 8:
431 shape.m_type=MacDrawParserInternal::Shape::Basic;
432 shape.m_shape.m_type=MWAWGraphicShape::Polygon;
433 f << "poly[free],";
434 break;
435 case 9:
436 shape.m_type=MacDrawParserInternal::Shape::Basic;
437 shape.m_shape.m_type=MWAWGraphicShape::Polygon;
438 f << "poly,";
439 break;
440 case 10:
441 shape.m_type=MacDrawParserInternal::Shape::Group;
442 f << "begin[group],";
443 break;
444 case 11:
445 shape.m_type=MacDrawParserInternal::Shape::Bitmap;
446 f << "bitmap,";
447 break;
448 default:
449 MWAW_DEBUG_MSG(("MacDrawParser::readObject: find unknown object type %d\n", type));
450 f << "#type=" << type << ",";
451 ascii().addPos(pos);
452 ascii().addNote(f.str().c_str());
453 m_state->m_shapeList.pop_back();
454 return -1;
455 }
456 auto val=static_cast<int>(input->readULong(1));
457 if (val==1) f << "locked,";
458 else if (val) f << "#lock=" << val << ",";
459 val=static_cast<int>(input->readLong(2));
460 if (val) f << "f0=" << val << ",";
461
462 auto lineType=static_cast<int>(input->readULong(1));
463 if (lineType>=1 && lineType<6) {
464 static float const widths[] = { 0, 1, 2, 3.5f, 5 };
465 shape.m_style.m_lineWidth=widths[lineType-1];
466 if (lineType!=2) // default
467 f << "line[width]=" << widths[lineType-1] << ",";
468 }
469 else {
470 MWAW_DEBUG_MSG(("MacDrawParser::readObject: find unexpected line type\n"));
471 f << "#line[width]=" << lineType << ",";
472 }
473 auto linePat=static_cast<int>(input->readULong(1));
474 if (linePat>=1&&linePat<37) {
475 if (linePat==1)
476 shape.m_style.m_lineWidth=0; // no pattern
477 else {
478 MWAWGraphicStyle::Pattern pat;
479 if (m_state->getPattern(linePat, pat))
480 pat.getAverageColor(shape.m_style.m_lineColor);
481 else
482 f << "###";
483 }
484 f << "line[pat]=" << linePat << ",";
485 }
486 else {
487 MWAW_DEBUG_MSG(("MacDrawParser::readObject: find unexpected line pattern\n"));
488 f << "#line[pat]=" << linePat << ",";
489 }
490 auto surfPat=static_cast<int>(input->readULong(1));
491 if (surfPat>=1&&surfPat<37) {
492 if (surfPat!=1) {
493 f << "surf[pat]=" << surfPat << ",";
494 MWAWGraphicStyle::Pattern pat;
495 if (m_state->getPattern(surfPat, pat)) {
496 MWAWColor col;
497 if (pat.getUniqueColor(col))
498 shape.m_style.setSurfaceColor(col);
499 else
500 shape.m_style.setPattern(pat);
501 }
502 else
503 f << "###surf[pat],";
504 }
505 }
506 else {
507 MWAW_DEBUG_MSG(("MacDrawParser::readObject: find unexpected surface pattern\n"));
508 f << "#surf[pat]=" << surfPat << ",";
509 }
510 val=static_cast<int>(input->readULong(1));
511 float cornerWidth=0;
512 if (type==2 || type==3) {
513 if (val&2) {
514 shape.m_style.m_arrows[0]=MWAWGraphicStyle::Arrow::plain();
515 f << "arrow[beg],";
516 }
517 if (val&1) {
518 shape.m_style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain();
519 f << "arrow[end],";
520 }
521 val &= 0xFC;
522 }
523 else if (type==4 || type==5) {
524 if (val>=1 && val <= 5) {
525 cornerWidth=float(val+1)*4.5f;
526 f << "corner[length]=" << cornerWidth << ",";
527 val=0;
528 }
529 else if (val) {
530 MWAW_DEBUG_MSG(("MacDrawParser::readObject: find unknown corner values\n"));
531 f << "###";
532 }
533 }
534 if (val) f << "#flags=" << std::hex << val << std::dec << ",";
535 bool ok=true;
536 long actPos=input->tell();
537 switch (type) {
538 case 0:
539 break;
540 case 1: {
541 if (!input->checkPosition(actPos+20)) {
542 MWAW_DEBUG_MSG(("MacDrawParser::readObject: the zone length seems bad\n"));
543 f << "###";
544 ok=false;
545 break;
546 }
547 auto id=long(input->readULong(4));
548 if (id) f << "id=" << std::hex << id << std::dec << ",";
549
550 MWAWFont &font=shape.m_font;
551 auto flag = static_cast<int>(input->readULong(1));
552 uint32_t flags=0;
553 if (flag&0x1) flags |= MWAWFont::boldBit;
554 if (flag&0x2) flags |= MWAWFont::italicBit;
555 if (flag&0x4) font.setUnderlineStyle(MWAWFont::Line::Simple);
556 if (flag&0x8) flags |= MWAWFont::embossBit;
557 if (flag&0x10) flags |= MWAWFont::shadowBit;
558 if (flag&0x20) font.setDeltaLetterSpacing(-1);
559 if (flag&0x40) font.setDeltaLetterSpacing(1);
560 if (flag&0x80) f << "#flag0[0x80],";
561 font.setFlags(flags);
562 font.setId(static_cast<int>(input->readULong(1)));
563 auto fSz=static_cast<int>(input->readULong(1));
564 if (fSz>=1 && fSz<9) {
565 static int const fontSize[]= {9,10,12,14,18,24,36,48};
566 font.setSize(float(fontSize[fSz-1]));
567 }
568 else {
569 MWAW_DEBUG_MSG(("MacDrawParser::readObject: find unknown font size\n"));
570 f << "#sz=" << fSz << ",";
571 }
572 f << "font=[" << font.getDebugString(getParserState()->m_fontConverter) << "],";
573 val=static_cast<int>(input->readULong(1));
574 switch (val) {
575 case 1:
576 break;
577 case 2:
578 shape.m_paragraph.setInterline(1.5, librevenge::RVNG_PERCENT);
579 f << "interline=150%,";
580 break;
581 case 3:
582 shape.m_paragraph.setInterline(2, librevenge::RVNG_PERCENT);
583 f << "interline=200%,";
584 break;
585 default:
586 MWAW_DEBUG_MSG(("MacDrawParser::readObject: find unknown interline\n"));
587 f << "#interline=" << val << ",";
588 }
589 val=static_cast<int>(input->readULong(1));
590 switch (val) {
591 case 1:
592 break;
593 case 2:
594 shape.m_paragraph.m_justify = MWAWParagraph::JustificationCenter;
595 f << "align=center,";
596 break;
597 case 3:
598 shape.m_paragraph.m_justify = MWAWParagraph::JustificationRight;
599 f << "align=right,";
600 break;
601 default:
602 MWAW_DEBUG_MSG(("MacDrawParser::readObject: find unknown align\n"));
603 f << "#align=" << val << ",";
604 }
605 val=static_cast<int>(input->readULong(1));
606 if (val&3) {
607 int rotation=90*(val&3);
608 if (val&4) {
609 if (rotation==90) rotation=180;
610 else if (rotation==180) rotation=90;
611 }
612 shape.m_style.m_rotate=float(rotation);
613 f << "rot=" << rotation << ",";
614 }
615 if (val&4) {
616 shape.m_style.m_flip[0]=true;
617 f << "sym,";
618 }
619 if (val&0xF8) f << "#rot=" << std::hex << (val&0xF8) << std::dec << ",";
620 auto N=static_cast<int>(input->readULong(2));
621 if (!input->checkPosition(actPos+20+N)) {
622 MWAW_DEBUG_MSG(("MacDrawParser::readObject: the number of character seems bad\n"));
623 f << "##N=" << N << ",";
624 ok=false;
625 break;
626 }
627 float dim[4];
628 for (auto &d : dim) d=float(input->readLong(2));
629 shape.m_box=MWAWBox2f(MWAWVec2f(dim[1],dim[0]), MWAWVec2f(dim[3],dim[2]));
630 shape.m_textEntry.setBegin(input->tell());
631 shape.m_textEntry.setLength(N);
632 shape.m_style.m_lineWidth=0; // no border for textbox
633 f << shape.m_box << ",";
634 input->seek(actPos+20+N, librevenge::RVNG_SEEK_SET);
635 break;
636 }
637 case 2:
638 case 3:
639 case 4:
640 case 5:
641 case 6:
642 case 7: {
643 if (!input->checkPosition(actPos+16+(type==7 ? 4 : 0))) {
644 MWAW_DEBUG_MSG(("MacDrawParser::readObject: the zone length seems bad\n"));
645 f << "###";
646 ok=false;
647 break;
648 }
649 float dim[4];
650 for (auto &d : dim) d=float(input->readLong(4))/65536.f;
651 MWAWBox2f box(MWAWVec2f(dim[1],dim[0]), MWAWVec2f(dim[3],dim[2]));
652 f << box << ",";
653 shape.m_box=box;
654 switch (type) {
655 case 2:
656 case 3:
657 shape.m_shape=MWAWGraphicShape::line(box[0], box[1]);
658 break;
659 case 4:
660 case 5:
661 shape.m_shape=MWAWGraphicShape::rectangle(box, MWAWVec2f(cornerWidth,cornerWidth));
662 break;
663 case 6:
664 shape.m_shape=MWAWGraphicShape::circle(box);
665 break;
666 case 7: {
667 int fileAngle[2];
668 for (auto &angle : fileAngle) angle=static_cast<int>(input->readLong(2));
669 f << "angle=" << fileAngle[0] << "x" << fileAngle[0]+fileAngle[1] << ",";
670
671 if (fileAngle[1]<0) {
672 fileAngle[0]+=fileAngle[1];
673 fileAngle[1]*=-1;
674 }
675 int angle[2] = { 90-fileAngle[0]-fileAngle[1], 90-fileAngle[0] };
676 if (angle[1]>360) {
677 int numLoop=int(angle[1]/360)-1;
678 angle[0]-=numLoop*360;
679 angle[1]-=numLoop*360;
680 while (angle[1] > 360) {
681 angle[0]-=360;
682 angle[1]-=360;
683 }
684 }
685 if (angle[0] < -360) {
686 int numLoop=int(angle[0]/360)+1;
687 angle[0]-=numLoop*360;
688 angle[1]-=numLoop*360;
689 while (angle[0] < -360) {
690 angle[0]+=360;
691 angle[1]+=360;
692 }
693 }
694
695 MWAWVec2f axis = 0.5f*MWAWVec2f(box.size());
696 // we must compute the real bd box
697 float minVal[2] = { 0, 0 }, maxVal[2] = { 0, 0 };
698 int limitAngle[2];
699 for (int i = 0; i < 2; i++)
700 limitAngle[i] = (angle[i] < 0) ? int(angle[i]/90)-1 : int(angle[i]/90);
701 for (int bord = limitAngle[0]; bord <= limitAngle[1]+1; bord++) {
702 float ang = (bord == limitAngle[0]) ? float(angle[0]) :
703 (bord == limitAngle[1]+1) ? float(angle[1]) : float(90 * bord);
704 ang *= float(M_PI/180.);
705 float actVal[2] = { axis[0] *std::cos(ang), -axis[1] *std::sin(ang)};
706 if (actVal[0] < minVal[0]) minVal[0] = actVal[0];
707 else if (actVal[0] > maxVal[0]) maxVal[0] = actVal[0];
708 if (actVal[1] < minVal[1]) minVal[1] = actVal[1];
709 else if (actVal[1] > maxVal[1]) maxVal[1] = actVal[1];
710 }
711 MWAWVec2f center = box.center();
712 MWAWBox2f realBox(MWAWVec2f(center[0]+minVal[0],center[1]+minVal[1]),
713 MWAWVec2f(center[0]+maxVal[0],center[1]+maxVal[1]));
714 shape.m_box=MWAWBox2f(MWAWVec2f(shape.m_box[0])+realBox[0],MWAWVec2f(shape.m_box[0])+realBox[1]);
715 if (shape.m_style.hasSurface())
716 shape.m_shape = MWAWGraphicShape::pie(realBox, box, MWAWVec2f(float(angle[0]),float(angle[1])));
717 else
718 shape.m_shape = MWAWGraphicShape::arc(realBox, box, MWAWVec2f(float(angle[0]),float(angle[1])));
719 break;
720 }
721 default:
722 break;
723 }
724 break;
725 }
726 case 8:
727 case 9: {
728 auto dSz=long(input->readULong(4));
729 if (dSz<18||!input->checkPosition(actPos+4+dSz)) {
730 MWAW_DEBUG_MSG(("MacDrawParser::readObject: the polygon data size seems bad\n"));
731 f << "###";
732 ok=false;
733 break;
734 }
735 auto N=static_cast<int>(input->readULong(2));
736 f << "N=" << N << ",";
737 float dim[4];
738 for (auto &d : dim) d=float(input->readLong(4))/65536.f;
739 MWAWBox2f box(MWAWVec2f(dim[1],dim[0]), MWAWVec2f(dim[3],dim[2]));
740 f << box << ",";
741 shape.m_shape.m_type = MWAWGraphicShape::Polygon;
742 shape.m_shape.m_bdBox= shape.m_box=box;
743 int coordSz=type==8 ? 1 : 4;
744 if (2+16+(type==8 ? 6 : 0)+2*N*coordSz>dSz) {
745 MWAW_DEBUG_MSG(("MacDrawParser::readObject: the number of points seems bad\n"));
746 f << "###";
747 ok=false;
748 break;
749 }
750 val=static_cast<int>(input->readLong(2)); // find a copy of the type here
751 if (val!=type) f << "g0=" << val << ",";
752 std::vector<MWAWVec2f> &vertices=shape.m_shape.m_vertices;
753 if (type==8) {
754 for (int i=0; i<2; ++i) dim[i]=float(input->readLong(4))/65536.f;
755 MWAWVec2f point(dim[1],dim[0]);
756 vertices.push_back(point);
757 f << "orig=" << point << ",";
758 f << "delta=[";
759 for (int i=0; i<N-1; ++i) {
760 int delta[2];
761 for (auto &d : delta) d=static_cast<int>(input->readLong(1));
762 MWAWVec2f deltaPt(static_cast<float>(delta[0]), static_cast<float>(delta[1]));
763 point+=deltaPt;
764 vertices.push_back(point);
765 f << deltaPt << ",";
766 }
767 f << "],";
768 }
769 else {
770 f << "pts=[";
771 for (int i=0; i<N; ++i) {
772 float coord[2];
773 for (auto &c : coord) c=float(input->readLong(4))/65536.f;
774 MWAWVec2f point(coord[1], coord[0]);
775 f << point << ",";
776 vertices.push_back(point);
777 }
778 f << "],";
779 }
780 input->seek(actPos+4+dSz, librevenge::RVNG_SEEK_SET);
781 break;
782 }
783 case 10: {
784 if (!input->checkPosition(actPos+32)) {
785 MWAW_DEBUG_MSG(("MacDrawParser::readObject: the zone length seems bad\n"));
786 f << "###";
787 ok=false;
788 break;
789 }
790 int const vers=version();
791 if (vers==1) {
792 float dim[4];
793 for (auto &d : dim) d=float(input->readLong(4))/65536.f;
794 MWAWBox2f box(MWAWVec2f(dim[1],dim[0]), MWAWVec2f(dim[3],dim[2]));
795 f << box << ",";
796 shape.m_box=box;
797 }
798 auto N=static_cast<int>(input->readULong(2));
799 f << "N=" << N << ",";
800 val=static_cast<int>(input->readLong(2));
801 if (val!=N) f << "N[child]=" << val << ",";
802 long dSz=static_cast<int>(input->readULong(4)); // related to size (but can be only an approximation)
803 f << "groupSize=" << std::hex << dSz << std::dec << ",";
804 if (vers==0) {
805 float dim[4];
806 for (auto &d : dim) d=float(input->readLong(4))/65536.f;
807 MWAWBox2f box(MWAWVec2f(dim[1],dim[0]), MWAWVec2f(dim[3],dim[2]));
808 f << box << ",";
809 shape.m_box=box;
810 }
811 for (int i=0; i<2; ++i) {
812 val=static_cast<int>(input->readULong(4));
813 if (val) f << "id" << i << "=" << std::hex << val << std::dec << ",";
814 }
815 ascii().addPos(pos);
816 ascii().addNote(f.str().c_str());
817 for (int i=0; i<N; ++i) {
818 int cId=readObject();
819 if (cId<0) {
820 MWAW_DEBUG_MSG(("MacDrawParser::readObject: can not find a child\n"));
821 return int(shapeId);
822 }
823 // do not use shape's childList as the vector can have grown
824 m_state->m_shapeList[shapeId].m_childList.push_back(size_t(cId));
825 }
826 int cId=readObject(); // read end group
827 auto nextId=int(m_state->m_shapeList.size());
828 if (cId<0) {
829 m_state->m_shapeList[shapeId].m_nextId=nextId;
830 return int(shapeId);
831 }
832 m_state->m_shapeList[shapeId].m_nextId=nextId-1;
833 if (m_state->m_shapeList[size_t(cId)].m_type!=MacDrawParserInternal::Shape::GroupEnd) {
834 MWAW_DEBUG_MSG(("MacDrawParser::readObject: oops, can not find the end group data\n"));
835 ascii().addPos(pos);
836 ascii().addNote("###");
837 }
838 else
839 m_state->m_shapeList.pop_back();
840 return int(shapeId);
841 }
842 case 11: {
843 if (!input->checkPosition(actPos+42)) {
844 MWAW_DEBUG_MSG(("MacDrawParser::readObject: the zone length seems bad\n"));
845 f << "###";
846 ok=false;
847 break;
848 }
849 for (int i=0; i<2; ++i) { // maybe a dim
850 val=static_cast<int>(input->readULong(2));
851 if (val) f << "f0=" << val << ",";
852 }
853 int dim[4];
854 for (auto &d : dim) d=static_cast<int>(input->readLong(2));
855 MWAWBox2i &bitmapBox=shape.m_bitmapDim;
856 bitmapBox=MWAWBox2i(MWAWVec2i(dim[1],dim[0]), MWAWVec2i(dim[3],dim[2]));
857 f << "bitmap[dim]="<< bitmapBox << ",";
858 float fDim[4];
859 for (auto &d : fDim) d=float(input->readLong(4))/65536.f;
860 MWAWBox2f box(MWAWVec2f(fDim[1],fDim[0]), MWAWVec2f(fDim[3],fDim[2]));
861 f << box << ",";
862 shape.m_box=box;
863
864 val=static_cast<int>(input->readULong(4)); // find 8063989c maybe type + id
865 if (val) f << "id=" << std::hex << val << std::dec << ",";
866 shape.m_numBytesByRow=static_cast<int>(input->readULong(2));
867
868 for (auto &d : dim) d=static_cast<int>(input->readLong(2));
869 MWAWBox2i &fileBox=shape.m_bitmapFileDim;
870 fileBox=MWAWBox2i(MWAWVec2i(dim[1],dim[0]), MWAWVec2i(dim[3],dim[2]));
871 f << "bitmap[dimInFile]="<< fileBox << ",";
872 shape.m_bitmapEntry.setBegin(input->tell());
873 shape.m_bitmapEntry.setLength(long(fileBox.size()[1])*shape.m_numBytesByRow);
874 if (fileBox.size()[1]<0 || shape.m_numBytesByRow<0 || !input->checkPosition(shape.m_bitmapEntry.end())) {
875 MWAW_DEBUG_MSG(("MacDrawParser::readObject: can not compute the bitmap endPos\n"));
876 f << "###";
877 ok=false;
878 break;
879 }
880 ascii().skipZone(shape.m_bitmapEntry.begin(), shape.m_bitmapEntry.end()-1);
881 if (shape.m_numBytesByRow*8 < fileBox.size()[0] ||
882 fileBox[0][0]>bitmapBox[0][0] || fileBox[0][1]>bitmapBox[0][1] ||
883 fileBox[1][0]<bitmapBox[1][0] || fileBox[1][1]<bitmapBox[1][1]) {
884 MWAW_DEBUG_MSG(("MacDrawParser::readObject: something look bad when reading a bitmap header\n"));
885 f << "###";
886 shape.m_bitmapEntry=MWAWEntry();
887 ok=false;
888 break;
889 }
890 if (shape.m_bitmapEntry.valid())
891 input->seek(shape.m_bitmapEntry.end(), librevenge::RVNG_SEEK_SET);
892 break;
893 }
894 default:
895 ok=false;
896 break;
897 }
898 ascii().addPos(pos);
899 ascii().addNote(f.str().c_str());
900 return ok ? int(shapeId) : -1;
901 }
902
903 ////////////////////////////////////////////////////////////
904 // read the header
905 ////////////////////////////////////////////////////////////
checkHeader(MWAWHeader * header,bool strict)906 bool MacDrawParser::checkHeader(MWAWHeader *header, bool strict)
907 {
908 *m_state = MacDrawParserInternal::State();
909 MWAWInputStreamPtr input = getInput();
910 if (!input || !input->hasDataFork() || !input->checkPosition(512))
911 return false;
912
913 libmwaw::DebugStream f;
914 f << "FileHeader:";
915 input->seek(0, librevenge::RVNG_SEEK_SET);
916 auto val=static_cast<int>(input->readULong(2));
917 int vers=0;
918 if (val==0x4452) {
919 if (input->readULong(2)!=0x5747) return false;
920 val=static_cast<int>(input->readULong(2));
921 if (val==0x4d44) vers=1;
922 else {
923 MWAW_DEBUG_MSG(("MacDrawParser::checkHeader: find unexpected header\n"));
924 return false;
925 }
926 f << "version=" << vers << ",";
927 f << "subVersion=" << input->readLong(2) << ",";
928 }
929 else if (val==0x4d44) {
930 vers=0;
931 val=static_cast<int>(input->readLong(2)); // find 4 for v0.9
932 if (val!=4) f << "f0=" << val << ",";
933 for (int i=0; i<2; ++i) { // always 0?
934 val=static_cast<int>(input->readLong(2));
935 if (val) f << "f" << i+1 << "=" << val << ",";
936 }
937 }
938 else
939 return false;
940 ascii().addPos(0);
941 ascii().addNote(f.str().c_str());
942
943 if (strict && !readPrintInfo()) {
944 input->seek(8, librevenge::RVNG_SEEK_SET);
945 for (int i=0; i<10; ++i) // allow print info to be zero
946 if (input->readLong(2)) return false;
947 }
948
949 if (strict && vers >= 1) {
950 // we must check that this is not a basic pict file
951 input->seek(512+2, librevenge::RVNG_SEEK_SET);
952 int dim[4];
953 for (auto &d : dim) d=static_cast<int>(input->readLong(2));
954 val=static_cast<int>(input->readLong(2));
955 if (dim[0]<dim[2] && dim[1]<dim[3] && (val==0x1101 || (val==0x11 && input->readLong(2)==0x2ff))) {
956 // posible
957 input->seek(512, librevenge::RVNG_SEEK_SET);
958 MWAWBox2f box;
959 if (MWAWPictData::check(input, static_cast<int>(input->size()-512), box) != MWAWPict::MWAW_R_BAD)
960 return false;
961 }
962 }
963 if (strict) {
964 // check also the beginning list of shape
965 input->seek(512, librevenge::RVNG_SEEK_SET);
966 for (int i=0; i<3; ++i) {
967 if (input->isEnd()) break;
968 if (readObject()<0) {
969 MWAW_DEBUG_MSG(("MacDrawParser::checkHeader: problem reading some shape\n"));
970 return false;
971 }
972 }
973 m_state.reset(new MacDrawParserInternal::State());
974 }
975 setVersion(vers);
976 m_state->m_version=vers;
977 if (header)
978 header->reset(MWAWDocument::MWAW_T_MACDRAW, vers, MWAWDocument::MWAW_K_DRAW);
979 input->seek(512,librevenge::RVNG_SEEK_SET);
980
981 return true;
982 }
983
984 ////////////////////////////////////////////////////////////
985 // try to read the prefs zone
986 ////////////////////////////////////////////////////////////
readPrefs()987 bool MacDrawParser::readPrefs()
988 {
989 MWAWInputStreamPtr input = getInput();
990 if (!input->checkPosition(512)) {
991 MWAW_DEBUG_MSG(("MacDrawParser::readPrefs: the prefs zone seems too short\n"));
992 ascii().addPos(14);
993 ascii().addNote("Entries(Prefs):#");
994 return false;
995 }
996 input->seek(8,librevenge::RVNG_SEEK_SET);
997 if (!readPrintInfo()) {
998 ascii().addPos(8);
999 ascii().addNote("Entries(PrintInfo):#");
1000 }
1001 input->seek(8+120, librevenge::RVNG_SEEK_SET);
1002 // v2: cut in 128, 40, 3*40, remain
1003 long pos=input->tell();
1004 libmwaw::DebugStream f;
1005 f << "Entries(Prefs):";
1006 for (int i=0; i<9; ++i) { // f0=1|2|7, f1=0|75|78|7c, f2=0|48, f4=0|48, f5=0|48, f6=0|48, f7=0|48
1007 auto val=static_cast<int>(input->readLong(2));
1008 if (val) f << "f" << i << "=" << val << ",";
1009 }
1010 ascii().addDelimiter(input->tell(),'|');
1011 ascii().addPos(pos);
1012 ascii().addNote(f.str().c_str());
1013
1014 input->seek(0x100, librevenge::RVNG_SEEK_SET);
1015 pos=input->tell();
1016 input->seek(pos+40, librevenge::RVNG_SEEK_SET);
1017 ascii().addPos(pos);
1018 ascii().addNote("Prefs-A:");
1019 for (int i=0; i<5; ++i) {
1020 pos=input->tell();
1021 f.str("");
1022 f << "Prefs-B" << i << ":";
1023 input->seek(pos+40, librevenge::RVNG_SEEK_SET);
1024 ascii().addPos(pos);
1025 ascii().addNote(f.str().c_str());
1026 }
1027 pos=input->tell();
1028 ascii().addPos(pos);
1029 ascii().addNote("Prefs-end:");
1030
1031 input->seek(512, librevenge::RVNG_SEEK_SET);
1032 return true;
1033 }
1034
1035 ////////////////////////////////////////////////////////////
1036 // try to read the print info zone
1037 ////////////////////////////////////////////////////////////
readPrintInfo()1038 bool MacDrawParser::readPrintInfo()
1039 {
1040 MWAWInputStreamPtr input = getInput();
1041 long pos=input->tell();
1042 long endPos=pos+120;
1043 if (!input->checkPosition(endPos)) {
1044 MWAW_DEBUG_MSG(("MacDrawParser::readPrintInfo: file seems too short\n"));
1045 return false;
1046 }
1047 libmwaw::DebugStream f;
1048 f << "Entries(PrintInfo):";
1049 libmwaw::PrinterInfo info;
1050 if (!info.read(input)) {
1051 MWAW_DEBUG_MSG(("MacDrawParser::readPrintInfo: can not read print info\n"));
1052 return false;
1053 }
1054 f << info;
1055 MWAWVec2i paperSize = info.paper().size();
1056 MWAWVec2i pageSize = info.page().size();
1057 if (pageSize.x() <= 0 || pageSize.y() <= 0 ||
1058 paperSize.x() <= 0 || paperSize.y() <= 0) {
1059 ascii().addPos(pos);
1060 ascii().addNote(f.str().c_str());
1061 input->seek(endPos, librevenge::RVNG_SEEK_SET);
1062 return true;
1063 }
1064
1065 // define margin from print info
1066 MWAWVec2i lTopMargin= -1 * info.paper().pos(0);
1067 MWAWVec2i rBotMargin=info.paper().size() - info.page().size();
1068
1069 // move margin left | top
1070 int decalX = lTopMargin.x() > 14 ? lTopMargin.x()-14 : 0;
1071 int decalY = lTopMargin.y() > 14 ? lTopMargin.y()-14 : 0;
1072 lTopMargin -= MWAWVec2i(decalX, decalY);
1073 rBotMargin += MWAWVec2i(decalX, decalY);
1074
1075 // decrease right | bottom
1076 int rightMarg = rBotMargin.x() -50;
1077 if (rightMarg < 0) rightMarg=0;
1078 int botMarg = rBotMargin.y() -50;
1079 if (botMarg < 0) botMarg=0;
1080
1081 getPageSpan().setMarginTop(lTopMargin.y()/72.0);
1082 getPageSpan().setMarginBottom(botMarg/72.0);
1083 getPageSpan().setMarginLeft(lTopMargin.x()/72.0);
1084 getPageSpan().setMarginRight(rightMarg/72.0);
1085 getPageSpan().setFormLength(paperSize.y()/72.);
1086 getPageSpan().setFormWidth(paperSize.x()/72.);
1087
1088 ascii().addPos(pos);
1089 ascii().addNote(f.str().c_str());
1090 input->seek(endPos, librevenge::RVNG_SEEK_SET);
1091 return true;
1092 }
1093
1094 ////////////////////////////////////////////////////////////
1095 //
1096 // send data
1097 //
1098 ////////////////////////////////////////////////////////////
1099
send(MacDrawParserInternal::Shape const & shape)1100 bool MacDrawParser::send(MacDrawParserInternal::Shape const &shape)
1101 {
1102 MWAWGraphicListenerPtr listener=getGraphicListener();
1103 if (!listener) {
1104 MWAW_DEBUG_MSG(("MacDrawParser::send: can not find the listener\n"));
1105 return false;
1106 }
1107 shape.m_isSent=true;
1108 MWAWBox2f box=shape.getBdBox();
1109 MWAWPosition pos(box[0], box.size(), librevenge::RVNG_POINT);
1110 pos.m_anchorTo = MWAWPosition::Page;
1111 switch (shape.m_type) {
1112 case MacDrawParserInternal::Shape::Basic:
1113 listener->insertShape(pos, shape.m_shape, shape.m_style);
1114 break;
1115 case MacDrawParserInternal::Shape::Bitmap:
1116 return sendBitmap(shape, pos);
1117 case MacDrawParserInternal::Shape::Group: {
1118 size_t numShapes=m_state->m_shapeList.size();
1119 if (!numShapes) break;
1120 listener->openGroup(pos);
1121 for (auto id : shape.m_childList) {
1122 if (id>=numShapes) {
1123 MWAW_DEBUG_MSG(("MacDrawParser::send: can not find a child\n"));
1124 continue;
1125 }
1126 MacDrawParserInternal::Shape const &child=m_state->m_shapeList[id];
1127 if (child.m_isSent) {
1128 MWAW_DEBUG_MSG(("MacDrawParser::send: the child is already sent\n"));
1129 continue;
1130 }
1131 send(child);
1132 }
1133 listener->closeGroup();
1134 break;
1135 }
1136 case MacDrawParserInternal::Shape::GroupEnd:
1137 break;
1138 case MacDrawParserInternal::Shape::Text: {
1139 std::shared_ptr<MWAWSubDocument> doc(new MacDrawParserInternal::SubDocument(*this, getInput(), shape.m_id));
1140 listener->insertTextBox(pos, doc, shape.m_style);
1141 return true;
1142 }
1143 case MacDrawParserInternal::Shape::Unknown:
1144 #if !defined(__clang__)
1145 default:
1146 #endif
1147 return false;
1148 }
1149 return true;
1150 }
1151
sendBitmap(MacDrawParserInternal::Shape const & shape,MWAWPosition const & position)1152 bool MacDrawParser::sendBitmap(MacDrawParserInternal::Shape const &shape, MWAWPosition const &position)
1153 {
1154 MWAWGraphicListenerPtr listener=getGraphicListener();
1155 if (!listener) {
1156 MWAW_DEBUG_MSG(("MacDrawParser::sendBitmap: can not find the listener\n"));
1157 return false;
1158 }
1159 if (!shape.m_bitmapEntry.valid()) return false;
1160 int const numBytesByRow=shape.m_numBytesByRow;
1161 MWAWInputStreamPtr input=getInput();
1162 MWAWVec2i pictDim=shape.m_bitmapDim.size();
1163 if (shape.m_type!=MacDrawParserInternal::Shape::Bitmap || numBytesByRow<=0 ||
1164 pictDim[0]<0 || pictDim[1]<0 ||
1165 shape.m_bitmapEntry.length() > (input->size() - shape.m_bitmapEntry.begin()) ||
1166 shape.m_bitmapFileDim.size()[1]<shape.m_bitmapEntry.length() / numBytesByRow ||
1167 shape.m_bitmapDim[0][0]<0 || shape.m_bitmapDim[0][1]<0 ||
1168 shape.m_bitmapDim[0][0]<shape.m_bitmapFileDim[0][0] ||
1169 shape.m_bitmapFileDim.size()[0]<=0 || shape.m_bitmapFileDim.size()[1]<=0 ||
1170 8*numBytesByRow<shape.m_bitmapFileDim.size()[0]) {
1171 MWAW_DEBUG_MSG(("MacDrawParser::sendBitmap: the bitmap seems bad\n"));
1172 return false;
1173 }
1174 // change: implement indexed transparent color, replaced this code
1175 MWAWPictBitmapColor pict(pictDim, true);
1176 MWAWColor transparent(255,255,255,0);
1177 MWAWColor black(MWAWColor::black());
1178 std::vector<MWAWColor> data;
1179 data.resize(size_t(pictDim[0]), transparent);
1180 // first set unseen row to zero (even if this must not appear)
1181 for (int r=shape.m_bitmapDim[0][1]; r<shape.m_bitmapFileDim[0][1]; ++r) pict.setRow(r-shape.m_bitmapDim[0][1], &data[0]);
1182 for (int r=shape.m_bitmapFileDim[1][1]; r<shape.m_bitmapDim[1][1]; ++r) pict.setRow(r-shape.m_bitmapDim[0][1], &data[0]);
1183
1184 input->seek(shape.m_bitmapEntry.begin(), librevenge::RVNG_SEEK_SET);
1185 for (int r=shape.m_bitmapFileDim[0][1]; r<shape.m_bitmapFileDim[1][1] && !input->isEnd(); ++r) {
1186 long pos=input->tell();
1187 if (r<shape.m_bitmapDim[0][1]||r>=shape.m_bitmapDim[1][1]) { // must not appear, but...
1188 input->seek(pos+numBytesByRow, librevenge::RVNG_SEEK_SET);
1189 continue;
1190 }
1191 int wPos=shape.m_bitmapDim[0][0]-shape.m_bitmapFileDim[0][0];
1192 for (int col=shape.m_bitmapFileDim[0][0]; col<shape.m_bitmapFileDim[1][0]; ++col) {
1193 auto c=static_cast<unsigned char>(input->readULong(1));
1194 for (int j=0, bit=0x80; j<8 ; ++j, bit>>=1) {
1195 if (wPos>=pictDim[0]) break;
1196 data[size_t(wPos++)]=(c&bit) ? black : transparent;
1197 }
1198 }
1199 pict.setRow(r-shape.m_bitmapDim[0][1], &data[0]);
1200 input->seek(pos+numBytesByRow, librevenge::RVNG_SEEK_SET);
1201 }
1202
1203 MWAWEmbeddedObject picture;
1204 if (!pict.getBinary(picture)) return false;
1205 #ifdef DEBUG_WITH_FILES
1206 if (!picture.m_dataList.empty()) {
1207 static int volatile pictName = 0;
1208 libmwaw::DebugStream f;
1209 f << "PICT-" << ++pictName << ".bmp";
1210 libmwaw::Debug::dumpFile(picture.m_dataList[0], f.str().c_str());
1211 }
1212 #endif
1213
1214 listener->insertPicture(position, picture);
1215
1216 return true;
1217 }
1218
sendText(int zId)1219 bool MacDrawParser::sendText(int zId)
1220 {
1221 MWAWGraphicListenerPtr listener=getGraphicListener();
1222 if (!listener) {
1223 MWAW_DEBUG_MSG(("MacDrawParser::sendText: can not find the listener\n"));
1224 return false;
1225 }
1226 if (zId<0||zId>=static_cast<int>(m_state->m_shapeList.size()) ||
1227 m_state->m_shapeList[size_t(zId)].m_type != MacDrawParserInternal::Shape::Text) {
1228 MWAW_DEBUG_MSG(("MacDrawParser::sendText: can not find the text shape\n"));
1229 return false;
1230 }
1231 MacDrawParserInternal::Shape const &shape=m_state->m_shapeList[size_t(zId)];
1232 shape.m_isSent = true;
1233 if (!shape.m_textEntry.valid())
1234 return true;
1235
1236 listener->setParagraph(shape.m_paragraph);
1237 listener->setFont(shape.m_font);
1238
1239 MWAWInputStreamPtr input=getInput();
1240 input->seek(shape.m_textEntry.begin(), librevenge::RVNG_SEEK_SET);
1241 libmwaw::DebugStream f;
1242 f << "Object[text]:";
1243 long endPos=shape.m_textEntry.end();
1244 while (!input->isEnd()) {
1245 if (input->tell()>=shape.m_textEntry.end())
1246 break;
1247 auto c = char(input->readULong(1));
1248 if (c==0) {
1249 MWAW_DEBUG_MSG(("MacDrawParser::sendText: find char 0\n"));
1250 f << "#[0]";
1251 continue;
1252 }
1253 f << c;
1254 switch (c) {
1255 case 9:
1256 listener->insertTab();
1257 break;
1258 case 0xd:
1259 listener->insertEOL();
1260 break;
1261 default:
1262 listener->insertCharacter(static_cast<unsigned char>(c), input, endPos);
1263 break;
1264 }
1265 }
1266 ascii().addPos(shape.m_textEntry.begin());
1267 ascii().addNote(f.str().c_str());
1268 return true;
1269 }
1270 // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab:
1271