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