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 <map>
39 #include <sstream>
40 
41 #include <librevenge/librevenge.h>
42 
43 #include "MWAWTextListener.hxx"
44 #include "MWAWPictData.hxx"
45 #include "MWAWPosition.hxx"
46 #include "MWAWSubDocument.hxx"
47 
48 #include "FullWrtParser.hxx"
49 #include "FullWrtStruct.hxx"
50 
51 #include "FullWrtGraph.hxx"
52 
53 /** Internal: the structures of a FullWrtGraph */
54 namespace FullWrtGraphInternal
55 {
56 ////////////////////////////////////////
57 //! Internal: the sidebar of a FullWrtGraph
58 struct SideBar final : public FullWrtStruct::ZoneHeader {
59   //! constructor
SideBarFullWrtGraphInternal::SideBar60   explicit SideBar(FullWrtStruct::ZoneHeader const &header): FullWrtStruct::ZoneHeader(header), m_box(), m_page(0), m_borderId(0), m_parsed(false)
61   {
62   }
63   //! destructor
64   ~SideBar() final;
65   //! the position (in point)
66   MWAWBox2f m_box;
67   //! the page
68   int m_page;
69   //! the border id
70   int m_borderId;
71   //! a flag to know if the sidebar is send to the listener
72   mutable bool m_parsed;
73 };
74 
~SideBar()75 SideBar::~SideBar()
76 {
77 }
78 
79 ////////////////////////////////////////
80 //! Internal: the state of a FullWrtGraph
81 struct State {
82   //! constructor
StateFullWrtGraphInternal::State83   State()
84     : m_version(-1)
85     , m_sidebarList()
86     , m_graphicMap()
87     , m_borderList()
88     , m_numPages(-1) { }
89 
90   //! the file version
91   mutable int m_version;
92   //! the sidebar list
93   std::vector<std::shared_ptr<SideBar> > m_sidebarList;
94   //! zoneId -> graphic entry
95   std::multimap<int, FullWrtStruct::EntryPtr > m_graphicMap;
96   //! a list of border
97   std::vector<FullWrtStruct::Border> m_borderList;
98   int m_numPages /* the number of pages */;
99 };
100 
101 ////////////////////////////////////////
102 //! Internal: the subdocument of a FullWrtGraph
103 class SubDocument final : public MWAWSubDocument
104 {
105 public:
106   //! constructor
SubDocument(FullWrtGraph & pars,int id,MWAWColor fontColor)107   SubDocument(FullWrtGraph &pars, int id, MWAWColor fontColor)
108     : MWAWSubDocument(pars.m_mainParser, MWAWInputStreamPtr(), MWAWEntry())
109     , m_graphParser(&pars)
110     , m_id(id)
111     , m_fontColor(fontColor) {}
112 
113   //! destructor
~SubDocument()114   ~SubDocument() final {}
115 
116   //! operator!=
117   bool operator!=(MWAWSubDocument const &doc) const final;
118 
119   //! the parser function
120   void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
121 
122 protected:
123   /** the graph parser */
124   FullWrtGraph *m_graphParser;
125   //! the zone file id
126   int m_id;
127   //! the default font color
128   MWAWColor m_fontColor;
129 
130 private:
131   SubDocument(SubDocument const &orig) = delete;
132   SubDocument &operator=(SubDocument const &orig) = delete;
133 };
134 
parse(MWAWListenerPtr & listener,libmwaw::SubDocumentType)135 void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/)
136 {
137   if (!listener.get()) {
138     MWAW_DEBUG_MSG(("FullWrtGraphInternal::SubDocument::parse: no listener\n"));
139     return;
140   }
141   if (!m_graphParser) {
142     MWAW_DEBUG_MSG(("FullWrtGraphInternal::SubDocument::parse: no graph parser\n"));
143     return;
144   }
145   m_graphParser->send(m_id, m_fontColor);
146 }
147 
operator !=(MWAWSubDocument const & doc) const148 bool SubDocument::operator!=(MWAWSubDocument const &doc) const
149 {
150   if (MWAWSubDocument::operator!=(doc)) return true;
151   auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
152   if (!sDoc) return true;
153   if (m_graphParser != sDoc->m_graphParser) return true;
154   if (m_id != sDoc->m_id) return true;
155   if (m_fontColor != sDoc->m_fontColor) return true;
156   return false;
157 }
158 }
159 
160 ////////////////////////////////////////////////////////////
161 // constructor/destructor, ...
162 ////////////////////////////////////////////////////////////
FullWrtGraph(FullWrtParser & parser)163 FullWrtGraph::FullWrtGraph(FullWrtParser &parser)
164   : m_parserState(parser.getParserState())
165   , m_state(new FullWrtGraphInternal::State)
166   , m_mainParser(&parser)
167 {
168 }
169 
~FullWrtGraph()170 FullWrtGraph::~FullWrtGraph()
171 {
172 }
173 
version() const174 int FullWrtGraph::version() const
175 {
176   if (m_state->m_version < 0)
177     m_state->m_version = m_parserState->m_version;
178   return m_state->m_version;
179 }
180 
numPages() const181 int FullWrtGraph::numPages() const
182 {
183   if (m_state->m_numPages > 0)
184     return m_state->m_numPages;
185   int nPage=0;
186   for (auto sidebar : m_state->m_sidebarList) {
187     if (!sidebar)
188       continue;
189     if (sidebar->m_page>nPage)
190       nPage=sidebar->m_page;
191   }
192   return (m_state->m_numPages=nPage);
193 }
194 
getBorder(int bId,FullWrtStruct::Border & border) const195 bool FullWrtGraph::getBorder(int bId, FullWrtStruct::Border &border) const
196 {
197   if (bId < 0 || bId>= int(m_state->m_borderList.size())) {
198     MWAW_DEBUG_MSG(("FullWrtGraph::getBorder: can not find border %d\n", bId));
199     border=FullWrtStruct::Border();
200     return false;
201   }
202   border=m_state->m_borderList[size_t(bId)];
203   return true;
204 }
205 
send(int fileId,MWAWColor const & fontColor)206 bool FullWrtGraph::send(int fileId, MWAWColor const &fontColor)
207 {
208   return m_mainParser->send(fileId, fontColor);
209 }
210 
211 ////////////////////////////////////////////////////////////
212 //
213 // Intermediate level
214 //
215 ////////////////////////////////////////////////////////////
216 
217 ////////////////////////////////////////////////////////////
218 // low level
219 ////////////////////////////////////////////////////////////
220 
221 ////////////////////////////////////////////////////////////
222 // border
readBorderDocInfo(FullWrtStruct::EntryPtr zone)223 bool FullWrtGraph::readBorderDocInfo(FullWrtStruct::EntryPtr zone)
224 {
225   MWAWInputStreamPtr input = zone->m_input;
226   libmwaw::DebugFile &asciiFile = zone->getAsciiFile();
227   libmwaw::DebugStream f;
228   long pos = input->tell();
229   if (input->readULong(4)!=0x626f7264 || input->readULong(1)) {
230     input->seek(pos, librevenge::RVNG_SEEK_SET);
231     return false;
232   }
233 
234   long blckSz = input->readLong(4);
235   long endData = pos+9+blckSz;
236   auto num = static_cast<int>(input->readULong(2));
237   int const fSz = 26;
238   f << "Entries(Border):N=" << num << ",";
239   if (blckSz < 2 || blckSz != 2 + num*fSz || endData > zone->end()) {
240     MWAW_DEBUG_MSG(("FullWrtGraph::readBorderDocInfo: problem reading the data block or the number of data\n"));
241     f << "###";
242     asciiFile.addPos(pos);
243     asciiFile.addNote(f.str().c_str());
244     if (endData <= zone->end()) {
245       input->seek(endData, librevenge::RVNG_SEEK_SET);
246       return true;
247     }
248     input->seek(pos, librevenge::RVNG_SEEK_SET);
249     return false;
250   }
251 
252   asciiFile.addPos(pos);
253   asciiFile.addNote(f.str().c_str());
254 
255   m_state->m_borderList.push_back(FullWrtStruct::Border());
256   for (int i = 0; i < num; i++) {
257     pos = input->tell();
258     FullWrtStruct::Border mod;
259     f.str("");
260     f << "Border-B" << i << ":";
261     if (!mod.read(zone, fSz))
262       f << "###";
263     else
264       f << mod;
265     m_state->m_borderList.push_back(mod);
266     asciiFile.addPos(pos);
267     asciiFile.addNote(f.str().c_str());
268     input->seek(pos+fSz, librevenge::RVNG_SEEK_SET);
269   }
270   return true;
271 }
272 
273 ////////////////////////////////////////////////////////////
274 // side bar
readSideBar(FullWrtStruct::EntryPtr zone,FullWrtStruct::ZoneHeader const & doc)275 std::shared_ptr<FullWrtStruct::ZoneHeader> FullWrtGraph::readSideBar(FullWrtStruct::EntryPtr zone, FullWrtStruct::ZoneHeader const &doc)
276 {
277   std::shared_ptr<FullWrtGraphInternal::SideBar> sidebar;
278   if (doc.m_type != 0x13 && doc.m_type != 0x14) {
279     MWAW_DEBUG_MSG(("FullWrtGraph::readSideBar: find unexpected type\n"));
280     return sidebar;
281   }
282   MWAWInputStreamPtr input = zone->m_input;
283   long pos = input->tell();
284   sidebar.reset(new FullWrtGraphInternal::SideBar(doc));
285   if (!sidebar->read(zone)) {
286     input->seek(pos, librevenge::RVNG_SEEK_SET);
287     sidebar.reset();
288     return sidebar;
289   }
290 
291   int val;
292   if (input->tell()+12 > zone->end()) {
293     input->seek(pos, librevenge::RVNG_SEEK_SET);
294     sidebar.reset();
295     return sidebar;
296   }
297 
298   libmwaw::DebugFile &asciiFile = zone->getAsciiFile();
299   libmwaw::DebugStream f;
300   f << "Entries(SideBar):" << *sidebar;
301   asciiFile.addPos(pos);
302   asciiFile.addNote(f.str().c_str());
303 
304   for (int i=0; i<3; ++i) {
305     pos = input->tell();
306     bool ok=false;
307     switch (i) {
308     case 0:
309       ok=readSideBarPosition(zone, *sidebar);
310       break;
311     case 1:
312       ok=readSideBarFormat(zone, *sidebar);
313       break;
314     case 2:
315       ok=readSideBarUnknown(zone, *sidebar);
316       break;
317     default:
318       break;
319     }
320     if (ok) continue;
321     MWAW_DEBUG_MSG(("FullWrtGraph::readSideBar: pb reading the zone %d\n", i));
322     f.str("");
323     static char const *wh[]= {"position","format","unknown"};
324     f << "SideBar[" << wh[i] << ":###";
325     asciiFile.addPos(pos);
326     asciiFile.addNote(f.str().c_str());
327 
328     input->seek(pos, librevenge::RVNG_SEEK_SET);
329     return sidebar;
330   }
331 
332   // checkme: can this exist for a sidebar ?
333   val = int(input->readLong(1));
334   if (val==1) {
335     pos = input->tell();
336     auto sz = long(input->readULong(4));
337     if (sz && input->tell()+sz <= zone->end()) {
338       f.str("");
339       f << "SideBar[end]:";
340       asciiFile.addPos(pos);
341       asciiFile.addNote(f.str().c_str());
342       input->seek(sz, librevenge::RVNG_SEEK_CUR);
343     }
344     else {
345       MWAW_DEBUG_MSG(("FullWrtGraph::readSideBar: find bad end data\n"));
346       input->seek(pos, librevenge::RVNG_SEEK_SET);
347     }
348   }
349   else if (val) {
350     MWAW_DEBUG_MSG(("FullWrtGraph::readSideBar: find bad end data(II)\n"));
351   }
352   m_state->m_sidebarList.push_back(sidebar);
353   return sidebar;
354 }
355 
readSideBarPosition(FullWrtStruct::EntryPtr zone,FullWrtGraphInternal::SideBar & frame)356 bool FullWrtGraph::readSideBarPosition(FullWrtStruct::EntryPtr zone, FullWrtGraphInternal::SideBar &frame)
357 {
358   MWAWInputStreamPtr input = zone->m_input;
359   long pos = input->tell();
360   libmwaw::DebugFile &asciiFile = zone->getAsciiFile();
361   libmwaw::DebugStream f;
362 
363   auto sz = long(input->readULong(4));
364   if (sz < 0 || pos+sz+4 > zone->end())
365     return false;
366   f << "SideBar[pos]:";
367 
368   if (sz < 28) {
369     MWAW_DEBUG_MSG(("FullWrtGraph::readSideBarPosition: the size seems bad\n"));
370     f << "###";
371     input->seek(pos+4+sz, librevenge::RVNG_SEEK_SET);
372     asciiFile.addPos(pos);
373     asciiFile.addNote(f.str().c_str());
374     return true;
375   }
376 
377   int dim[4];
378   for (auto &d : dim) d=int(input->readLong(2));
379   frame.m_box=MWAWBox2f(MWAWVec2f(float(dim[1]),float(dim[0])),MWAWVec2f(float(dim[3]),float(dim[2])));
380   f << "pos=" << frame.m_box << ",";
381   auto val=int(input->readLong(2));
382   if (val) f << "w[wrap]=" << val << "pt,";
383   f << "ptr?=[" << std::hex;
384   for (int i = 0; i < 2; i++) // two big number
385     f << input->readULong(4) << ",";
386   f << std::dec << "],";
387   val = int(input->readLong(2)); // seems related to floating point position
388   if (val) f << "unkn=" << std::hex << val << std::dec << ",";// 0|441|442|f91|16ac
389   val = int(input->readLong(2)); // always 0?
390   if (val) f << "f0=" << val << ",";
391   frame.m_page = int(input->readLong(2));
392   if (frame.m_page) f << "page=" << frame.m_page << ",";
393   val = int(input->readLong(2)); // number of point in the left part
394   if (val) f << "N[left]?=" << val << ",";
395   auto N=static_cast<int>(input->readLong(2));
396   if (N*4+28 > sz) {
397     f << "#N=" << N << ",";
398     N=0;
399   }
400   else
401     f << "N=" << N << ",";
402 
403   /* probably first the left margin: (x_i,n): meaning to add n times
404      a point at x, then the same thing for the right margins
405      -16000/16000=no point (left/right)
406   */
407   f << "mask=[";
408   for (int i = 0; i < N; i++) {
409     auto x = int(input->readLong(2));
410     auto n = int(input->readLong(2));
411     f << x << ":" << n << ",";
412   }
413   f << "],";
414   if (input->tell() != pos+4+sz) {
415     asciiFile.addDelimiter(input->tell(),'|');
416     input->seek(pos+4+sz, librevenge::RVNG_SEEK_SET);
417   }
418   asciiFile.addPos(pos);
419   asciiFile.addNote(f.str().c_str());
420   return true;
421 }
422 
readSideBarFormat(FullWrtStruct::EntryPtr zone,FullWrtGraphInternal::SideBar & frame)423 bool FullWrtGraph::readSideBarFormat(FullWrtStruct::EntryPtr zone, FullWrtGraphInternal::SideBar &frame)
424 {
425   int const vers=version();
426   MWAWInputStreamPtr input = zone->m_input;
427   long pos = input->tell();
428   libmwaw::DebugFile &asciiFile = zone->getAsciiFile();
429   libmwaw::DebugStream f;
430 
431   auto sz = long(input->readULong(4));
432   if (sz < 0 || pos+sz+4 > zone->end())
433     return false;
434   f << "SideBar[format]:";
435   if ((vers==1&&sz!=0x3a)||(vers==2&&sz!=0x38)) {
436     MWAW_DEBUG_MSG(("FullWrtGraph::readSideBarFormat: the size seems bad\n"));
437     f << "###";
438     input->seek(pos+4+sz, librevenge::RVNG_SEEK_SET);
439     asciiFile.addPos(pos);
440     asciiFile.addNote(f.str().c_str());
441     return true;
442   }
443   f << "PTR=" << std::hex << input->readLong(4) << std::dec << ",";
444   auto N=static_cast<int>(input->readLong(1));
445   int val;
446   if (N) {
447     f << "N=" << N << ",";
448     val=static_cast<int>(input->readLong(1));
449     if (val) f << "#f0=" << val << ",";
450     /* now probably N*[unknData],
451        find for N=1 005f000000b201d2001600f40f94020004100001009700000000000000000000
452      */
453   }
454   input->seek(pos+42, librevenge::RVNG_SEEK_SET);
455   float dim[2];
456   for (auto &d : dim) d=float(input->readLong(4))/65536.f;
457   f << "dim?=" << dim[1] << "x" << dim[0] << ",";
458   val=static_cast<int>(input->readULong(2)); // another dim with a flag?
459   if (val&0x8000) f << "f1[high],";
460   if (val&0x7FFF) f << "f1=" << (val&0x7FFF) << ",";
461   float w=float(input->readLong(4))/65536.f;
462   f << "w[wrap]=" << w << "pt,";
463   frame.m_borderId=static_cast<int>(input->readLong(2));
464   if (frame.m_borderId)
465     f << "B" << frame.m_borderId-1 << ",";
466   if (vers==1) {
467     val=static_cast<int>(input->readLong(2)); // 0|1|4|b|20|..f0
468     if (val) f << "f2=" << val << ",";
469   }
470   val=static_cast<int>(input->readLong(2)); // always 0
471   if (val)
472     f << "f3=" << val << ",";
473 
474   if (input->tell() != pos+4+sz) {
475     asciiFile.addDelimiter(input->tell(),'|');
476     input->seek(pos+4+sz, librevenge::RVNG_SEEK_SET);
477   }
478   asciiFile.addPos(pos);
479   asciiFile.addNote(f.str().c_str());
480   return true;
481 }
482 
readSideBarUnknown(FullWrtStruct::EntryPtr zone,FullWrtGraphInternal::SideBar &)483 bool FullWrtGraph::readSideBarUnknown(FullWrtStruct::EntryPtr zone, FullWrtGraphInternal::SideBar &/*frame*/)
484 {
485   MWAWInputStreamPtr input = zone->m_input;
486   long pos = input->tell();
487   libmwaw::DebugFile &asciiFile = zone->getAsciiFile();
488   libmwaw::DebugStream f;
489 
490   auto sz = long(input->readULong(4));
491   if (sz < 0 || pos+sz+4 > zone->end())
492     return false;
493   f << "SideBar[unknown]:";
494   if (sz!=0x30) {
495     MWAW_DEBUG_MSG(("FullWrtGraph::readSideBarUnknown: the size seems bad\n"));
496     f << "###";
497     input->seek(pos+4+sz, librevenge::RVNG_SEEK_SET);
498     asciiFile.addPos(pos);
499     asciiFile.addNote(f.str().c_str());
500     return true;
501   }
502   auto val = static_cast<int>(input->readLong(2));
503   if (val!=-1)
504     f << "f0=" << val << ",";
505   val = static_cast<int>(input->readLong(2));
506   if (val!=1)
507     f << "f1=" << val << ",";
508   val = static_cast<int>(input->readULong(2)); // maybe a color?
509   if (val)
510     f << "f2=" << std::hex << val << std::dec << ",";
511   for (int i=0; i<2; ++i) { // f3=1|2, f4=small numer 0..ff
512     val = static_cast<int>(input->readULong(2));
513     if (val)
514       f << "f" << i+3 << "=" << val << ",";
515   }
516   for (int i=0; i<19; ++i) { // g0,g1,g17,g18: in form xyxy, other 0
517     val = static_cast<int>(input->readULong(2));
518     if (val)
519       f << "g" << i << "=" << std::hex << val << std::dec << ",";
520   }
521   if (input->tell() != pos+4+sz) {
522     asciiFile.addDelimiter(input->tell(),'|');
523     input->seek(pos+4+sz, librevenge::RVNG_SEEK_SET);
524   }
525   asciiFile.addPos(pos);
526   asciiFile.addNote(f.str().c_str());
527   return true;
528 }
529 
sendSideBar(FullWrtGraphInternal::SideBar const & frame)530 bool FullWrtGraph::sendSideBar(FullWrtGraphInternal::SideBar const &frame)
531 {
532   MWAWTextListenerPtr listener=m_parserState->m_textListener;
533   if (!listener) {
534     MWAW_DEBUG_MSG(("FullWrtGraph::sendSideBar can not find the listener\n"));
535     return true;
536   }
537 
538   frame.m_parsed=true;
539   MWAWPosition pos(frame.m_box[0]+72.f*m_mainParser->getPageLeftTop(),
540                    frame.m_box.size(),librevenge::RVNG_POINT);
541   pos.setPage(frame.m_page>0 ? frame.m_page : 1);
542   pos.setRelativePosition(MWAWPosition::Page);
543   pos.m_wrapping=(frame.m_wrapping==3) ?
544                  MWAWPosition::WBackground : MWAWPosition::WDynamic;
545   FullWrtStruct::Border border;
546   MWAWGraphicStyle style;
547   if (frame.m_borderId && getBorder(frame.m_borderId, border))
548     border.addTo(style);
549   MWAWSubDocumentPtr doc(new FullWrtGraphInternal::SubDocument(*this,frame.m_fileId,border.m_frontColor));
550   listener->insertTextBox(pos, doc, style);
551   return true;
552 }
553 
554 ////////////////////////////////////////////////////////////
555 // graphic: data +
readGraphicData(FullWrtStruct::EntryPtr zone,FullWrtStruct::ZoneHeader & doc)556 std::shared_ptr<FullWrtStruct::ZoneHeader> FullWrtGraph::readGraphicData(FullWrtStruct::EntryPtr zone, FullWrtStruct::ZoneHeader &doc)
557 {
558   std::shared_ptr<FullWrtStruct::ZoneHeader> graphData;
559   if (doc.m_type != 0x15) {
560     MWAW_DEBUG_MSG(("FullWrtGraph::readGraphicData: find unexpected type\n"));
561     return graphData;
562   }
563   MWAWInputStreamPtr input = zone->m_input;
564   long pos = input->tell();
565   if (!doc.read(zone)) {
566     input->seek(pos, librevenge::RVNG_SEEK_SET);
567     return graphData;
568   }
569 
570   int const vers = version();
571   libmwaw::DebugFile &asciiFile = zone->getAsciiFile();
572   libmwaw::DebugStream f;
573 
574   if (input->tell()+(vers==2?14:2) > zone->end()) {
575     input->seek(pos, librevenge::RVNG_SEEK_SET);
576     return graphData;
577   }
578 
579   graphData.reset(new FullWrtStruct::ZoneHeader(doc));
580   f.str("");
581   f << "Entries(GraphData):" << doc;
582   asciiFile.addPos(pos);
583   asciiFile.addNote(f.str().c_str());
584   if (vers == 2) {
585     pos = input->tell();
586     f.str("");
587     f << "GraphData[1]:";
588     int dim[4];
589     for (auto &d : dim) d=int(input->readLong(2));
590     f << "box=" << dim[1] << "x" << dim[0] << "<->" << dim[3] << "x" << dim[2] << ",";
591     for (int i = 0; i < 2; i++) { // always 0 ?
592       auto val = int(input->readLong(2));
593       if (val)
594         f << "f" << i << "=" << val << "c";
595     }
596     asciiFile.addPos(pos);
597     asciiFile.addNote(f.str().c_str());
598   }
599 
600   f.str("");
601   auto nextData = int(input->readULong(1));
602   pos = input->tell();
603   if (nextData==1) {
604     f << "GraphData[2]:";
605     auto sz = long(input->readULong(4));
606     if (sz < 0 || pos+4+sz > zone->end()) {
607       f << "#sz=" << sz << ",";
608       input->seek(pos, librevenge::RVNG_SEEK_SET);
609     }
610     else if (sz) {   // a serie of doc id ( normally 1e )
611       f << "docId[type1e?]=[";
612       for (long i = 0; i < sz/2; i++) {
613         auto id = int(input->readLong(2));
614         std::string type=m_mainParser->getDocumentTypeName(id);
615         if (type.empty())
616           f << "#" << id << ",";
617         else
618           f << id << "[" << type << "],";
619       }
620       f << "],";
621       input->seek(pos+4+sz, librevenge::RVNG_SEEK_SET);
622     }
623   }
624   else if (nextData) f << "GraphData[2]:#" << nextData;
625 
626   input->seek(1, librevenge::RVNG_SEEK_CUR);
627   if (f.str().length()) {
628     asciiFile.addPos(pos);
629     asciiFile.addNote(f.str().c_str());
630   }
631 
632   return graphData;
633 }
634 
readGraphic(FullWrtStruct::EntryPtr zone)635 bool FullWrtGraph::readGraphic(FullWrtStruct::EntryPtr zone)
636 {
637   int vers = version();
638 
639   MWAWInputStreamPtr input = zone->m_input;
640   libmwaw::DebugFile &asciiFile = zone->getAsciiFile();
641   libmwaw::DebugStream f;
642 
643   long pos = zone->begin();
644   input->seek(pos, librevenge::RVNG_SEEK_SET);
645   auto sz = long(input->readULong(4));
646   int expectedSz = vers==1 ? 0x5c : 0x54;
647   if (sz != expectedSz || pos+sz > zone->end()) return false;
648   input->seek(sz, librevenge::RVNG_SEEK_CUR);
649   f << "Entries(Graphic)";
650   f << "|" << *zone << ":";
651   if (zone->m_fileType >= 0)
652     f << "type=" << std::hex << zone->m_fileType << std::dec << ",";
653   asciiFile.addPos(pos);
654   asciiFile.addNote(f.str().c_str());
655 
656   pos = input->tell();
657   sz = long(input->readULong(4));
658   if (!sz || pos+4+sz > zone->end()) {
659     MWAW_DEBUG_MSG(("FullWrtGraph::readGraphic: can not read graphic size\n"));
660     return false;
661   }
662   f.str("");
663   f << "Graphic:sz=" << std::hex << sz << std::dec << ",";
664   asciiFile.addPos(pos);
665   asciiFile.addNote(f.str().c_str());
666   asciiFile.skipZone(pos+4, pos+4+sz-1);
667   input->seek(sz, librevenge::RVNG_SEEK_CUR);
668 
669   m_state->m_graphicMap.insert
670   (std::multimap<int, FullWrtStruct::EntryPtr >::value_type(zone->id(), zone));
671 
672   pos = input->tell();
673   if (pos == zone->end())
674     return true;
675 
676   sz = long(input->readULong(4));
677   if (sz)
678     input->seek(sz, librevenge::RVNG_SEEK_CUR);
679   if (pos+4+sz!=zone->end()) {
680     MWAW_DEBUG_MSG(("FullWrtGraph::readGraphic: end graphic seems odds\n"));
681   }
682   asciiFile.addPos(pos);
683   asciiFile.addNote("Graphic-A");
684 
685   asciiFile.addPos(input->tell());
686   asciiFile.addNote("_");
687 
688   return true;
689 }
690 
691 ////////////////////////////////////////////////////////////
692 // send data
693 ////////////////////////////////////////////////////////////
sendGraphic(int fId)694 bool FullWrtGraph::sendGraphic(int fId)
695 {
696   auto it = m_state->m_graphicMap.find(fId);
697   if (it == m_state->m_graphicMap.end() || !it->second) {
698     MWAW_DEBUG_MSG(("FullWrtGraph::sendGraphic: can not find graphic %d\n", fId));
699     return false;
700   }
701   auto zone = it->second;
702   MWAWInputStreamPtr input = zone->m_input;
703   long pos = input->tell();
704   bool ok=sendGraphic(zone);
705   input->seek(pos, librevenge::RVNG_SEEK_SET);
706   return ok;
707 }
708 
sendGraphic(FullWrtStruct::EntryPtr zone)709 bool FullWrtGraph::sendGraphic(FullWrtStruct::EntryPtr zone)
710 {
711   MWAWTextListenerPtr listener=m_parserState->m_textListener;
712   if (!listener) {
713     MWAW_DEBUG_MSG(("FullWrtGraph::sendGraphic can not find the listener\n"));
714     return true;
715   }
716   zone->setParsed(true);
717 
718   MWAWInputStreamPtr input = zone->m_input;
719 
720   long pos = zone->begin();
721   input->seek(pos, librevenge::RVNG_SEEK_SET);
722   auto sz = static_cast<int>(input->readULong(4));
723   input->seek(sz, librevenge::RVNG_SEEK_CUR);
724 
725   // header
726   pos = input->tell();
727   sz = static_cast<int>(input->readULong(4));
728 
729 #ifdef DEBUG_WITH_FILES
730   if (1) {
731     librevenge::RVNGBinaryData file;
732     input->seek(pos+4, librevenge::RVNG_SEEK_SET);
733     input->readDataBlock(sz, file);
734     static int volatile pictName = 0;
735     libmwaw::DebugStream f;
736     f << "DATA-" << ++pictName;
737     libmwaw::Debug::dumpFile(file, f.str().c_str());
738   }
739 #endif
740 
741   input->seek(pos+4, librevenge::RVNG_SEEK_SET);
742   MWAWBox2f box;
743   auto res = MWAWPictData::check(input, sz, box);
744   if (res == MWAWPict::MWAW_R_BAD) {
745     MWAW_DEBUG_MSG(("FullWrtGraph::sendGraphic: can not find the picture\n"));
746     return false;
747   }
748 
749   MWAWVec2f actualSize, naturalSize;
750   if (box.size().x() > 0 && box.size().y()  > 0) {
751     actualSize = naturalSize = box.size();
752   }
753   else if (actualSize.x() <= 0 || actualSize.y() <= 0) {
754     MWAW_DEBUG_MSG(("FullWrtGraph::sendGraphic: can not find the picture size\n"));
755     actualSize = naturalSize = MWAWVec2f(100,100);
756   }
757   MWAWPosition pictPos=MWAWPosition(MWAWVec2f(0,0),actualSize, librevenge::RVNG_POINT);
758   pictPos.setRelativePosition(MWAWPosition::Char);
759   pictPos.setNaturalSize(naturalSize);
760 
761   input->seek(pos+4, librevenge::RVNG_SEEK_SET);
762   std::shared_ptr<MWAWPict> pict(MWAWPictData::get(input, sz));
763   if (pict) {
764     MWAWEmbeddedObject picture;
765     if (pict->getBinary(picture)) {
766       listener->insertPicture(pictPos, picture);
767       return true;
768     }
769   }
770 
771   return true;
772 }
773 
sendPageGraphics()774 bool FullWrtGraph::sendPageGraphics()
775 {
776   for (auto const &frame : m_state->m_sidebarList) {
777     if (!frame)
778       continue;
779     if (!frame->m_parsed)
780       sendSideBar(*frame);
781   }
782   return true;
783 }
784 
flushExtra()785 void FullWrtGraph::flushExtra()
786 {
787   for (auto it : m_state->m_graphicMap) {
788     FullWrtStruct::EntryPtr &zone = it.second;
789     if (!zone || zone->isParsed())
790       continue;
791     sendGraphic(zone);
792   }
793 }
794 // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab:
795