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 <iomanip>
35 #include <iostream>
36 #include <limits>
37 #include <map>
38 #include <sstream>
39 
40 #include <librevenge/librevenge.h>
41 
42 #include "MWAWCell.hxx"
43 #include "MWAWTextListener.hxx"
44 #include "MWAWDebug.hxx"
45 #include "MWAWFont.hxx"
46 #include "MWAWFontConverter.hxx"
47 #include "MWAWParagraph.hxx"
48 #include "MWAWPosition.hxx"
49 #include "MWAWRSRCParser.hxx"
50 #include "MWAWSection.hxx"
51 #include "MWAWSubDocument.hxx"
52 #include "MWAWTable.hxx"
53 
54 #include "MarinerWrtParser.hxx"
55 
56 #include "MarinerWrtText.hxx"
57 
58 /** Internal: the structures of a MarinerWrtText */
59 namespace MarinerWrtTextInternal
60 {
61 ////////////////////////////////////////
62 //! Internal: struct used to store the font of a MarinerWrtText
63 struct Font {
64   //! constructor
FontMarinerWrtTextInternal::Font65   Font()
66     : m_font()
67     , m_localId(-1)
68     , m_tokenId(0)
69     , m_extra("")
70   {
71   }
72   //! operator<<
73   friend std::ostream &operator<<(std::ostream &o, Font const &font);
74 
75   //! the font
76   MWAWFont m_font;
77   //! the local id
78   int m_localId;
79   //! the token id
80   long m_tokenId;
81   //! extra data
82   std::string m_extra;
83 };
84 
operator <<(std::ostream & o,Font const & font)85 std::ostream &operator<<(std::ostream &o, Font const &font)
86 {
87   if (font.m_localId >= 0)
88     o << "FN" << font.m_localId << ",";
89   if (font.m_tokenId > 0)
90     o << "tokId=" << std::hex << font.m_tokenId << std::dec << ",";
91   o << font.m_extra;
92   return o;
93 }
94 
95 ////////////////////////////////////////
96 //! Internal: struct used to store the paragraph of a MarinerWrtText
97 struct Paragraph final : public MWAWParagraph {
98   //! constructor
ParagraphMarinerWrtTextInternal::Paragraph99   Paragraph()
100     : MWAWParagraph()
101     , m_paraFill()
102     , m_cellWidth(0)
103     , m_cellHeight(0)
104     , m_cellSep(0)
105     , m_cellFill()
106   {
107   }
108   Paragraph(Paragraph const &)=default;
109   Paragraph &operator=(Paragraph const &)=default;
110   //! destructor
111   ~Paragraph() final;
112   //! updates the paragraph knowing the paragraph pattern percent
updateMarinerWrtTextInternal::Paragraph113   void update(float percent)
114   {
115     if (m_paraFill.hasBackgroundColor())
116       m_backgroundColor=m_paraFill.getBackgroundColor(percent);
117     if (!m_paraFill.hasBorders())
118       return;
119     static int const wh[] = { libmwaw::Left, libmwaw::Top, libmwaw::Right, libmwaw::Bottom };
120     resizeBorders(4);
121     for (int i = 0; i < 4; i++) {
122       if (m_paraFill.m_borderTypes[i] <=0)
123         continue;
124       m_borders[size_t(wh[i])]=m_paraFill.getBorder(i);
125     }
126   }
127   //! updates the paragraph knowing the paragraph pattern percent
updateMarinerWrtTextInternal::Paragraph128   void update(float percent, MWAWCell &cell) const
129   {
130     if (m_cellFill.hasBackgroundColor())
131       cell.setBackgroundColor(m_cellFill.getBackgroundColor(percent));
132     if (!m_cellFill.hasBorders())
133       return;
134     static int const wh[] = { libmwaw::LeftBit, libmwaw::TopBit, libmwaw::RightBit, libmwaw::BottomBit };
135     for (int i = 0; i < 4; i++) {
136       if (m_cellFill.m_borderTypes[i] <=0)
137         continue;
138       cell.setBorders(wh[i], m_cellFill.getBorder(i));
139     }
140   }
141 
142   //! operator<<
143   friend std::ostream &operator<<(std::ostream &o, Paragraph const &para);
144   //! small structure to store border/fills properties in MarinerWrtText
145   struct BorderFill {
146     //! constructor
BorderFillMarinerWrtTextInternal::Paragraph::BorderFill147     BorderFill()
148       : m_foreColor(MWAWColor::black())
149       , m_backColor(MWAWColor::white())
150       , m_patternId(0)
151       , m_borderColor(MWAWColor::black())
152     {
153       for (auto &type : m_borderTypes) type=0;
154     }
155     //! return true if the properties are default properties
isDefaultMarinerWrtTextInternal::Paragraph::BorderFill156     bool isDefault() const
157     {
158       return !hasBorders() && !hasBackgroundColor();
159     }
160     //! reset the background color
resetBackgroundColorMarinerWrtTextInternal::Paragraph::BorderFill161     void resetBackgroundColor()
162     {
163       m_foreColor=MWAWColor::black();
164       m_backColor=MWAWColor::white();
165       m_patternId=0;
166     }
167     //! return true if we have a not white background color
hasBackgroundColorMarinerWrtTextInternal::Paragraph::BorderFill168     bool hasBackgroundColor() const
169     {
170       return !m_foreColor.isBlack()||!m_backColor.isWhite()||m_patternId;
171     }
172     //! returns the background color knowing the pattern percent
getBackgroundColorMarinerWrtTextInternal::Paragraph::BorderFill173     MWAWColor getBackgroundColor(float percent) const
174     {
175       if (percent < 0)
176         return m_backColor;
177       return MWAWColor::barycenter(percent,m_foreColor,1.f-percent,m_backColor);
178     }
179     //! reset the borders
resetBordersMarinerWrtTextInternal::Paragraph::BorderFill180     void resetBorders()
181     {
182       for (auto &type : m_borderTypes) type=0;
183     }
184     //! return true if we have border
hasBordersMarinerWrtTextInternal::Paragraph::BorderFill185     bool hasBorders() const
186     {
187       for (auto type : m_borderTypes)
188         if (type) return true;
189       return false;
190     }
191     //! return a border corresponding to a pos
192     MWAWBorder getBorder(int pos) const;
193     //! operator<<
194     friend std::ostream &operator<<(std::ostream &o, BorderFill const &fill);
195 
196     //! the foreground color
197     MWAWColor m_foreColor;
198     //! the background color
199     MWAWColor m_backColor;
200     //! the pattern id
201     int m_patternId;
202     //! the border color
203     MWAWColor m_borderColor;
204     //! the border type L T R B
205     int m_borderTypes[4];
206   };
207   //! the paragraph fill properties
208   BorderFill m_paraFill;
209   //! a cell width
210   int m_cellWidth;
211   //! a cell height
212   int m_cellHeight;
213   //! a cell separator
214   int m_cellSep;
215   //! the cell fill properties
216   BorderFill m_cellFill;
217 };
218 
~Paragraph()219 Paragraph::~Paragraph()
220 {
221 }
222 
operator <<(std::ostream & o,Paragraph const & para)223 std::ostream &operator<<(std::ostream &o, Paragraph const &para)
224 {
225   o << static_cast<MWAWParagraph const &>(para);
226   if (para.m_cellWidth)
227     o << "cellWidth=" << para.m_cellWidth << ",";
228   if (para.m_cellHeight > 0)
229     o << "cellHeight[atLeast]=" << para.m_cellHeight << ",";
230   else if (para.m_cellHeight < 0)
231     o << "cellHeight=" << -para.m_cellHeight << ",";
232   if (para.m_cellSep)
233     o << "cellSep=" << para.m_cellSep << ",";
234   if (!para.m_paraFill.isDefault())
235     o << para.m_paraFill;
236   if (!para.m_cellFill.isDefault())
237     o << "cell=[" << para.m_cellFill << "]";
238   return o;
239 }
240 
getBorder(int i) const241 MWAWBorder Paragraph::BorderFill::getBorder(int i) const
242 {
243   MWAWBorder res;
244   switch (m_borderTypes[i]) {
245   case 0:
246     res.m_style = MWAWBorder::None;
247     break;
248   case 1: // single[w=0.5]
249     res.m_width = 0.5;
250     MWAW_FALLTHROUGH;
251   case 2:
252     res.m_style = MWAWBorder::Simple;
253     break;
254   case 3:
255     res.m_style = MWAWBorder::Dot;
256     break;
257   case 4:
258     res.m_style = MWAWBorder::Dash;
259     break;
260   case 5:
261     res.m_width = 2;
262     break;
263   case 6:
264     res.m_width = 3;
265     break;
266   case 7:
267     res.m_width = 6;
268     break;
269   case 8:
270     res.m_type = MWAWBorder::Double;
271     break;
272   case 10:
273     res.m_type = MWAWBorder::Double;
274     res.m_widthsList.resize(3,1.);
275     res.m_widthsList[0]=2.0;
276     break;
277   case 11:
278     res.m_type = MWAWBorder::Double;
279     res.m_widthsList.resize(3,1.);
280     res.m_widthsList[2]=2.0;
281     break;
282   case 9:
283     res.m_type = MWAWBorder::Double;
284     res.m_width = 2;
285     break;
286   default:
287     res.m_style = MWAWBorder::None;
288     break;
289   }
290   res.m_color=m_borderColor;
291   return res;
292 }
293 
operator <<(std::ostream & o,Paragraph::BorderFill const & fill)294 std::ostream &operator<<(std::ostream &o, Paragraph::BorderFill const &fill)
295 {
296   if (fill.hasBackgroundColor()) {
297     o << "fill=[";
298     if (!fill.m_foreColor.isBlack()) o << "foreColor=" << fill.m_foreColor << ",";
299     if (!fill.m_backColor.isWhite()) o << "backColor=" << fill.m_backColor << ",";
300     if (fill.m_patternId) o << "patId=" << fill.m_patternId << ",";
301     o << "],";
302   }
303   static char const *wh[] = {"bordL", "bordT", "bordR", "bordB" };
304   if (!fill.m_borderColor.isBlack() && fill.hasBorders())
305     o << "borderColor=" << fill.m_borderColor << ",";
306   for (int i = 0; i < 4; i++) {
307     if (!fill.m_borderTypes[i]) continue;
308     o << wh[i] << "=";
309     switch (fill.m_borderTypes[i]) {
310     case 0:
311       break;
312     case 1:
313       o << "single[w=0.5],";
314       break;
315     case 2:
316       o << "single,";
317       break;
318     case 3:
319       o << "dot,";
320       break;
321     case 4:
322       o << "dash,";
323       break;
324     case 5:
325       o << "single[w=2],";
326       break;
327     case 6:
328       o << "single[w=3],";
329       break;
330     case 7:
331       o << "single[w=6],";
332       break;
333     case 8:
334       o << "double,";
335       break;
336     case 9:
337       o << "double[w=2],";
338       break;
339     case 10:
340       o << "double[w=1|2],";
341       break;
342     case 11:
343       o << "double[w=2|1],";
344       break;
345     default:
346       o << "#" << fill.m_borderTypes[i] << ",";
347       break;
348     }
349   }
350   return o;
351 }
352 
353 ////////////////////////////////////////
354 //! Internal: struct used to store zone data of a MarinerWrtText
355 struct Zone {
356   struct Information;
357 
358   //! constructor
ZoneMarinerWrtTextInternal::Zone359   explicit Zone(int zId)
360     : m_id(zId)
361     , m_infoList()
362     , m_fontList()
363     , m_rulerList()
364     , m_idFontMap()
365     , m_posFontMap()
366     , m_posRulerMap()
367     , m_actZone(0)
368     , m_parsed(false)
369   {
370   }
371 
372   //! returns the file position and the number of the sub zone
getPositionMarinerWrtTextInternal::Zone373   bool getPosition(long cPos, long &fPos, size_t &subZone) const
374   {
375     if (cPos < 0) return false;
376     long nChar= cPos;
377     for (size_t z = 0; z < m_infoList.size(); z++) {
378       if (m_infoList[z].m_pos.length() > nChar) {
379         fPos = m_infoList[z].m_pos.begin()+nChar;
380         subZone = z;
381         return true;
382       }
383       nChar -= m_infoList[z].m_pos.length();
384     }
385     return false;
386   }
387   //! returns the zone length
lengthMarinerWrtTextInternal::Zone388   long length() const
389   {
390     long res=0;
391     for (auto const &info : m_infoList)
392       res += info.m_pos.length();
393     return res;
394   }
395   //! returns a fonts corresponding to an id (if possible)
getFontMarinerWrtTextInternal::Zone396   bool getFont(int id, Font &ft) const
397   {
398     if (id < 0 || id >= int(m_fontList.size())) {
399       MWAW_DEBUG_MSG(("MarinerWrtTextInternal::Zone::getFont: can not find font %d\n", id));
400       return false;
401     }
402     ft = m_fontList[size_t(id)];
403     if (m_idFontMap.find(ft.m_localId) == m_idFontMap.end()) {
404       MWAW_DEBUG_MSG(("MarinerWrtTextInternal::Zone::getFont: can not find font id %d\n", id));
405     }
406     else
407       ft.m_font.setId(m_idFontMap.find(ft.m_localId)->second);
408     return true;
409   }
410   //! returns a ruler corresponding to an id (if possible)
getRulerMarinerWrtTextInternal::Zone411   bool getRuler(int id, Paragraph &ruler) const
412   {
413     if (id < 0 || id >= int(m_rulerList.size())) {
414       MWAW_DEBUG_MSG(("MarinerWrtTextInternal::Zone::getParagraph: can not find paragraph %d\n", id));
415       return false;
416     }
417     ruler = m_rulerList[size_t(id)];
418     return true;
419   }
420   //! the zone id
421   int m_id;
422   //! the list of information of the text in the file
423   std::vector<Information> m_infoList;
424   //! a list of font
425   std::vector<Font> m_fontList;
426   //! a list of ruler
427   std::vector<Paragraph> m_rulerList;
428   //! a map id -> fontId
429   std::map<int,int> m_idFontMap;
430   //! a map pos -> fontId
431   std::map<long,int> m_posFontMap;
432   //! a map pos -> rulerId
433   std::map<long,int> m_posRulerMap;
434   //! a index used to know the next zone in MarinerWrtText::readZone
435   int m_actZone;
436   //! a flag to know if the zone is parsed
437   mutable bool m_parsed;
438 
439   //! struct used to keep the information of a small zone of MarinerWrtTextInternal::Zone
440   struct Information {
441     //! constructor
InformationMarinerWrtTextInternal::Zone::Information442     Information()
443       : m_pos()
444       , m_cPos(0,0)
445       , m_extra("")
446     {
447     }
448     //! operator<<
operator <<MarinerWrtTextInternal::Zone449     friend std::ostream &operator<<(std::ostream &o, Information const &info)
450     {
451       if (info.m_cPos[0] || info.m_cPos[1])
452         o << "cPos=" << std::hex << info.m_cPos << std::dec << ",";
453       o << info.m_extra;
454       return o;
455     }
456 
457     //! the file position
458     MWAWEntry m_pos;
459     //! the characters positions
460     MWAWVec2l m_cPos;
461     //! extra data
462     std::string m_extra;
463   };
464 };
465 
466 ////////////////////////////////////////
467 //! Internal: struct used to store the table of a MarinerWrtText
468 struct Table {
469   struct Cell;
470   struct Row;
471   //! constructor
TableMarinerWrtTextInternal::Table472   explicit Table(Zone const &zone)
473     : m_zone(zone)
474     , m_rowsList()
475   {
476   }
477   //! returns the next char position after the table
nextCharPosMarinerWrtTextInternal::Table478   long nextCharPos() const
479   {
480     if (!m_rowsList.size()) {
481       MWAW_DEBUG_MSG(("MarinerWrtTextInternal::Table: can not compute the last position\n"));
482       return -1;
483     }
484     return m_rowsList.back().m_lastChar;
485   }
486   //! the actual zone
487   Zone const &m_zone;
488   //! the list of row
489   std::vector<Row> m_rowsList;
490 
491   //! a table row of a MarinerWrtText
492   struct Row {
493     //! constructor
RowMarinerWrtTextInternal::Table::Row494     Row()
495       :  m_lastChar(-1)
496       , m_height(0)
497       , m_cellsList()
498     {
499     }
500     //! the last table position
501     long m_lastChar;
502     //! the table height ( <=0 a least )
503     int m_height;
504     //! a list of cell entry list
505     std::vector<Cell> m_cellsList;
506   };
507   //! a table cell of a MarinerWrtText
508   struct Cell {
509     // constructor
CellMarinerWrtTextInternal::Table::Cell510     Cell()
511       : m_entry()
512       , m_rulerId(-1)
513       , m_width(-1)
514     {
515     }
516     // returns true if the information are find
okMarinerWrtTextInternal::Table::Cell517     bool ok() const
518     {
519       return m_entry.length()>0 && m_rulerId>=0 && m_width>=0;
520     }
521     //! the cell entry
522     MWAWEntry m_entry;
523     //! a list of cell ruler id
524     int m_rulerId;
525     //! the column width
526     int m_width;
527   };
528 };
529 
530 ////////////////////////////////////////
531 //! Internal: the state of a MarinerWrtText
532 struct State {
533   //! constructor
StateMarinerWrtTextInternal::State534   State()
535     : m_version(-1)
536     , m_textZoneMap()
537     , m_numPages(-1)
538     , m_actualPage(0)
539   {
540   }
541 
542   //! return a reference to a textzone ( if zone not exists, created it )
getZoneMarinerWrtTextInternal::State543   Zone &getZone(int id)
544   {
545     auto it = m_textZoneMap.find(id);
546     if (it != m_textZoneMap.end())
547       return it->second;
548     it = m_textZoneMap.insert
549          (std::map<int,Zone>::value_type(id,Zone(id))).first;
550     return it->second;
551   }
552   //! the file version
553   mutable int m_version;
554   //! a map id -> textZone
555   std::map<int,Zone> m_textZoneMap;
556   int m_numPages /* the number of pages */, m_actualPage /* the actual page */;
557 };
558 
559 }
560 
561 ////////////////////////////////////////////////////////////
562 // constructor/destructor, ...
563 ////////////////////////////////////////////////////////////
MarinerWrtText(MarinerWrtParser & parser)564 MarinerWrtText::MarinerWrtText(MarinerWrtParser &parser)
565   : m_parserState(parser.getParserState())
566   , m_state(new MarinerWrtTextInternal::State)
567   , m_mainParser(&parser)
568 {
569 }
570 
~MarinerWrtText()571 MarinerWrtText::~MarinerWrtText()
572 {
573 }
574 
version() const575 int MarinerWrtText::version() const
576 {
577   if (m_state->m_version < 0)
578     m_state->m_version = m_parserState->m_version;
579   return m_state->m_version;
580 }
581 
numPages() const582 int MarinerWrtText::numPages() const
583 {
584   if (m_state->m_numPages <= 0) {
585     int nPages = 0;
586     for (auto it : m_state->m_textZoneMap) {
587       nPages = computeNumPages(it.second);
588       if (nPages)
589         break;
590     }
591     m_state->m_numPages=nPages ? nPages : 1;
592   }
593   return m_state->m_numPages;
594 }
595 
596 ////////////////////////////////////////////////////////////
597 // Intermediate level
598 ////////////////////////////////////////////////////////////
599 
600 ////////////////////////////////////////////////////////////
601 //     Text
602 ////////////////////////////////////////////////////////////
readZone(MarinerWrtEntry const & entry,int zoneId)603 bool MarinerWrtText::readZone(MarinerWrtEntry const &entry, int zoneId)
604 {
605   if (entry.length() < 0x3) {
606     MWAW_DEBUG_MSG(("MarinerWrtText::readZone: data seems to short\n"));
607     return false;
608   }
609 
610   MWAWInputStreamPtr &input= m_parserState->m_input;
611   input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
612   input->pushLimit(entry.end());
613   std::vector<MarinerWrtStruct> dataList;
614   m_mainParser->decodeZone(dataList);
615   input->popLimit();
616 
617   if (dataList.size() != 1) {
618     MWAW_DEBUG_MSG(("MarinerWrtText::readZone: can find my data\n"));
619     return false;
620   }
621 
622   libmwaw::DebugStream f;
623   f << entry.name() << "[data]:";
624   MarinerWrtStruct const &data = dataList[0];
625   if (data.m_type) {
626     MWAW_DEBUG_MSG(("MarinerWrtText::readZone: find unexpected type zone\n"));
627     return false;
628   }
629 
630   auto &zone = m_state->getZone(zoneId);
631   if (zone.m_actZone < 0 || zone.m_actZone >= int(zone.m_infoList.size())) {
632     MWAW_DEBUG_MSG(("MarinerWrtText::readZone: actZone seems bad\n"));
633     if (zone.m_actZone < 0)
634       zone.m_actZone = int(zone.m_infoList.size());
635     zone.m_infoList.resize(size_t(zone.m_actZone)+1);
636   }
637   auto &info = zone.m_infoList[size_t(zone.m_actZone++)];
638   info.m_pos = data.m_pos;
639 
640   m_parserState->m_asciiFile.addPos(entry.begin());
641   m_parserState->m_asciiFile.addNote(f.str().c_str());
642 
643   input->seek(entry.end(), librevenge::RVNG_SEEK_SET);
644   return true;
645 }
646 
computeNumPages(MarinerWrtTextInternal::Zone const & zone) const647 int MarinerWrtText::computeNumPages(MarinerWrtTextInternal::Zone const &zone) const
648 {
649   int nPages = 0;
650   MWAWInputStreamPtr &input= m_parserState->m_input;
651   long pos = input->tell();
652   for (auto const &info : zone.m_infoList) {
653     if (!info.m_pos.valid()) continue;
654     if (nPages==0) nPages=1;
655     input->seek(info.m_pos.begin(), librevenge::RVNG_SEEK_SET);
656     long numChar = info.m_pos.length();
657     while (numChar-- > 0) {
658       if (input->readULong(1)==0xc)
659         nPages++;
660     }
661   }
662 
663   input->seek(pos, librevenge::RVNG_SEEK_SET);
664   return nPages;
665 }
666 
readTextStruct(MarinerWrtEntry const & entry,int zoneId)667 bool MarinerWrtText::readTextStruct(MarinerWrtEntry const &entry, int zoneId)
668 {
669   if (entry.length() < entry.m_N) {
670     MWAW_DEBUG_MSG(("MarinerWrtText::readTextStruct: data seems to short\n"));
671     return false;
672   }
673   MWAWInputStreamPtr &input= m_parserState->m_input;
674   input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
675   input->pushLimit(entry.end());
676   std::vector<MarinerWrtStruct> dataList;
677   m_mainParser->decodeZone(dataList, 1+22*entry.m_N);
678   input->popLimit();
679 
680   if (int(dataList.size()) != 22*entry.m_N) {
681     MWAW_DEBUG_MSG(("MarinerWrtText::readTextStruct: find unexpected number of data\n"));
682     return false;
683   }
684 
685   auto &zone = m_state->getZone(zoneId);
686   libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
687   libmwaw::DebugStream f;
688   size_t d = 0;
689   for (int i = 0; i < entry.m_N; i++) {
690     MarinerWrtTextInternal::Zone::Information info;
691     ascFile.addPos(dataList[d].m_filePos);
692 
693     int posi[4]= {0,0,0,0};
694     int dim[4]= {0,0,0,0}, dim2[4]= {0,0,0,0};
695     f.str("");
696     for (int j = 0; j < 22; j++) {
697       MarinerWrtStruct const &data = dataList[d++];
698       if (!data.isBasic()) {
699         f << "###f" << j << "=" << data << ",";
700         continue;
701       }
702       switch (j) {
703       case 0:
704       case 1:
705         info.m_cPos[j] = data.value(0);
706         break;
707       case 2:
708         if (data.value(0))
709           f << "fl0=" << std::hex << data.value(0) << std::dec << ",";
710         break;
711       case 3:
712       case 4:
713       case 5:
714       case 6:
715         posi[j-3]=static_cast<int>(data.value(0));
716         while (j < 6)
717           posi[++j-3]=static_cast<int>(dataList[d++].value(0));
718         if (posi[0] || posi[1])
719           f << "pos0=" << posi[0] << ":" << posi[1] << ",";
720         if (posi[2] || posi[3])
721           f << "pos1=" << posi[2] << ":" << posi[3] << ",";
722         break;
723       case 8:
724       case 9:
725       case 10:
726       case 11:
727         dim[j-8]=static_cast<int>(data.value(0));
728         while (j < 11)
729           dim[++j-8]=static_cast<int>(dataList[d++].value(0));
730         if (dim[0]||dim[1]||dim[2]||dim[3])
731           f << "pos2=" << dim[1] << "x" << dim[0] << "<->" << dim[3] << "x" << dim[2] << ",";
732         break;
733       case 12:
734         if (data.value(0)!=info.m_cPos[1]-info.m_cPos[0])
735           f << "nChar(diff)=" << info.m_cPos[1]-info.m_cPos[0]-data.value(0) << ",";
736         break;
737       case 14: // a small number(cst) in the list of structure
738       case 16: // an id?
739         if (data.value(0))
740           f << "f" << j << "=" << data.value(0) << ",";
741         break;
742       case 15: // 0xcc00|0xce40|... some flags? a dim
743         if (data.value(0))
744           f << "f" << j << "=" << std::hex << data.value(0) << std::dec << ",";
745         break;
746       case 17:
747       case 18:
748       case 19:
749       case 20:
750         dim2[j-17]=static_cast<int>(data.value(0));
751         while (j < 20)
752           dim2[++j-17]=static_cast<int>(dataList[d++].value(0));
753         if (dim2[0]||dim2[1]||dim2[2]||dim2[3])
754           f << "pos3=" << dim2[1] << "x" << dim2[0] << "<->" << dim2[3] << "x" << dim2[2] << ",";
755         break;
756       default:
757         if (data.value(0))
758           f << "#f" << j << "=" << data.value(0) << ",";
759         break;
760       }
761     }
762     info.m_extra = f.str();
763     zone.m_infoList.push_back(info);
764     f.str("");
765     f << entry.name() << "-" << i << ":" << info;
766     ascFile.addNote(f.str().c_str());
767   }
768   input->seek(entry.end(), librevenge::RVNG_SEEK_SET);
769 
770   return true;
771 }
772 
send(int zoneId)773 bool MarinerWrtText::send(int zoneId)
774 {
775   if (!m_parserState->m_textListener) {
776     MWAW_DEBUG_MSG(("MarinerWrtText::send: can not find the listener\n"));
777     return false;
778   }
779   if (m_state->m_textZoneMap.find(zoneId) == m_state->m_textZoneMap.end()) {
780     MWAW_DEBUG_MSG(("MarinerWrtText::send: can not find the text zone %d\n", zoneId));
781     return false;
782   }
783   auto const &zone=m_state->getZone(zoneId);
784   MWAWEntry entry;
785   entry.setBegin(0);
786   entry.setEnd(zone.length());
787   entry.setId(zoneId);
788   return send(zone,entry);
789 }
790 
send(MarinerWrtTextInternal::Zone const & zone,MWAWEntry const & entry)791 bool MarinerWrtText::send(MarinerWrtTextInternal::Zone const &zone, MWAWEntry const &entry)
792 {
793   MWAWTextListenerPtr listener=m_parserState->m_textListener;
794   if (!listener) {
795     MWAW_DEBUG_MSG(("MarinerWrtText::send: can not find the listener\n"));
796     return false;
797   }
798   zone.m_parsed = true;
799 
800   listener->setFont(MWAWFont());
801   int actPage = 1;
802   int numCols = 1;
803   bool isMain=entry.id()==0;
804 
805   if (isMain) {
806     m_mainParser->newPage(actPage);
807     MWAWSection sec=m_mainParser->getSection(0);
808     numCols=sec.numColumns();
809     if (numCols > 1) {
810       if (listener->isSectionOpened())
811         listener->closeSection();
812       listener->openSection(sec);
813     }
814   }
815 
816   long firstPos=0;
817   size_t firstZ=0;
818   if (!zone.getPosition(entry.begin(), firstPos, firstZ)) {
819     MWAW_DEBUG_MSG(("MarinerWrtText::send: can not find the beginning of the zone\n"));
820     return false;
821   }
822   MWAWInputStreamPtr &input= m_parserState->m_input;
823   input->seek(firstPos, librevenge::RVNG_SEEK_SET);
824 
825   long actChar = entry.begin();
826   libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
827   for (size_t z = firstZ ; z < zone.m_infoList.size(); z++) {
828     if (actChar >= entry.end())
829       break;
830     long pos = (firstPos >= 0) ? firstPos : zone.m_infoList[z].m_pos.begin();
831     long endPos = zone.m_infoList[z].m_pos.end();
832     if (endPos > pos+entry.end()-actChar)
833       endPos = pos+entry.end()-actChar;
834     input->seek(pos, librevenge::RVNG_SEEK_SET);
835     firstPos = -1;
836 
837     libmwaw::DebugStream f;
838     f << "Text[" << std::hex << actChar << std::dec << "]:";
839     int tokenEndPos = 0;
840     while (!input->isEnd()) {
841       long actPos = input->tell();
842       if (actPos >= endPos) {
843         ascFile.addPos(pos);
844         ascFile.addNote(f.str().c_str());
845 
846         f.str("");
847         f << "Text:";
848         break;
849       }
850       if (zone.m_posRulerMap.find(actChar)!=zone.m_posRulerMap.end()) {
851         int id = zone.m_posRulerMap.find(actChar)->second;
852         f << "[P" << id << "]";
853         MarinerWrtTextInternal::Paragraph para;
854         if (zone.getRuler(id, para)) {
855           if (entry.id()>=0 && para.m_cellWidth>0) {
856             MarinerWrtTextInternal::Table table(zone);
857             MWAWEntry tableEntry;
858             tableEntry.setBegin(actChar);
859             tableEntry.setEnd(entry.end());
860             if (!findTableStructure(table, tableEntry)) {
861               MWAW_DEBUG_MSG(("MarinerWrtText::send: can not find table data\n"));
862             }
863             else if (!sendTable(table) || actChar >= table.nextCharPos()) {
864               MWAW_DEBUG_MSG(("MarinerWrtText::send: can not send a table data\n"));
865             }
866             else {
867               ascFile.addPos(pos);
868               ascFile.addNote(f.str().c_str());
869 
870               f.str("");
871               f << "Text:";
872               actChar = table.nextCharPos();
873               if (actChar >= entry.end())
874                 break;
875               if (!zone.getPosition(actChar, firstPos, firstZ)) {
876                 MWAW_DEBUG_MSG(("MarinerWrtText::send: can not find the data after a table\n"));
877                 actChar = entry.end();
878                 break;
879               }
880               pos=firstPos;
881               if (z == firstZ) {
882                 input->seek(firstPos, librevenge::RVNG_SEEK_SET);
883                 firstPos = -1;
884                 continue;
885               }
886               else {
887                 z = firstZ-1;
888                 break;
889               }
890             }
891 
892             input->seek(actPos, librevenge::RVNG_SEEK_SET);
893           }
894           setProperty(para);
895         }
896       }
897       if (zone.m_posFontMap.find(actChar)!=zone.m_posFontMap.end()) {
898         int id = zone.m_posFontMap.find(actChar)->second;
899         f << "[F" << id << "]";
900         MarinerWrtTextInternal::Font font;
901         if (zone.getFont(id, font)) {
902           listener->setFont(font.m_font);
903           if (font.m_tokenId > 0) {
904             m_mainParser->sendToken(zone.m_id, font.m_tokenId);
905             tokenEndPos = -2;
906           }
907         }
908       }
909 
910       auto c = char(input->readULong(1));
911       ++actChar;
912       if (tokenEndPos) {
913         if ((c=='[' && tokenEndPos==-2)||(c==']' && tokenEndPos==-1)) {
914           tokenEndPos++;
915           f << c;
916           continue;
917         }
918         tokenEndPos++;
919         MWAW_DEBUG_MSG(("MarinerWrtText::send: find unexpected char for a token\n"));
920       }
921       switch (c) {
922       case 0x6: { // end of line
923         static bool first = true;
924         if (first) {
925           MWAW_DEBUG_MSG(("MarinerWrtText::send: oops find some table end of row\n"));
926           first = false;
927         }
928         f << "#";
929         listener->insertEOL();
930         break;
931       }
932       case 0x7: // fixme end of cell
933         f << "#";
934         listener->insertChar(' ');
935         break;
936       case 0x9:
937         listener->insertTab();
938         break;
939       case 0xa:
940         listener->insertEOL(true);
941         break;
942       case 0xc:
943         if (isMain)
944           m_mainParser->newPage(++actPage);
945         break;
946       case 0xd:
947         listener->insertEOL();
948         break;
949       case 0xe:
950         if (numCols > 1) {
951           listener->insertBreak(MWAWTextListener::ColumnBreak);
952           break;
953         }
954         MWAW_DEBUG_MSG(("MarinerWrtText::sendText: Find unexpected column break\n"));
955         f << "###";
956         if (isMain)
957           m_mainParser->newPage(++actPage);
958         break;
959 
960       // some special character
961       case 0x11:
962         listener->insertUnicode(0x2318);
963         break;
964       case 0x12:
965         listener->insertUnicode(0x2713);
966         break;
967       case 0x14:
968         listener->insertUnicode(0xF8FF);
969         break;
970       case 0x1f: // soft hyphen, ignore
971         break;
972       default:
973         actChar+=listener->insertCharacter(static_cast<unsigned char>(c), input, endPos);
974         break;
975       }
976 
977       f << c;
978       if (c==0xa || c==0xd || actPos==endPos) {
979         ascFile.addPos(pos);
980         ascFile.addNote(f.str().c_str());
981 
982         pos = actPos;
983         f.str("");
984         f << "Text:";
985       }
986     }
987   }
988 
989   return true;
990 }
991 
992 ////////////////////////////////////////////////////////////
993 // table function
sendTable(MarinerWrtTextInternal::Table & table)994 bool MarinerWrtText::sendTable(MarinerWrtTextInternal::Table &table)
995 {
996   MWAWTextListenerPtr listener=m_parserState->m_textListener;
997   if (!listener) {
998     MWAW_DEBUG_MSG(("MarinerWrtText::sendTable: can not find the listener\n"));
999     return false;
1000   }
1001   size_t nRows=table.m_rowsList.size();
1002   if (nRows == 0) {
1003     MWAW_DEBUG_MSG(("MarinerWrtText::sendTable: can not find the number of row\n"));
1004     return false;
1005   }
1006   // fixme: create a single table
1007   for (auto &row : table.m_rowsList) {
1008     size_t nCells=row.m_cellsList.size();
1009     if (nCells == 0) {
1010       MWAW_DEBUG_MSG(("MarinerWrtText::sendTable: can not find the number of cells\n"));
1011       continue;
1012     }
1013     std::vector<float> colWidths(nCells);
1014     for (size_t c=0; c < nCells; c++)
1015       colWidths[c]=float(row.m_cellsList[c].m_width);
1016     MWAWTable theTable(MWAWTable::TableDimBit);
1017     theTable.setColsSize(colWidths);
1018     theTable.setMergeBorders(false);
1019     listener->openTable(theTable);
1020     listener->openTableRow(-float(row.m_height), librevenge::RVNG_POINT);
1021 
1022     for (size_t c=0; c < nCells; c++) {
1023       auto const &cell=row.m_cellsList[c];
1024       MWAWCell fCell;
1025       MarinerWrtTextInternal::Paragraph para;
1026       if (table.m_zone.getRuler(cell.m_rulerId, para))
1027         para.update(m_mainParser->getPatternPercent(para.m_cellFill.m_patternId), fCell);
1028       fCell.setPosition(MWAWVec2i(static_cast<int>(c),0));
1029 
1030       listener->openTableCell(fCell);
1031       MWAWEntry entry(cell.m_entry);
1032       if (entry.length()<=1)
1033         listener->insertChar(' ');
1034       else {
1035         entry.setLength(entry.length()-1);
1036         send(table.m_zone, entry);
1037       }
1038 
1039       listener->closeTableCell();
1040     }
1041 
1042     listener->closeTableRow();
1043     listener->closeTable();
1044   }
1045   return true;
1046 }
1047 
findTableStructure(MarinerWrtTextInternal::Table & table,MWAWEntry const & entry)1048 bool MarinerWrtText::findTableStructure(MarinerWrtTextInternal::Table &table, MWAWEntry const &entry)
1049 {
1050   MarinerWrtTextInternal::Zone const &zone = table.m_zone;
1051   long firstPos=0;
1052   size_t firstZ=0;
1053   if (!zone.getPosition(entry.begin(), firstPos, firstZ))
1054     return false;
1055   MWAWInputStreamPtr &input= m_parserState->m_input;
1056   input->seek(firstPos, librevenge::RVNG_SEEK_SET);
1057 
1058   int actHeight=0, lastHeight = 0;
1059   long actChar = entry.begin();
1060   MarinerWrtTextInternal::Table::Row row;
1061 
1062   MarinerWrtTextInternal::Table::Cell cell;
1063   cell.m_entry.setBegin(actChar);
1064   bool firstCellInRow=true;
1065   for (size_t z=firstZ ; z < zone.m_infoList.size(); z++) {
1066     if (actChar >= entry.end())
1067       break;
1068 
1069     long endPos = zone.m_infoList[z].m_pos.end();
1070     if (z!=firstZ)
1071       input->seek(zone.m_infoList[z].m_pos.begin(), librevenge::RVNG_SEEK_SET);
1072 
1073     while (!input->isEnd()) {
1074       long actPos = input->tell();
1075       if (actPos == endPos)
1076         break;
1077       if (zone.m_posRulerMap.find(actChar)!=zone.m_posRulerMap.end()) {
1078         int id = zone.m_posRulerMap.find(actChar)->second;
1079         MarinerWrtTextInternal::Paragraph para;
1080         if (zone.getRuler(id, para)) {
1081           if (para.m_cellWidth > 0) {
1082             cell.m_rulerId = id;
1083             cell.m_width = para.m_cellWidth;
1084             lastHeight = para.m_cellHeight;
1085             if (lastHeight < 0 || (actHeight >= 0 && lastHeight > actHeight))
1086               actHeight=lastHeight;
1087           }
1088           else if (firstCellInRow)
1089             return table.m_rowsList.size();
1090         }
1091       }
1092 
1093       firstCellInRow = false;
1094       auto c = char(input->readULong(1));
1095       actChar++;
1096       if (c == 0x6) {
1097         if (!row.m_cellsList.size())
1098           return false;
1099         row.m_lastChar = actChar;
1100         row.m_height = actHeight;
1101         table.m_rowsList.push_back(row);
1102 
1103         // reset to look for the next row
1104         row=MarinerWrtTextInternal::Table::Row();
1105         actHeight=lastHeight;
1106         cell.m_entry.setBegin(actChar);
1107         firstCellInRow = true;
1108       }
1109       else if (c==0x7) {
1110         cell.m_entry.setEnd(actChar);
1111         if (!cell.ok())
1112           return false;
1113         row.m_cellsList.push_back(cell);
1114         cell.m_entry.setBegin(actChar);
1115       }
1116     }
1117   }
1118   return table.m_rowsList.size();
1119 }
1120 
1121 ////////////////////////////////////////////////////////////
1122 // read the data
readPLCZone(MarinerWrtEntry const & entry,int zoneId)1123 bool MarinerWrtText::readPLCZone(MarinerWrtEntry const &entry, int zoneId)
1124 {
1125   if (entry.length() < 2*entry.m_N-1) {
1126     MWAW_DEBUG_MSG(("MarinerWrtText::readPLCZone: data seems to short\n"));
1127     return false;
1128   }
1129 
1130   MWAWInputStreamPtr &input= m_parserState->m_input;
1131   input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
1132   input->pushLimit(entry.end());
1133   std::vector<MarinerWrtStruct> dataList;
1134   m_mainParser->decodeZone(dataList,1+2*entry.m_N);
1135   input->popLimit();
1136 
1137   if (int(dataList.size()) != 2*entry.m_N) {
1138     MWAW_DEBUG_MSG(("MarinerWrtText::readPLCZone: find unexpected number of data\n"));
1139     return false;
1140   }
1141 
1142   auto &zone = m_state->getZone(zoneId);
1143   bool isCharZone = entry.m_fileType==4;
1144   std::map<long,int> &map = isCharZone ? zone.m_posFontMap : zone.m_posRulerMap;
1145   libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
1146   libmwaw::DebugStream f;
1147   long pos = entry.begin();
1148   for (size_t d=0; d < dataList.size(); d+=2) {
1149     if (d%40==0) {
1150       if (d) {
1151         ascFile.addPos(pos);
1152         ascFile.addNote(f.str().c_str());
1153       }
1154       f.str("");
1155       f << entry.name() << ":";
1156       pos = dataList[d].m_filePos;
1157     }
1158     long cPos = dataList[d].value(0);
1159     auto id = static_cast<int>(dataList[d+1].value(0));
1160     map[cPos] = id;
1161     f << std::hex << cPos << std::dec; //pos
1162     if (isCharZone)
1163       f << "(F" << id << "),"; // id
1164     else
1165       f << "(P" << id << "),"; // id
1166   }
1167   ascFile.addPos(pos);
1168   ascFile.addNote(f.str().c_str());
1169   input->seek(entry.end(), librevenge::RVNG_SEEK_SET);
1170   return true;
1171 }
1172 
1173 ////////////////////////////////////////////////////////////
1174 //     Fonts
1175 ////////////////////////////////////////////////////////////
readFontNames(MarinerWrtEntry const & entry,int zoneId)1176 bool MarinerWrtText::readFontNames(MarinerWrtEntry const &entry, int zoneId)
1177 {
1178   if (entry.length() < entry.m_N) {
1179     MWAW_DEBUG_MSG(("MarinerWrtText::readFontNames: data seems to short\n"));
1180     return false;
1181   }
1182 
1183   MWAWInputStreamPtr &input= m_parserState->m_input;
1184   input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
1185   input->pushLimit(entry.end());
1186   std::vector<MarinerWrtStruct> dataList;
1187   m_mainParser->decodeZone(dataList,1+19*entry.m_N);
1188   input->popLimit();
1189 
1190   if (int(dataList.size()) != 19*entry.m_N) {
1191     MWAW_DEBUG_MSG(("MarinerWrtText::readFontNames: find unexpected number of data\n"));
1192     return false;
1193   }
1194 
1195   auto &zone = m_state->getZone(zoneId);
1196   libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
1197   libmwaw::DebugStream f;
1198   size_t d = 0;
1199   int val;
1200   for (int i = 0; i < entry.m_N; i++) {
1201     f.str("");
1202     f << entry.name() << "-FN" << i << ":";
1203     ascFile.addPos(dataList[d].m_filePos);
1204     std::string fontName("");
1205     for (int j = 0; j < 2; j++, d++) {
1206       MarinerWrtStruct const &data = dataList[d];
1207       if (data.m_type!=0 || !data.m_pos.valid()) {
1208         MWAW_DEBUG_MSG(("MarinerWrtText::readFontNames: name %d seems bad\n", j));
1209         f << "###" << data << ",";
1210         continue;
1211       }
1212       long pos = data.m_pos.begin();
1213       input->seek(pos, librevenge::RVNG_SEEK_SET);
1214       auto fSz = int(input->readULong(1));
1215       if (fSz+1 > data.m_pos.length()) {
1216         MWAW_DEBUG_MSG(("MarinerWrtText::readFontNames: field name %d seems bad\n", j));
1217         f << data << "[###fSz=" << fSz << ",";
1218         continue;
1219       }
1220       std::string name("");
1221       for (int c = 0; c < fSz; c++)
1222         name+=char(input->readULong(1));
1223       if (j == 0) {
1224         fontName = name;
1225         f << name << ",";
1226       }
1227       else
1228         f << "nFont=" << name << ",";
1229     }
1230     val = static_cast<int>(dataList[d++].value(0));
1231     if (val != 4) // always 4
1232       f << "f0=" << val << ",";
1233     val = static_cast<int>(dataList[d++].value(0));
1234     if (val) // always 0
1235       f << "f1=" << val << ",";
1236     auto fId = static_cast<int>(static_cast<uint16_t>(dataList[d++].value(0)));
1237     f << "fId=" << fId << ",";
1238     auto fIdAux = static_cast<int>(static_cast<uint16_t>(dataList[d++].value(0)));
1239     if (fIdAux)
1240       f << "f2=" << std::hex << fIdAux << std::dec << ",";
1241     for (int j = 6; j < 19; j++) { // f14=1,f15=0|3
1242       MarinerWrtStruct const &data = dataList[d++];
1243       if (data.m_type==0 || data.numValues() > 1)
1244         f << "f" << j-3 << "=" << data << ",";
1245       else if (data.value(0))
1246         f << "f" << j-3 << "=" << data.value(0) << ",";
1247     }
1248     if (fontName.length()) {
1249       // checkme:
1250       std::string family = (fIdAux&0xFF00) ==0x4000 ? "Osaka" : "";
1251       m_parserState->m_fontConverter->setCorrespondance(fId, fontName, family);
1252     }
1253     zone.m_idFontMap[i] = fId;
1254     ascFile.addNote(f.str().c_str());
1255   }
1256   input->seek(entry.end(), librevenge::RVNG_SEEK_SET);
1257   return true;
1258 }
1259 
readFonts(MarinerWrtEntry const & entry,int zoneId)1260 bool MarinerWrtText::readFonts(MarinerWrtEntry const &entry, int zoneId)
1261 {
1262   if (entry.length() < entry.m_N+1) {
1263     MWAW_DEBUG_MSG(("MarinerWrtText::readFonts: data seems to short\n"));
1264     return false;
1265   }
1266 
1267   MWAWInputStreamPtr &input= m_parserState->m_input;
1268   input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
1269   input->pushLimit(entry.end());
1270   std::vector<MarinerWrtStruct> dataList;
1271   m_mainParser->decodeZone(dataList,1+1+77*entry.m_N);
1272   input->popLimit();
1273 
1274   if (int(dataList.size()) != 1+77*entry.m_N) {
1275     MWAW_DEBUG_MSG(("MarinerWrtText::readFonts: find unexpected number of data\n"));
1276     return false;
1277   }
1278 
1279   auto &zone = m_state->getZone(zoneId);
1280   libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
1281   libmwaw::DebugStream f;
1282   f << entry.name() << ":unkn=" << dataList[0].value(0);
1283   ascFile.addPos(dataList[0].m_filePos);
1284   ascFile.addNote(f.str().c_str());
1285 
1286   size_t d = 1;
1287   for (int i = 0; i < entry.m_N; i++) {
1288     MarinerWrtTextInternal::Font font;
1289     f.str("");
1290     ascFile.addPos(dataList[d].m_filePos);
1291 
1292     size_t fD = d;
1293     long val;
1294     uint32_t fFlags=0;
1295     for (int j = 0; j < 77; j++) {
1296       MarinerWrtStruct const &dt = dataList[d++];
1297       if (!dt.isBasic()) continue;
1298       unsigned char color[3];
1299       switch (j) {
1300       case 0:
1301         font.m_localId=static_cast<int>(dt.value(0));
1302         break;
1303       case 1: // 0|1
1304       case 2: // 0
1305       case 3: // small number
1306       case 4: // 0|..|10
1307       case 5: // 0|1|2
1308       case 6: // 0
1309       case 8: // small number or 1001,1002
1310       case 17: // small number between 4 && 39
1311       case 19: // 0
1312       case 20: // 0|1|3|5
1313       case 21: // 0
1314       case 22: // 0
1315       case 30: // small number between 0 or 0x3a9 ( a dim?)
1316       case 66: // 0|1
1317       case 74: // 0|1|2|3
1318         if (dt.value(0))
1319           f << "f" << j << "=" << dt.value(0) << ",";
1320         break;
1321       case 7:  // 0, 1000, 100000, 102004
1322         if (dt.value(0))
1323           f << "fl0=" << std::hex << dt.value(0) << std::dec << ",";
1324         break;
1325       case 9:
1326       case 10:
1327       case 11:
1328         color[0]=color[1]=color[2]=0;
1329         color[j-9]=static_cast<unsigned char>(dt.value(0)>>8);
1330         while (j < 11)
1331           color[++j-9] = static_cast<unsigned char>(dataList[d++].value(0));
1332         font.m_font.setColor(MWAWColor(color[0],color[1],color[2]));
1333         break;
1334       case 12: // big number
1335       case 16: // 0 or one time 0x180
1336         if (dt.value(0))
1337           f << "f" << j << "=" << std::hex << dt.value(0) << std::dec << ",";
1338         break;
1339       case 13:
1340       case 14:
1341       case 15:
1342         color[0]=color[1]=color[2]=0xFF;
1343         color[j-13]=static_cast<unsigned char>(dt.value(0)>>8);
1344         while (j < 15)
1345           color[++j-13] = static_cast<unsigned char>(dataList[d++].value(0)>>8);
1346         font.m_font.setBackgroundColor(MWAWColor(color[0],color[1],color[2]));
1347         break;
1348       case 18: {
1349         val = dt.value(0);
1350         font.m_font.setSize(float(val)/65536.f);
1351         break;
1352       }
1353       case 23: // kern
1354         if (dt.value(0))
1355           font.m_font.setDeltaLetterSpacing(float(dt.value(0))/65536.f);
1356         break;
1357       case 24: // 0
1358       case 25: // 0
1359       case 27: // 0
1360       case 29: // 0
1361       case 32: // 0
1362       case 33: // 0
1363       case 35: // 0
1364         if (dt.value(0))
1365           f << "f" << j << "=" << dt.value(0) << ",";
1366         break;
1367       case 26: // 0|very big number id f28
1368       case 28: // 0|very big number
1369       case 31: // 0|very big number
1370       case 34: // an id?
1371         if (!dt.value(0))
1372           break;
1373         switch (j) {
1374         case 28:
1375           f << "idA";
1376           break;
1377         case 31:
1378           f << "idB";
1379           break;
1380         default:
1381           f << "f" << j;
1382           break;
1383         }
1384         f << "=" << std::hex << int32_t(dt.value(0)) << std::dec << ",";
1385         break;
1386       // tokens
1387       case 36: // 0|1|6 related to token?
1388         if (dt.value(0))
1389           f << "tok0=" << dt.value(0) << ",";
1390         break;
1391       case 37: // another id?
1392         if (dt.value(0))
1393           f << "tok1=" << std::hex << dt.value(0) << std::dec << ",";
1394         break;
1395       case 38:
1396         font.m_tokenId = dt.value(0);
1397         break;
1398       case 39:
1399       case 40:
1400       case 41:
1401       case 42:
1402       case 43:
1403       case 44:
1404       case 45:
1405       case 46:
1406       case 47:
1407       case 48:
1408       case 49:
1409       case 50:
1410       case 54:
1411       case 55:
1412       case 56:
1413       case 57:
1414       case 58:
1415         if (int16_t(dt.value(0))==-1) {
1416           switch (j) {
1417           case 39:
1418             fFlags |= MWAWFont::boldBit;
1419             break;
1420           case 40:
1421             fFlags |= MWAWFont::italicBit;
1422             break;
1423           case 41:
1424             font.m_font.setUnderlineStyle(MWAWFont::Line::Simple);
1425             break;
1426           case 42:
1427             fFlags |= MWAWFont::outlineBit;
1428             break;
1429           case 43:
1430             fFlags |= MWAWFont::shadowBit;
1431             break;
1432           case 44:
1433             font.m_font.setDeltaLetterSpacing(-1);
1434             break;
1435           case 45:
1436             font.m_font.setDeltaLetterSpacing(1);
1437             break;
1438           case 46:
1439             font.m_font.setUnderlineStyle(MWAWFont::Line::Simple);
1440             font.m_font.setUnderlineType(MWAWFont::Line::Double);
1441             break;
1442           case 47:
1443             font.m_font.setUnderlineStyle(MWAWFont::Line::Simple);
1444             font.m_font.setUnderlineWordFlag(true);
1445             break;
1446           case 48:
1447             font.m_font.setUnderlineStyle(MWAWFont::Line::Dot);
1448             break;
1449           case 49:
1450             fFlags |= MWAWFont::hiddenBit;
1451             break;
1452           case 50:
1453             font.m_font.setStrikeOutStyle(MWAWFont::Line::Simple);
1454             break;
1455           case 54:
1456             fFlags |= MWAWFont::uppercaseBit;
1457             break;
1458           case 55:
1459             fFlags |= MWAWFont::lowercaseBit;
1460             break;
1461           case 56:
1462             fFlags |= MWAWFont::smallCapsBit;
1463             break;
1464           case 57:
1465             font.m_font.setOverline(font.m_font.getUnderline());
1466             font.m_font.setUnderline(MWAWFont::Line());
1467             break;
1468           case 58:
1469             fFlags |= MWAWFont::boxedBit;
1470             break;
1471           default:
1472             MWAW_DEBUG_MSG(("MarinerWrtText::readFonts: find unknown font flag: %d\n", j));
1473             f << "#f" << j << ",";
1474             break;
1475           }
1476         }
1477         else if (dt.value(0))
1478           f << "#f" << j << "=" << dt.value(0) << ",";
1479         break;
1480       case 51:
1481         if (dt.value(0) > 0)
1482           font.m_font.set(MWAWFont::Script(float(dt.value(0)),librevenge::RVNG_POINT));
1483         else if (dt.value(0))
1484           f << "#superscript=" << dt.value(0) << ",";
1485         break;
1486       case 52:
1487         if (dt.value(0) > 0)
1488           font.m_font.set(MWAWFont::Script(float(-dt.value(0)),librevenge::RVNG_POINT));
1489         else if (dt.value(0))
1490           f << "#subscript=" << dt.value(0) << ",";
1491         break;
1492       case 59:
1493         if (dt.value(0))
1494           font.m_font.set(MWAWFont::Script(float(dt.value(0))/3.0f,librevenge::RVNG_POINT,58));
1495         break;
1496       default:
1497         if (dt.value(0))
1498           f << "#f" << j << "=" << dt.value(0) << ",";
1499         break;
1500       }
1501     }
1502     font.m_font.setFlags(fFlags);
1503     // the error
1504     d = fD;
1505     for (int j = 0; j < 77; j++, d++) {
1506       if (!dataList[d].isBasic())
1507         f << "#f" << j << "=" << dataList[d] << ",";
1508     }
1509     zone.m_fontList.push_back(font);
1510 
1511     font.m_extra = f.str();
1512     f.str("");
1513     f << entry.name() << "-F" << i << ":"
1514       << font.m_font.getDebugString(m_parserState->m_fontConverter) << font;
1515     ascFile.addNote(f.str().c_str());
1516   }
1517   input->seek(entry.end(), librevenge::RVNG_SEEK_SET);
1518   return true;
1519 }
1520 
1521 ////////////////////////////////////////////////////////////
1522 //     Style
1523 ////////////////////////////////////////////////////////////
readStyleNames(MarinerWrtEntry const & entry,int)1524 bool MarinerWrtText::readStyleNames(MarinerWrtEntry const &entry, int)
1525 {
1526   if (entry.length() < entry.m_N) {
1527     MWAW_DEBUG_MSG(("MarinerWrtText::readStyleNames: data seems to short\n"));
1528     return false;
1529   }
1530 
1531   MWAWInputStreamPtr &input= m_parserState->m_input;
1532   input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
1533   input->pushLimit(entry.end());
1534   std::vector<MarinerWrtStruct> dataList;
1535   m_mainParser->decodeZone(dataList,1+2*entry.m_N);
1536   input->popLimit();
1537 
1538   if (int(dataList.size()) != 2*entry.m_N) {
1539     MWAW_DEBUG_MSG(("MarinerWrtText::readStyleNames: find unexpected number of data\n"));
1540     return false;
1541   }
1542 
1543   libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
1544   libmwaw::DebugStream f;
1545   size_t d = 0;
1546   for (int i = 0; i < entry.m_N; i++) {
1547     f.str("");
1548     f << entry.name() << "-" << i << ":";
1549     ascFile.addPos(dataList[d].m_filePos);
1550     if (!dataList[d].isBasic()) {
1551       MWAW_DEBUG_MSG(("MarinerWrtText::readStyleNames: bad id field for style %d\n", i));
1552       f << "###" << dataList[d] << ",";
1553     }
1554     else
1555       f << "id=" << dataList[d].value(0) << ",";
1556     d++;
1557 
1558     std::string name("");
1559     MarinerWrtStruct const &data = dataList[d++];
1560     if (data.m_type!=0 || !data.m_pos.valid()) {
1561       MWAW_DEBUG_MSG(("MarinerWrtText::readStyleNames: name %d seems bad\n", i));
1562       f << "###" << data << ",";
1563     }
1564     else {
1565       long pos = data.m_pos.begin();
1566       input->seek(pos, librevenge::RVNG_SEEK_SET);
1567       auto fSz = int(input->readULong(1));
1568       if (fSz+1 > data.m_pos.length()) {
1569         MWAW_DEBUG_MSG(("MarinerWrtText::readStyleNames: field name %d seems bad\n", i));
1570         f << data << "[###fSz=" << fSz << ",";
1571       }
1572       else {
1573         for (int c = 0; c < fSz; c++)
1574           name+=char(input->readULong(1));
1575         f << name << ",";
1576       }
1577     }
1578     ascFile.addNote(f.str().c_str());
1579   }
1580   input->seek(entry.end(), librevenge::RVNG_SEEK_SET);
1581   return true;
1582 }
1583 
1584 ////////////////////////////////////////////////////////////
1585 //     Paragraph
1586 ////////////////////////////////////////////////////////////
setProperty(MarinerWrtTextInternal::Paragraph const & ruler)1587 void MarinerWrtText::setProperty(MarinerWrtTextInternal::Paragraph const &ruler)
1588 {
1589   if (!m_parserState->m_textListener) return;
1590   m_parserState->m_textListener->setParagraph(ruler);
1591 }
1592 
readRulers(MarinerWrtEntry const & entry,int zoneId)1593 bool MarinerWrtText::readRulers(MarinerWrtEntry const &entry, int zoneId)
1594 {
1595   if (entry.length() < entry.m_N+1) {
1596     MWAW_DEBUG_MSG(("MarinerWrtText::readRulers: data seems to short\n"));
1597     return false;
1598   }
1599 
1600   MWAWInputStreamPtr &input= m_parserState->m_input;
1601   input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
1602   input->pushLimit(entry.end());
1603   std::vector<MarinerWrtStruct> dataList;
1604   m_mainParser->decodeZone(dataList,1+3*68*entry.m_N);
1605   input->popLimit();
1606 
1607   auto numDatas = int(dataList.size());
1608   if (numDatas < 68*entry.m_N) {
1609     MWAW_DEBUG_MSG(("MarinerWrtText::readRulers: find unexpected number of data\n"));
1610     return false;
1611   }
1612 
1613   auto &zone = m_state->getZone(zoneId);
1614   libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile;
1615   libmwaw::DebugStream f;
1616   size_t d = 0;
1617   for (int i = 0; i < entry.m_N; i++) {
1618     MarinerWrtTextInternal::Paragraph para;
1619     if (int(d) < numDatas)
1620       ascFile.addPos(dataList[d].m_filePos);
1621 
1622     if (int(d+68) > numDatas) {
1623       MWAW_DEBUG_MSG(("MarinerWrtText::readRulers: ruler %d is too short\n", i));
1624       f << "###";
1625       ascFile.addNote(f.str().c_str());
1626       return true;
1627     }
1628     size_t fD = d;
1629     unsigned char color[3];
1630     f.str("");
1631     int nTabs = 0;
1632     MWAWFont fontItem(3);
1633     MWAWListLevel level;
1634     for (int j = 0; j < 58; j++, d++) {
1635       MarinerWrtStruct const &dt = dataList[d];
1636       if (!dt.isBasic()) continue;
1637       switch (j) {
1638       case 0:
1639         switch (dt.value(0)) {
1640         case 0:
1641           break;
1642         case 1:
1643           para.m_justify = MWAWParagraph::JustificationCenter;
1644           break;
1645         case 2:
1646           para.m_justify = MWAWParagraph::JustificationRight;
1647           break;
1648         case 3:
1649           para.m_justify = MWAWParagraph::JustificationFull;
1650           break;
1651         case 4:
1652           para.m_justify = MWAWParagraph::JustificationFullAllLines;
1653           break;
1654         default:
1655           f << "#justify=" << dt.value(0) << ",";
1656         }
1657         break;
1658       case 3:
1659       case 4:
1660         para.m_margins[j-2] = double(dt.value(0))/72.;
1661         break;
1662       case 5:
1663         para.m_margins[0] = double(dt.value(0))/72.;
1664         break;
1665       case 6:
1666         if (!dt.value(0)) break;
1667         para.setInterline(double(dt.value(0))/65536., librevenge::RVNG_PERCENT);
1668         break;
1669       case 8:
1670         if (!dt.value(0)) break;
1671         para.setInterline(double(dt.value(0))/65536., librevenge::RVNG_POINT);
1672         break;
1673       case 9:
1674         if (!dt.value(0)) break;
1675         if (dt.value(0)<0) {
1676           MWAW_DEBUG_MSG(("MarinerWrtText::readRulers: find negative interline\n"));
1677           f << "#inteline=" << dt.value(0) << "[at least],";
1678         }
1679         else
1680           para.setInterline(double(dt.value(0)), librevenge::RVNG_POINT, MWAWParagraph::AtLeast);
1681         break;
1682       case 10:
1683         if (!dt.value(0)) break;
1684         para.m_spacings[1] = double(dt.value(0))/72.;
1685         break;
1686       case 11:
1687         if (!dt.value(0)) break;
1688         para.m_spacings[2] = double(dt.value(0))/72.;
1689         break;
1690       case 1: // always 0
1691       case 2: // small number between -15 and 15
1692       case 7: // always 0
1693         if (dt.value(0))
1694           f << "f" << j << "=" << dt.value(0) << ",";
1695         break;
1696       case 23: // big number related to fonts f28?
1697       case 24: // big number related to fonts f31?
1698         if (dt.value(0))
1699           f << "id" << char('A'+(j-23)) << "=" << std::hex << int32_t(dt.value(0)) << std::dec << ",";
1700         break;
1701       case 22: // find 1|2|4
1702         if (dt.value(0) != 1)
1703           f << "#f22=" << dt.value(0) << ",";
1704         break;
1705       //item properties
1706       case 27: {
1707         if (!dt.value(0))
1708           break;
1709         auto fId = int(uint32_t(dt.value(0)>>16));
1710         if (fId) fontItem.setId(fId);
1711         auto fSz = int(uint32_t(dt.value(0)&0xFFFF));
1712         if (fSz) fontItem.setSize(float(uint32_t(dt.value(0)&0xFFFF)));
1713         f << "itemFont=[id=" << fId << ", sz=" << fSz << "],";
1714         break;
1715       }
1716       case 28: {
1717         if (!dt.value(0))
1718           break;
1719         auto strNum=static_cast<uint32_t>(dt.value(0));
1720         unsigned char str[4];
1721         for (int depl=24, k=0; k < 4; k++, depl-=8)
1722           str[k]=static_cast<unsigned char>(strNum>>depl);
1723         unsigned char const *strPtr=str;
1724         auto sz=int(*strPtr++);
1725         if (sz<=0 || sz>3 || !str[1]) {
1726           MWAW_DEBUG_MSG(("MarinerWrtText::readRulers: can not read bullet\n"));
1727           f << "#bullet=" << std::hex << strNum << std::dec << ",";
1728           break;
1729         }
1730         unsigned char c=*strPtr++;
1731         int unicode = m_parserState->m_fontConverter->unicode(3, c, strPtr, sz-1);
1732         if (unicode==-1)
1733           libmwaw::appendUnicode(c, level.m_bullet);
1734         else
1735           libmwaw::appendUnicode(static_cast<uint32_t>(unicode), level.m_bullet);
1736         break;
1737       }
1738       case 29: // 0|5|6|30|64
1739         if (!dt.value(0))
1740           break;
1741         switch (dt.value(0)&3) {
1742         case 0:
1743           break;
1744         case 1:
1745           level.m_alignment=MWAWListLevel::CENTER;
1746           break;
1747         case 2:
1748           level.m_alignment=MWAWListLevel::RIGHT;
1749           break;
1750         default:
1751           f << "#align[item]=3,";
1752           break;
1753         }
1754         if (dt.value(0)>>2)
1755           f << "f29[high]=" << std::hex << (int32_t(dt.value(0))>>2) << std::dec << ",";
1756         break;
1757       case 30:
1758         level.m_labelWidth=double(dt.value(0))/72.0;
1759         break;
1760       // cell properties
1761       case 40:
1762         para.m_cellWidth = static_cast<int>(dt.value(0));
1763         break;
1764       case 41:
1765         para.m_cellHeight = static_cast<int>(dt.value(0));
1766         break;
1767       case 42:
1768         para.m_cellSep = static_cast<int>(dt.value(0));
1769         break;
1770       // border fill properties:
1771       case 19:
1772         para.m_paraFill.m_patternId= static_cast<int>(dt.value(0));
1773         break;
1774       case 55:
1775         para.m_cellFill.m_patternId= static_cast<int>(dt.value(0));
1776         break;
1777       case 15:
1778       case 16:
1779       case 17: // border para color
1780       case 31:
1781       case 32:
1782       case 33: // foreground para color
1783       case 35:
1784       case 36:
1785       case 37: // background para color
1786       case 43:
1787       case 44:
1788       case 45: // table border color
1789       case 47:
1790       case 48:
1791       case 49: // table background color
1792       case 51:
1793       case 52:
1794       case 53: { // table foreground color
1795         int debInd=-1;
1796         unsigned char defValue=0;
1797         if (j>=15&&j<=17)
1798           debInd=15;
1799         else if (j>=31&&j<=33)
1800           debInd=31;
1801         else if (j>=35&&j<=37) {
1802           debInd=35;
1803           defValue=0xFF;
1804         }
1805         else if (j>=43&&j<=45)
1806           debInd=43;
1807         else if (j>=47&&j<=49) {
1808           debInd=47;
1809           defValue=0xFF;
1810         }
1811         else if (j>=51&&j<=53)   // table foreground color
1812           debInd=51;
1813         // coverity[dead_error_line : FALSE]: intended as sanity check
1814         else {
1815           MWAW_DEBUG_MSG(("MarinerWrtText::readRulers: find unknown color idx\n"));
1816           f << "#col[debIndex=" << j << ",";
1817           break;
1818         }
1819 
1820         color[0]=color[1]=color[2]=defValue;
1821         color[j-debInd]=static_cast<unsigned char>(dt.value(0)>>8);
1822         while (j < debInd+2)
1823           color[++j-debInd] = static_cast<unsigned char>(dataList[++d].value(0)>>8);
1824         MWAWColor col(color[0],color[1],color[2]);
1825         switch (debInd) {
1826         case 15:
1827           para.m_paraFill.m_borderColor=col;
1828           break;
1829         case 31:
1830           para.m_paraFill.m_foreColor=col;
1831           break;
1832         case 35:
1833           para.m_paraFill.m_backColor=col;
1834           break;
1835         case 43:
1836           para.m_cellFill.m_borderColor=col;
1837           break;
1838         case 47:
1839           para.m_cellFill.m_backColor=col;
1840           break;
1841         case 51:
1842           para.m_cellFill.m_foreColor=col;
1843           break;
1844         default:
1845           MWAW_DEBUG_MSG(("MarinerWrtText::readRulers: find unknown color idx\n"));
1846           f << "#col[debIndex]=" << col << ",";
1847           break;
1848         }
1849         break;
1850       }
1851       case 14: // para border
1852       case 56: { // cell border
1853         auto &fill=(j==14) ? para.m_paraFill : para.m_cellFill;
1854         long val = dt.value(0);
1855         for (int b = 0, depl=0; b < 4; b++,depl+=8)
1856           fill.m_borderTypes[b] = int((val>>depl)&0xFF);
1857         break;
1858       }
1859       case 57:
1860         nTabs = static_cast<int>(dt.value(0));
1861         break;
1862       default:
1863         if (dt.value(0))
1864           f << "#f" << j << "=" << dt.value(0) << ",";
1865         break;
1866       }
1867     }
1868     d = fD;
1869     for (int j = 0; j < 58; j++, d++) {
1870       if (!dataList[d].isBasic())
1871         f << "#f" << j << "=" << dataList[d].isBasic() << ",";
1872     }
1873     if (nTabs < 0 || int(d)+4*long(nTabs)+10 > numDatas) {
1874       MWAW_DEBUG_MSG(("MarinerWrtText::readRulers: can not read numtabs\n"));
1875       para.m_extra = f.str();
1876       f.str("");
1877       f << entry.name() << "-P" << i << ":" << para << "," << "###";
1878       ascFile.addNote(f.str().c_str());
1879       zone.m_rulerList.push_back(para);
1880       return true;
1881     }
1882     if (nTabs) {
1883       for (int j = 0; j < nTabs; j++) {
1884         MWAWTabStop tab;
1885         for (int k = 0; k < 4; k++, d++) {
1886           MarinerWrtStruct const &dt = dataList[d];
1887           if (!dt.isBasic()) {
1888             f << "#tabs" << j << "[" << k << "]=" << dt << ",";
1889             continue;
1890           }
1891           switch (k) {
1892           case 0:
1893             switch (dt.value(0)) {
1894             case 1:
1895               break;
1896             case 2:
1897               tab.m_alignment = MWAWTabStop::CENTER;
1898               break;
1899             case 3:
1900               tab.m_alignment = MWAWTabStop::RIGHT;
1901               break;
1902             case 4:
1903               tab.m_alignment = MWAWTabStop::DECIMAL;
1904               break;
1905             default:
1906               f << "#tabAlign" << j << "=" << dt.value(0) << ",";
1907               break;
1908             }
1909             break;
1910           case 1:
1911             tab.m_position = double(dt.value(0))/72.;
1912             break;
1913           case 2:
1914             if (dt.value(0)) {
1915               int unicode= m_parserState->m_fontConverter->unicode(3, static_cast<unsigned char>(dt.value(0)));
1916               if (unicode==-1)
1917                 tab.m_leaderCharacter =uint16_t(dt.value(0));
1918               else
1919                 tab.m_leaderCharacter = uint16_t(unicode);
1920             }
1921             break;
1922           default:
1923             if (dt.value(0))
1924               f << "#tabs" << j << "[" << 3 << "]=" << dt.value(0) << ",";
1925             break;
1926           }
1927         }
1928         para.m_tabs->push_back(tab);
1929       }
1930     }
1931     for (int j = 0; j < 10; j++, d++) {
1932       MarinerWrtStruct const &dt = dataList[d];
1933       if (j==1 && dt.m_type==0) { // a block with sz=40
1934         input->seek(dt.m_pos.begin(), librevenge::RVNG_SEEK_SET);
1935         auto fSz = static_cast<int>(input->readULong(1));
1936         if (fSz+1>dt.m_pos.length()) {
1937           MWAW_DEBUG_MSG(("MarinerWrtText::readRulers: can not read paragraph name\n"));
1938           f << "#name,";
1939           continue;
1940         }
1941         if (fSz == 0) continue;
1942         std::string name("");
1943         for (int k = 0; k < fSz; k++)
1944           name+=char(input->readULong(1));
1945         f << "name=" << name << ",";
1946         continue;
1947       }
1948       if (!dt.isBasic() || j==1) {
1949         f << "#g" << j << "=" << dt << ",";
1950         continue;
1951       }
1952       switch (j) {
1953       case 0: // always 36 ?
1954         if (dt.value(0)!=36)
1955           f << "#g0=" << dt.value(0) << ",";
1956         break;
1957       case 4: { // find also flag&0x80
1958         long val = dt.value(0);
1959         if (val & 0x1000) {
1960           val &= 0xFFFFEFFF;
1961 
1962           level.m_type = MWAWListLevel::BULLET;
1963           if (!level.m_bullet.len())
1964             libmwaw::appendUnicode(0x2022, level.m_bullet);
1965           std::shared_ptr<MWAWList> list;
1966           list = m_parserState->m_listManager->getNewList(list, 1, level);
1967           if (!list) {
1968             MWAW_DEBUG_MSG(("MarinerWrtText::readRulers: can create a listn for bullet\n"));
1969             f << "###";
1970             break;
1971           }
1972 
1973           para.m_listLevelIndex = 1;
1974           para.m_listId=list->getId();
1975 
1976           // we must update the margins:
1977           para.m_margins[1]=*para.m_margins[0]+*para.m_margins[1];
1978           para.m_margins[0]=0;
1979         }
1980         if (val&0x4000) {
1981           val &= 0xFFFFDFFF;
1982           f << "hasBackborder,";
1983         }
1984         else
1985           para.m_paraFill.resetBorders();
1986         if (val&0x4000) {
1987           val &= 0xFFFFBFFF;
1988           f << "hasBackground,";
1989         }
1990         else
1991           para.m_paraFill.resetBackgroundColor();
1992         if (val)
1993           f << "flag?=" << std::hex << val << std::dec << ",";
1994         break;
1995       }
1996       case 7: // 1|3|de
1997       case 8: // 0|4 : 4 for header entry?
1998         if (dt.value(0))
1999           f << "g" << j << "=" << dt.value(0) << ",";
2000         break;
2001       default:
2002         if (dt.value(0))
2003           f << "#g" << j << "=" << dt.value(0) << ",";
2004         break;
2005       }
2006     }
2007     para.m_extra = f.str();
2008     para.update(m_mainParser->getPatternPercent(para.m_paraFill.m_patternId));
2009     zone.m_rulerList.push_back(para);
2010     f.str("");
2011     f << entry.name() << "-P" << i << ":" << para << ",";
2012     ascFile.addNote(f.str().c_str());
2013   }
2014   input->seek(entry.end(), librevenge::RVNG_SEEK_SET);
2015   return true;
2016 }
2017 
2018 ////////////////////////////////////////////////////////////
2019 //     the token
2020 ////////////////////////////////////////////////////////////
2021 
2022 ////////////////////////////////////////////////////////////
2023 //     the sections
2024 ////////////////////////////////////////////////////////////
2025 
2026 ////////////////////////////////////////////////////////////
2027 //
2028 // Low level
2029 //
2030 ////////////////////////////////////////////////////////////
2031 
2032 //! send data to the listener
2033 
flushExtra()2034 void MarinerWrtText::flushExtra()
2035 {
2036   if (!m_parserState->m_textListener) return;
2037 #ifdef DEBUG
2038   for (auto it : m_state->m_textZoneMap) {
2039     if (it.second.m_parsed)
2040       continue;
2041     send(it.first);
2042   }
2043 #endif
2044 }
2045 
2046 // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab:
2047