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 ¶);
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 ¶)
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