Coverage Report

Created: 2026-09-14 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/DrawTableParser.cxx
Line
Count
Source
1
/* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */
2
3
/* libmwaw
4
* Version: MPL 2.0 / LGPLv2+
5
*
6
* The contents of this file are subject to the Mozilla Public License Version
7
* 2.0 (the "License"); you may not use this file except in compliance with
8
* the License or as specified alternatively below. You may obtain a copy of
9
* the License at http://www.mozilla.org/MPL/
10
*
11
* Software distributed under the License is distributed on an "AS IS" basis,
12
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13
* for the specific language governing rights and limitations under the
14
* License.
15
*
16
* Major Contributor(s):
17
* Copyright (C) 2002 William Lachance (wrlach@gmail.com)
18
* Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net)
19
* Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
20
* Copyright (C) 2006, 2007 Andrew Ziem
21
* Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr)
22
*
23
*
24
* All Rights Reserved.
25
*
26
* For minor contributions see the git repository.
27
*
28
* Alternatively, the contents of this file may be used under the terms of
29
* the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
30
* in which case the provisions of the LGPLv2+ are applicable
31
* instead of those above.
32
*/
33
34
#include <cmath>
35
#include <iomanip>
36
#include <iostream>
37
#include <limits>
38
#include <sstream>
39
#include <stack>
40
#include <utility>
41
42
#include <librevenge/librevenge.h>
43
44
#include "MWAWFontConverter.hxx"
45
#include "MWAWGraphicListener.hxx"
46
#include "MWAWGraphicShape.hxx"
47
#include "MWAWGraphicStyle.hxx"
48
#include "MWAWHeader.hxx"
49
#include "MWAWParagraph.hxx"
50
#include "MWAWPictBitmap.hxx"
51
#include "MWAWPictData.hxx"
52
#include "MWAWPrinter.hxx"
53
#include "MWAWPosition.hxx"
54
#include "MWAWRSRCParser.hxx"
55
#include "MWAWStringStream.hxx"
56
#include "MWAWSubDocument.hxx"
57
58
#include "DrawTableParser.hxx"
59
60
/** Internal: the structures of a DrawTableParser */
61
namespace DrawTableParserInternal
62
{
63
64
////////////////////////////////////////
65
//! Internal: the state of a DrawTableParser
66
struct State {
67
  //! constructor
68
  State()
69
2.54k
    : m_openedGroup(0)
70
2.54k
    , m_patternList()
71
2.54k
    , m_maxDim(0,0)
72
2.54k
  {
73
2.54k
  }
74
75
  //! try to return a color
76
  MWAWColor getColor(int id) const;
77
  //! try to init a patterns
78
  bool getPattern(int id, MWAWGraphicStyle::Pattern &pat) const;
79
  //! init the patterns list
80
  void initPatterns();
81
  //! the number of opened groups
82
  int m_openedGroup;
83
  //! the patterns list
84
  std::vector<MWAWGraphicStyle::Pattern> m_patternList;
85
  //! the max dimensions
86
  MWAWVec2f m_maxDim;
87
};
88
89
MWAWColor State::getColor(int id) const
90
1.00k
{
91
1.00k
  if (id<0 || id>=8) {
92
631
    MWAW_DEBUG_MSG(("DrawTableParserInternal::State::getColor: unknown color %d\n", id));
93
631
    return MWAWColor::white();
94
631
  }
95
375
  MWAWColor const colors[]= {
96
375
    MWAWColor::white(), MWAWColor::black(), MWAWColor(255,0,0), MWAWColor(0,255,0),
97
375
    MWAWColor(0,0,255), MWAWColor(0,255,255), MWAWColor(255,0,255), MWAWColor(255,255,0)
98
375
  };
99
375
  return colors[id];
100
1.00k
}
101
102
bool State::getPattern(int id, MWAWGraphicStyle::Pattern &pat) const
103
356
{
104
356
  if (m_patternList.empty())
105
143
    const_cast<State *>(this)->initPatterns();
106
356
  if (id<0 || id>=int(m_patternList.size())) {
107
142
    MWAW_DEBUG_MSG(("DrawTableParserInternal::State::getPattern: unknown pattern %d\n", id));
108
142
    return false;
109
142
  }
110
214
  pat=m_patternList[size_t(id)];
111
214
  return true;
112
356
}
113
114
void State::initPatterns()
115
143
{
116
143
  if (!m_patternList.empty()) return;
117
143
  static uint16_t const patterns[]= {
118
143
    0x0, 0x0, 0x0, 0x0, 0xffff, 0xffff, 0xffff, 0xffff, 0x77dd, 0x77dd, 0x77dd, 0x77dd, 0xaa55, 0xaa55, 0xaa55, 0xaa55,
119
143
    0x8822, 0x8822, 0x8822, 0x8822, 0x8800, 0x2200, 0x8800, 0x2200, 0x8000, 0x800, 0x8000, 0x800, 0x8000, 0x0, 0x800, 0x0,
120
143
    0x8080, 0x413e, 0x808, 0x14e3, 0xff80, 0x8080, 0xff08, 0x808, 0x8142, 0x2418, 0x8142, 0x2418, 0x8040, 0x2010, 0x804, 0x201,
121
143
    0xe070, 0x381c, 0xe07, 0x83c1, 0x77bb, 0xddee, 0x77bb, 0xddee, 0x8844, 0x2211, 0x8844, 0x2211, 0x99cc, 0x6633, 0x99cc, 0x6633,
122
143
    0x2040, 0x8000, 0x804, 0x200, 0xff00, 0xff00, 0xff00, 0xff00, 0xff00, 0x0, 0xff00, 0x0, 0xcc00, 0x0, 0x3300, 0x0,
123
143
    0xf0f0, 0xf0f0, 0xf0f, 0xf0f, 0xff88, 0x8888, 0xff88, 0x8888, 0xaa44, 0xaa11, 0xaa44, 0xaa11, 0x102, 0x408, 0x1020, 0x4080,
124
143
    0x8307, 0xe1c, 0x3870, 0xe0c1, 0xeedd, 0xbb77, 0xeedd, 0xbb77, 0x1122, 0x4488, 0x1122, 0x4488, 0x3366, 0xcc99, 0x3366, 0xcc99,
125
143
    0x40a0, 0x0, 0x40a, 0x0, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, 0x8888, 0x8888, 0x8888, 0x8888, 0x101, 0x1010, 0x101, 0x1010,
126
143
    0x8, 0x142a, 0x552a, 0x1408, 0xff80, 0x8080, 0x8080, 0x8080, 0x8244, 0x2810, 0x2844, 0x8201, 0x0, 0x0, 0x0, 0x0,
127
143
    0x8000, 0x0, 0x0, 0x0, 0x8000, 0x0, 0x800, 0x0, 0x8800, 0x0, 0x800, 0x0, 0x8800, 0x0, 0x8800, 0x0,
128
143
    0x8800, 0x2000, 0x8800, 0x0, 0x8800, 0x2000, 0x8800, 0x200, 0x8800, 0x2200, 0x8800, 0x2200, 0xa800, 0x2200, 0x8a00, 0x2200,
129
143
    0xaa00, 0x2200, 0xaa00, 0x2200, 0xaa00, 0xa200, 0xaa00, 0x2a00, 0xaa00, 0xaa00, 0xaa00, 0xaa00, 0xaa40, 0xaa00, 0xaa04, 0xaa00,
130
143
    0xaa44, 0xaa00, 0xaa44, 0xaa00, 0xaa44, 0xaa10, 0xaa44, 0xaa01, 0xaa44, 0xaa11, 0xaa44, 0xaa11, 0xaa54, 0xaa11, 0xaa45, 0xaa11,
131
143
    0xaa55, 0xaa11, 0xaa55, 0xaa11, 0xaa55, 0xaa51, 0xaa55, 0xaa15, 0xaa55, 0xaa55, 0xaa55, 0xaa55, 0xea55, 0xaa55, 0xae55, 0xaa55,
132
143
    0xee55, 0xaa55, 0xee55, 0xaa55, 0xee55, 0xba55, 0xee55, 0xab55, 0xee55, 0xbb55, 0xee55, 0xbb55, 0xfe55, 0xbb55, 0xef55, 0xbb55,
133
143
    0xff55, 0xbb55, 0xff55, 0xbb55, 0xff55, 0xfb55, 0xff55, 0xbf55, 0xff55, 0xff55, 0xff55, 0xff55, 0xffd5, 0xff55, 0xff5d, 0xff55,
134
143
    0xffdd, 0xff55, 0xffdd, 0xff55, 0xffdd, 0xff75, 0xffdd, 0xff57, 0xffdd, 0xff77, 0xffdd, 0xff77, 0xfffd, 0xff77, 0xffdf, 0xff77,
135
143
    0xffff, 0xff77, 0xffff, 0xff77, 0xffff, 0xfff7, 0xffff, 0xff7f, 0xffff, 0xffff, 0xffff, 0xffff, 0x81c3, 0x8100, 0x183c, 0x1800,
136
143
    0xffff, 0x0, 0xffff, 0x0, 0x1122, 0x2211, 0x1188, 0x8811, 0xbb00, 0x0, 0xee00, 0x0, 0xa55a, 0xa545, 0x45ba, 0x45ba,
137
143
    0x82c7, 0x10, 0x287c, 0x1, 0xe7db, 0x9966, 0x6699, 0xdbe7, 0x66, 0x6f0f, 0x3e78, 0x7b33, 0xefef, 0xffef, 0xefef, 0x28ef,
138
143
    0x7fd, 0x1b0e, 0x6672, 0x5272, 0xdb66, 0xbddb, 0xbd66, 0xdbbd, 0x525, 0x7525, 0x525, 0x5525, 0xff00, 0x0, 0x4024, 0xa850,
139
143
    0xcccc, 0xcccc, 0xcccc, 0xcccc, 0xbfb0, 0xb0b0, 0xb0bf, 0xbf, 0x6600, 0x99, 0x9900, 0x66, 0x1010, 0x1010, 0x1028, 0xc628,
140
143
    0xe0a0, 0xe000, 0xe0a, 0xe00, 0xebeb, 0xebeb, 0xebeb, 0xebeb, 0xc366, 0x3c66, 0xc366, 0x3c66, 0x8004, 0x2211, 0x8004, 0x2211,
141
143
    0xcf4d, 0xca4d, 0xca4d, 0xcf00, 0x83c6, 0x6c38, 0x180c, 0x603, 0xff, 0x80be, 0xa2aa, 0x2aeb, 0x6dab, 0xd729, 0xd7ab, 0x6dfe,
142
143
    0xaabf, 0xa0bf, 0xaafb, 0xafb, 0x1010, 0x10, 0x1010, 0xd710, 0x18, 0x187e, 0x7e18, 0x1800, 0x82a, 0x1463, 0x142a, 0x880,
143
143
    0x2418, 0x8142, 0x4281, 0x1824, 0xffff, 0xffff, 0xff, 0xff, 0xcc06, 0x3318, 0xcc60, 0x3381, 0x447c, 0x4483, 0x3844, 0xc744,
144
143
    0x2808, 0x3000, 0x0, 0x6080, 0x7e3c, 0x99c3, 0xe7c3, 0x993c, 0x220e, 0x8838, 0x22e0, 0x8883, 0x80be, 0xa2aa, 0xaaba, 0x82fe,
145
143
    0x40, 0x5c5c, 0x5c40, 0x7e00, 0xaa55, 0xaa55, 0x0, 0x0, 0x0, 0x0, 0x40e0, 0x4040, 0x81c, 0x3e7f, 0xf7e3, 0xc180,
146
143
    0x3e7f, 0x7f7f, 0x7f7f, 0x3e80, 0xeaee, 0xeaee, 0xeaee, 0xeaee, 0x10, 0x1, 0x20, 0x4, 0xf68e, 0x7efd, 0xc3bf, 0x7ff8,
147
143
    0x8888, 0x8888, 0x8877, 0x22dd, 0x3800, 0x3800, 0x3800, 0x3800, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xc0c0, 0xc0ff, 0xffc0, 0xc0c0,
148
143
    0xff80, 0x8183, 0x878f, 0x9fbf, 0xa050, 0xa050, 0xa050, 0xa050, 0xd0a0, 0xd0a0, 0xd0bc, 0xf2e1, 0x8310, 0x55, 0x10, 0x8393,
149
143
    0xff00, 0x7755, 0xdd00, 0xff00, 0x182, 0x7c54, 0x7c54, 0x7c82, 0x10, 0x10fe, 0x7c38, 0x6c44, 0x2874, 0xeac5, 0x83c5, 0xea74,
150
143
    0x288, 0x75d8, 0xa8d8, 0x7588, 0x0, 0xaaaa, 0xaa00, 0x0, 0xcccc, 0x3333, 0xcccc, 0x3333, 0x24e7, 0x7e, 0x427e, 0xe7,
151
143
    0x7f1f, 0xdfc7, 0xf7f1, 0xfd7c, 0x4182, 0x50a, 0x1428, 0x50a0, 0x8894, 0x2249, 0x8800, 0xaa00, 0x300, 0x6066, 0x600, 0x3033,
152
143
    0x7744, 0x5c50, 0x7705, 0x1d11, 0xe3dd, 0x3eba, 0x3edd, 0xa3eb, 0x1c1c, 0x14e3, 0xc1e3, 0x141c, 0x2449, 0x9224, 0x9249, 0x2492,
153
143
    0xe724, 0xbd81, 0x7e42, 0xdb18, 0xe000, 0x3800, 0xe00, 0x8300, 0x60, 0x908c, 0x43e0, 0x0
154
143
  };
155
143
  MWAWGraphicStyle::Pattern pat;
156
143
  pat.m_dim=MWAWVec2i(8,8);
157
143
  pat.m_data.resize(8);
158
143
  pat.m_colors[0]=MWAWColor::white();
159
143
  pat.m_colors[1]=MWAWColor::black();
160
143
  m_patternList.push_back(pat); // none pattern
161
162
143
  int numPatterns=int(MWAW_N_ELEMENTS(patterns))/4;
163
143
  uint16_t const *patPtr=patterns;
164
20.5k
  for (int i=0; i<numPatterns; ++i) {
165
102k
    for (size_t j=0; j<8; j+=2, ++patPtr) {
166
81.7k
      pat.m_data[j]=uint8_t((*patPtr)>>8);
167
81.7k
      pat.m_data[j+1]=uint8_t((*patPtr)&0xFF);
168
81.7k
    }
169
20.4k
    m_patternList.push_back(pat);
170
20.4k
  }
171
143
}
172
173
////////////////////////////////////////
174
//! Internal: the subdocument of a DrawTableParser
175
class SubDocument final : public MWAWSubDocument
176
{
177
public:
178
  //! constructor from a zoneId
179
  SubDocument(DrawTableParser &parser, MWAWInputStreamPtr const &input, MWAWEntry const &entry, MWAWFont const &font, MWAWParagraph const &para)
180
385
    : MWAWSubDocument(&parser, input, entry)
181
385
    , m_font(font)
182
385
    , m_para(para)
183
385
  {
184
385
  }
185
186
  //! destructor
187
385
  ~SubDocument() final {}
188
189
  //! the parser function
190
  void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
191
192
protected:
193
  //! the font style
194
  MWAWFont m_font;
195
  //! the paragraph style
196
  MWAWParagraph m_para;
197
private:
198
  SubDocument(SubDocument const &orig) = delete;
199
  SubDocument &operator=(SubDocument const &orig) = delete;
200
};
201
202
void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/)
203
385
{
204
385
  if (!listener || !listener->canWriteText()) {
205
0
    MWAW_DEBUG_MSG(("DrawTableParserInternal::SubDocument::parse: no listener\n"));
206
0
    return;
207
0
  }
208
385
  listener->setFont(m_font);
209
385
  listener->setParagraph(m_para);
210
385
  if (!m_input || !m_zone.valid() || !m_input->checkPosition(m_zone.end()))
211
79
    return;
212
306
  long pos = m_input->tell();
213
306
  m_input->seek(m_zone.begin(), librevenge::RVNG_SEEK_SET);
214
674k
  while (m_input->tell()<m_zone.end() && !m_input->isEnd()) {
215
674k
    unsigned char c=(unsigned char)(m_input->readULong(1));
216
674k
    switch (c) {
217
4.05k
    case 0x9:
218
4.05k
      listener->insertTab();
219
4.05k
      break;
220
4.64k
    case 0xd:
221
4.64k
      if (m_input->tell()<m_zone.end())
222
4.64k
        listener->insertEOL();
223
4.64k
      break;
224
665k
    default:
225
665k
      if (c<=0x1f) {
226
393k
        MWAW_DEBUG_MSG(("DrawTableParserInternal::SubDocument::parse: find unexpected char=%x\n", (unsigned int)(c)));
227
393k
      }
228
272k
      else
229
272k
        listener->insertCharacter(c);
230
674k
    }
231
674k
  }
232
306
  m_input->seek(pos, librevenge::RVNG_SEEK_SET);
233
306
}
234
235
}
236
237
////////////////////////////////////////////////////////////
238
// constructor/destructor, ...
239
////////////////////////////////////////////////////////////
240
DrawTableParser::DrawTableParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header)
241
2.54k
  : MWAWGraphicParser(input, rsrcParser, header)
242
2.54k
  , m_state()
243
2.54k
{
244
2.54k
  resetGraphicListener();
245
2.54k
  setAsciiName("main-1");
246
247
2.54k
  m_state.reset(new DrawTableParserInternal::State);
248
249
2.54k
  getPageSpan().setMargins(0.1);
250
2.54k
}
251
252
DrawTableParser::~DrawTableParser()
253
2.54k
{
254
2.54k
}
255
256
////////////////////////////////////////////////////////////
257
// the parser
258
////////////////////////////////////////////////////////////
259
void DrawTableParser::parse(librevenge::RVNGDrawingInterface *docInterface)
260
984
{
261
984
  if (!getInput().get() || !checkHeader(nullptr))  throw(libmwaw::ParseException());
262
984
  bool ok = false;
263
984
  try {
264
    // create the asciiFile
265
984
    ascii().setStream(getInput());
266
984
    ascii().open(asciiName());
267
268
984
    checkHeader(nullptr);
269
270
984
    ok = createZones();
271
984
    if (ok) {
272
540
      createDocument(docInterface);
273
540
      sendShapes();
274
540
    }
275
984
    ascii().reset();
276
984
  }
277
984
  catch (...) {
278
0
    MWAW_DEBUG_MSG(("DrawTableParser::parse: exception catched when parsing\n"));
279
0
    ok = false;
280
0
  }
281
282
984
  resetGraphicListener();
283
984
  if (!ok) throw(libmwaw::ParseException());
284
984
}
285
286
////////////////////////////////////////////////////////////
287
// create the document
288
////////////////////////////////////////////////////////////
289
void DrawTableParser::createDocument(librevenge::RVNGDrawingInterface *documentInterface)
290
540
{
291
540
  if (!documentInterface) return;
292
540
  if (getGraphicListener()) {
293
0
    MWAW_DEBUG_MSG(("DrawTableParser::createDocument: listener already exist\n"));
294
0
    return;
295
0
  }
296
297
  // create the page list
298
540
  MWAWPageSpan ps(getPageSpan());
299
540
  ps.setPageSpan(1);
300
  // check if the document has multiple pages, if yes increase the page
301
540
  if (ps.getFormLength()>0 && 1.02*ps.getFormLength()*72<m_state->m_maxDim[0]) {
302
98
    int numPageY=int(m_state->m_maxDim[0]/ps.getFormLength()/72)+1;
303
98
    MWAW_DEBUG_MSG(("DrawTableParser::createDocument: increase Y pages to %d\n", numPageY));
304
98
    ps.setFormLength(ps.getFormLength()*(numPageY>10 ? 10 : numPageY));
305
98
  }
306
540
  if (ps.getFormWidth()>0 && 1.02*ps.getFormWidth()*72<m_state->m_maxDim[1]) {
307
147
    int numPageX=int(m_state->m_maxDim[1]/ps.getFormWidth()/72)+1;
308
147
    MWAW_DEBUG_MSG(("DrawTableParser::createDocument: increase X pages to %d\n", numPageX));
309
147
    ps.setFormWidth(ps.getFormWidth()*(numPageX>10 ? 10 : numPageX));
310
147
  }
311
540
  std::vector<MWAWPageSpan> pageList(1,ps);
312
540
  MWAWGraphicListenerPtr listen(new MWAWGraphicListener(*getParserState(), pageList, documentInterface));
313
540
  setGraphicListener(listen);
314
540
  listen->startDocument();
315
540
}
316
317
////////////////////////////////////////////////////////////
318
//
319
// Intermediate level
320
//
321
////////////////////////////////////////////////////////////
322
bool DrawTableParser::createZones()
323
984
{
324
984
  auto input=getInput();
325
984
  if (!input) return false;
326
327
984
  if (!readPrefs() || !readPrintInfo() || !readFonts())
328
71
    return false;
329
330
913
  long pos=input->tell();
331
913
  if (!computeMaxDimension())
332
373
    return false;
333
540
  input->seek(pos, librevenge::RVNG_SEEK_SET);
334
540
  return true;
335
913
}
336
337
bool DrawTableParser::computeMaxDimension()
338
913
{
339
913
  auto input=getInput();
340
913
  int numShapes=0;
341
3.92M
  while (input->checkPosition(input->tell()+10)) {
342
3.92M
    long pos=input->tell();
343
3.92M
    int val=int(input->readULong(2));
344
3.92M
    if (val==0)
345
3.92M
      continue;
346
1.30k
    if (val!=6)
347
536
      break;
348
773
    int type=int(input->readULong(2));
349
773
    if (type<=1 || type>=10)
350
90
      break;
351
683
    input->seek(2, librevenge::RVNG_SEEK_CUR); // flags
352
683
    int headerSz=int(input->readULong(4));
353
683
    long endPos=pos+10+headerSz;
354
683
    if (!input->checkPosition(endPos))
355
37
      break;
356
646
    long dimPos=0;
357
646
    switch (type) {
358
35
    case 2:
359
45
    case 3:
360
45
      dimPos=endPos-8;
361
45
      break;
362
9
    case 4:
363
9
      dimPos=pos+22;
364
9
      break;
365
42
    case 7:
366
465
    case 9:
367
465
      dimPos=endPos-10;
368
465
      break;
369
7
    case 8:
370
7
      dimPos=endPos-16;
371
7
      break;
372
120
    default:
373
120
      break;
374
646
    }
375
646
    if (dimPos>=pos+10 && dimPos+8<=endPos) {
376
463
      input->seek(dimPos, librevenge::RVNG_SEEK_SET);
377
1.38k
      for (int pt=0; pt<2; ++pt) {
378
926
        if (type==4 && pt==1)
379
5
          break;
380
921
        float dim[2];
381
1.84k
        for (auto &d : dim) d=float(input->readLong(2))/10.f;
382
2.76k
        for (int i=0; i<2; ++i) {
383
1.84k
          if (dim[i]>m_state->m_maxDim[i])
384
773
            m_state->m_maxDim[i]=dim[i];
385
1.84k
        }
386
921
      }
387
463
    }
388
646
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
389
646
    int const numData[]= {
390
646
      0, 0, 0, 0, 0,
391
646
      2, 0, 1, 2, 1
392
646
    };
393
646
    bool ok=true;
394
1.16k
    for (int i=0; i<numData[type]; ++i) {
395
574
      pos=input->tell();
396
574
      int dSz=int(input->readULong(2));
397
574
      if (!input->checkPosition(pos+2+dSz)) {
398
56
        ok=false;
399
56
        break;
400
56
      }
401
518
      if (type==5 && i==0 && (dSz%4)==0) {
402
809
        for (int pt=0; pt<(dSz/4); ++pt) {
403
767
          float dim[2];
404
1.53k
          for (auto &d : dim) d=float(input->readLong(2))/10.f;
405
2.30k
          for (int j=0; j<2; ++j) {
406
1.53k
            if (dim[j]>m_state->m_maxDim[j])
407
123
              m_state->m_maxDim[j]=dim[j];
408
1.53k
          }
409
767
        }
410
42
      }
411
518
      input->seek(pos+2+dSz, librevenge::RVNG_SEEK_SET);
412
518
    }
413
646
    if (!ok)
414
56
      break;
415
590
    ++numShapes;
416
590
  }
417
913
  return numShapes>0;
418
913
}
419
420
bool DrawTableParser::readFonts()
421
940
{
422
940
  auto input=getInput();
423
940
  libmwaw::DebugStream f;
424
940
  auto fontConverter=getFontConverter();
425
1.00k
  while (input->checkPosition(input->tell()+6)) {
426
975
    long pos=input->tell();
427
975
    if (input->readULong(2)!=2) {
428
880
      input->seek(pos, librevenge::RVNG_SEEK_SET);
429
880
      return true;
430
880
    }
431
95
    f.str("");
432
95
    f << "Entries(Font):";
433
95
    int dataSz[2];
434
190
    for (auto &d : dataSz) d=int(input->readULong(2));
435
95
    if (dataSz[0]>dataSz[1])
436
30
      std::swap(dataSz[0],dataSz[1]);
437
95
    if (!input->checkPosition(pos+6+dataSz[1])) {
438
27
      MWAW_DEBUG_MSG(("DrawTableParser::readFonts: zone seems too short\n"));
439
27
      f << "###";
440
27
      ascii().addPos(pos);
441
27
      ascii().addNote(f.str().c_str());
442
27
      input->seek(pos, librevenge::RVNG_SEEK_SET);
443
27
      return false;
444
27
    }
445
68
    int type=int(input->readULong(2));
446
68
    bool ok=false;
447
68
    switch (type) {
448
6
    case 0:
449
6
      ok=true;
450
6
      break;
451
16
    case 1: {
452
16
      if (dataSz[0]<3) {
453
10
        MWAW_DEBUG_MSG(("DrawTableParser::readFonts: the data size seems to short\n"));
454
10
        break;
455
10
      }
456
6
      int id=int(input->readULong(2));
457
6
      f << "id=" << id << ",";
458
6
      int dSz=int(input->readULong(1));
459
6
      if (3+dSz>dataSz[0])
460
2
        break;
461
4
      ok=true;
462
4
      std::string name;
463
4
      for (int s=0; s<dSz; ++s) name+=char(input->readULong(1));
464
4
      if (!name.empty())
465
0
        fontConverter->setCorrespondance(id, name);
466
4
      f << name << ",";
467
4
      break;
468
6
    }
469
46
    default:
470
46
      f << "type=" << type << ",";
471
46
      MWAW_DEBUG_MSG(("DrawTableParser::readFonts: unknown type\n"));
472
46
      break;
473
68
    }
474
68
    if (!ok)
475
58
      f << "###";
476
68
    ascii().addPos(pos);
477
68
    ascii().addNote(f.str().c_str());
478
68
    input->seek(pos+6+dataSz[1], librevenge::RVNG_SEEK_SET);
479
68
  }
480
33
  return true;
481
940
}
482
483
bool DrawTableParser::readPrintInfo()
484
2.31k
{
485
2.31k
  auto input=getInput();
486
2.31k
  long pos=input->tell();
487
2.31k
  libmwaw::DebugStream f;
488
2.31k
  f << "Entries(PrintInfo):";
489
2.31k
  auto sz = long(input->readULong(2));
490
2.31k
  if (sz < 0x78 || !input->checkPosition(pos+2+sz)) {
491
141
    MWAW_DEBUG_MSG(("DrawTableParser::readPrintInfo: can not find the print info zone\n"));
492
141
    f << "###";
493
141
    ascii().addPos(pos);
494
141
    ascii().addNote(f.str().c_str());
495
141
    return false;
496
141
  }
497
  // print info
498
2.17k
  libmwaw::PrinterInfo info;
499
2.17k
  if (!info.read(input))
500
1.70k
    f << "###";
501
461
  else {
502
461
    f << info;
503
461
    MWAWVec2i paperSize = info.paper().size();
504
461
    MWAWVec2i pageSize = info.page().size();
505
461
    if (pageSize.x() > 0 && pageSize.y() > 0 && paperSize.x() > 0 && paperSize.y() > 0) {
506
237
      MWAWVec2i lTopMargin= -1 * info.paper().pos(0);
507
237
      MWAWVec2i rBotMargin=info.paper().pos(1) - info.page().pos(1);
508
509
237
      getPageSpan().setMarginTop(lTopMargin.y()<0 ? 0 : lTopMargin.y()/72.0);
510
237
      getPageSpan().setMarginBottom(rBotMargin.y()<0 ? 0 : rBotMargin.y()/72.0);
511
237
      getPageSpan().setMarginLeft(lTopMargin.x()<0 ? 0 : lTopMargin.x()/72.0);
512
237
      getPageSpan().setMarginRight(rBotMargin.y()<0 ? 0 : rBotMargin.y()/72.0);
513
237
      getPageSpan().setFormLength(paperSize.y()/72.);
514
237
      getPageSpan().setFormWidth(paperSize.x()/72.);
515
237
    }
516
461
  }
517
2.17k
  ascii().addPos(pos);
518
2.17k
  ascii().addNote(f.str().c_str());
519
2.17k
  input->seek(pos+2+sz, librevenge::RVNG_SEEK_SET);
520
2.17k
  return true;
521
2.31k
}
522
523
bool DrawTableParser::readPrefs()
524
984
{
525
984
  auto input=getInput();
526
984
  long pos=input->tell();
527
984
  if (!input->checkPosition(pos+172)) {
528
0
    MWAW_DEBUG_MSG(("DrawTableParser::readPrefs: the zone is too short\n"));
529
0
    return false;
530
0
  }
531
984
  libmwaw::DebugStream f;
532
984
  int val;
533
984
  f << "Entries(Prefs):";
534
4.92k
  for (int i=0; i<4; ++i) {
535
3.93k
    val=int(input->readULong(2));
536
3.93k
    int const expected[]= { 0 /* or 1*/, 4 /* 2-4*/, 3, 0xc };
537
3.93k
    if (val==expected[i]) continue;
538
3.17k
    if (i==2)
539
984
      f << "font[id]=" << val << ",";
540
2.18k
    else if (i==3)
541
984
      f << "font[sz]=" << val << ",";
542
1.20k
    else
543
1.20k
      f << "f" << i << "=" << val << ",";
544
3.17k
  }
545
3.93k
  for (int i=0; i<3; ++i) { // f4=0|1
546
2.95k
    val=int(input->readULong(2));
547
2.95k
    if (!val) continue;
548
2.23k
    if (i==0)
549
860
      f << "font[flags]=" << std::hex << val << std::dec << ",";
550
1.37k
    else if (i==1) {
551
704
      if (val&0xff00) f << "align=" << (val>>8) << ",";
552
704
      if (val&0xff) f << "interline=" << float(2+(val&0xff))/2.f << ",";
553
704
    }
554
669
    else
555
669
      f << "f" << i+4 << "=" << val << ",";
556
2.23k
  }
557
2.95k
  for (int i=0; i<2; ++i) { // always 101: an int or two boolean ?
558
1.96k
    val=int(input->readULong(1));
559
1.96k
    if (val==1) continue;
560
1.90k
    if (i==1)
561
970
      f << "font[color]=" << val << ",";
562
939
    else
563
939
      f << "fl" << i << "=" << val << ",";
564
1.90k
  }
565
4.92k
  for (int i=0; i<4; ++i) {
566
3.93k
    val=int(input->readULong(2));
567
3.93k
    int const expected[]= { 10, 1, 2, 1 };
568
3.93k
    if (val!=expected[i]) f << "f" << i+7 << "=" << val << ",";
569
3.93k
  }
570
984
  int dim[2];
571
1.96k
  for (auto &d : dim) d=int(input->readULong(2));
572
984
  if (dim[1]&3) {
573
459
    f << "penSize=" << (dim[0]&0x7fff) << "/" << (dim[1]>>2);
574
459
    if ((dim[1]&3)!=1) f << "[" << (dim[1]&3) << "]";
575
459
    if (dim[0]&0x8000) f << "_dec"; // decimal or frac
576
459
    f << ",";
577
459
  }
578
2.95k
  for (int st=0; st<2; ++st) {
579
1.96k
    f << (st==0 ? "line" : "surf") << "[style]=[";
580
1.96k
    val=int(input->readULong(1));
581
1.96k
    if (val==0)
582
616
      f << "none,";
583
1.35k
    else if (val!=2-st)
584
1.32k
      f << "pat=" << val << ",";
585
5.90k
    for (int i=0; i<2; ++i) { // 0: back, 1: front
586
3.93k
      val=int(input->readULong(1));
587
3.93k
      if (val!=i)
588
3.29k
        f << "col" << i << "=" << val << ",";
589
3.93k
    }
590
1.96k
    input->seek(1, librevenge::RVNG_SEEK_CUR);
591
1.96k
    f << "],";
592
1.96k
  }
593
13.7k
  for (int i=0; i<13; ++i) { // g0=6|15, g4=0|1, g6=g10=1
594
12.7k
    val=int(input->readULong(2));
595
12.7k
    if (val) f << "g" << i << "=" << val << ",";
596
12.7k
  }
597
984
  float fDim[2];
598
1.96k
  for (auto &d : fDim) d=float(input->readLong(2))/10.f;
599
984
  f << "dim=" << MWAWVec2f(fDim[1], fDim[0]) << ",";
600
984
  ascii().addPos(pos);
601
984
  ascii().addNote(f.str().c_str());
602
984
  input->seek(pos+66, librevenge::RVNG_SEEK_SET);
603
604
984
  pos=input->tell();
605
984
  f.str("");
606
984
  f << "Prefs-1:";
607
9.84k
  for (int i=0; i<9; ++i) {
608
8.85k
    val=int(input->readULong(2));
609
8.85k
    int const expected[]= { 0 /* or 1*/, 0, 1, 1, 0 /* or 1*/, 0, 1, 0, 2 };
610
8.85k
    if (val==expected[i]) continue;
611
8.00k
    if (i==5 && val==1)
612
1
      f << "spline,";
613
8.00k
    else
614
8.00k
      f << "f" << i << "=" << val << ",";
615
8.00k
  }
616
10.8k
  for (int i=0; i<10; ++i) { // g1=0|1
617
9.84k
    val=int(input->readULong(2));
618
9.84k
    if (val) f << "g" << i << "=" << val << ",";
619
9.84k
  }
620
984
  val=int(input->readULong(2)); // 0|6|c6e
621
984
  if (val) f << "fl=" << std::hex << val << std::dec << ",";
622
984
  val=int(input->readULong(2)); // 0-2
623
984
  if (val) f << "h0=" << val << ",";
624
1.96k
  for (auto &d : fDim) d=float(input->readLong(2))/10.f;
625
984
  f << "dim=" << MWAWVec2f(fDim[1], fDim[0]) << ","; // unsure two times the same number
626
984
  ascii().addPos(pos);
627
984
  ascii().addNote(f.str().c_str());
628
629
984
  input->seek(pos+46, librevenge::RVNG_SEEK_SET);
630
631
984
  pos=input->tell();
632
984
  f.str("");
633
984
  f << "Prefs-2:";
634
30.5k
  for (int i=0; i<30; ++i) { // f8=0|1 f10=1
635
29.5k
    val=int(input->readULong(2));
636
29.5k
    if (val) f << "f" << i << "=" << val << ",";
637
29.5k
  }
638
984
  ascii().addPos(pos);
639
984
  ascii().addNote(f.str().c_str());
640
641
984
  return true;
642
984
}
643
644
////////////////////////////////////////////////////////////
645
// read the header
646
////////////////////////////////////////////////////////////
647
bool DrawTableParser::checkHeader(MWAWHeader *header, bool strict)
648
3.52k
{
649
3.52k
  MWAWInputStreamPtr input = getInput();
650
3.52k
  if (!input || !input->hasDataFork() || !input->checkPosition(316))
651
141
    return false;
652
653
3.38k
  libmwaw::DebugStream f;
654
3.38k
  input->seek(0, librevenge::RVNG_SEEK_SET);
655
3.38k
  if (input->readULong(2)!=0xc || input->readULong(2)!=0x1357)
656
0
    return false;
657
3.38k
  f << "FileHeader:";
658
3.38k
  int const vers=1;
659
3.38k
  setVersion(vers);
660
3.38k
  if (header)
661
1.41k
    header->reset(MWAWDocument::MWAW_T_DRAWINGTABLE, vers, MWAWDocument::MWAW_K_DRAW);
662
23.6k
  for (int i=0; i<6; ++i) { // checkme: f0=f2 some file's version?
663
20.3k
    int const expected[]= {0x13 /* or 14*/, 0, 0x13 /* or 14*/, 2, 2, 0xac};
664
20.3k
    int val=int(input->readLong(2));
665
20.3k
    if (val!=expected[i])
666
13.8k
      f << "f" << i << "=" << val << ",";
667
20.3k
  }
668
3.38k
  if (strict) {
669
1.32k
    long pos=input->tell();
670
1.32k
    input->seek(0xbc, librevenge::RVNG_SEEK_SET);
671
1.32k
    if (!readPrintInfo()) return false;
672
1.23k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
673
1.23k
  }
674
3.28k
  ascii().addPos(0);
675
3.28k
  ascii().addNote(f.str().c_str());
676
3.28k
  return true;
677
3.38k
}
678
679
////////////////////////////////////////////////////////////
680
//
681
// send data
682
//
683
////////////////////////////////////////////////////////////
684
bool DrawTableParser::sendShapes()
685
540
{
686
540
  auto input=getInput();
687
540
  auto listener=getGraphicListener();
688
540
  if (!input || !listener) {
689
0
    MWAW_DEBUG_MSG(("DrawTableParser::sendShapes: can not find the listener\n"));
690
0
    return false;
691
0
  }
692
693
528k
  while (input->checkPosition(input->tell()+2)) {
694
528k
    long pos=input->tell();
695
528k
    if (sendShape())
696
527k
      continue;
697
492
    input->seek(pos, librevenge::RVNG_SEEK_SET);
698
492
    break;
699
528k
  }
700
540
  if (m_state->m_openedGroup) {
701
10
    MWAW_DEBUG_MSG(("DrawTableParser::sendShapes: find unclosed group\n"));
702
10
  }
703
550
  while (m_state->m_openedGroup-->0)
704
10
    listener->closeGroup();
705
540
  if (!input->isEnd()) {
706
505
    MWAW_DEBUG_MSG(("DrawTableParser::sendShapes: find extra data\n"));
707
505
    ascii().addPos(input->tell());
708
505
    ascii().addNote("Entries(Extra):###");
709
505
  }
710
540
  return true;
711
540
}
712
713
bool DrawTableParser::sendShape()
714
528k
{
715
528k
  auto input=getInput();
716
528k
  auto listener=getGraphicListener();
717
528k
  if (!input || !listener)
718
0
    return false;
719
528k
  long pos=input->tell();
720
528k
  libmwaw::DebugStream f;
721
528k
  f << "Entries(Shape):";
722
528k
  if (!input->checkPosition(pos+2))
723
0
    return false;
724
528k
  int type=int(input->readULong(2));
725
528k
  if (type==0) { // end of shapes' list or end of group
726
527k
    if (m_state->m_openedGroup>0) {
727
61
      --m_state->m_openedGroup;
728
61
      listener->closeGroup();
729
61
    }
730
527k
    ascii().addPos(pos);
731
527k
    ascii().addNote("_");
732
527k
    return true;
733
527k
  }
734
1.16k
  if (type!=6 || !input->checkPosition(pos+10))
735
434
    return false;
736
737
732
  type=int(input->readULong(2));
738
732
  char const *wh[]= {
739
732
    nullptr, nullptr, "line", "rect", "arc",
740
732
    "poly", "group", "bitmap", "epsf", "text"
741
732
  };
742
732
  int const numData[]= {
743
732
    0, 0, 0, 0, 0,
744
732
    2, 0, 1, 2, 1
745
732
  };
746
732
  std::string what;
747
732
  int nbData=0;
748
732
  if (type<10 && wh[type]) {
749
639
    what=wh[type];
750
639
    nbData=numData[type];
751
639
  }
752
93
  else {
753
93
    MWAW_DEBUG_MSG(("DrawTableParser::sendShape: find unknown shape %d\n", type));
754
93
    f << "###";
755
756
93
    std::stringstream s;
757
93
    s << "Type" << type;
758
93
    what=s.str();
759
93
  }
760
732
  f << what << ",";
761
762
732
  int val=int(input->readULong(2));
763
732
  if (val&1) f << "selected,";
764
732
  if (val&0x40) f << "group,";
765
732
  if (val&0x80) f << "locked,";
766
732
  val&=0xFF3E;
767
732
  if (val) f << "fl=" << std::hex << val << std::dec << ",";
768
732
  val=int(input->readULong(2)); // 0
769
732
  if (val) f << "f0=" << val << ",";
770
732
  int headerSz=int(input->readULong(2));
771
732
  long endPos=pos+10+headerSz;
772
732
  if (!input->checkPosition(endPos)) {
773
24
    MWAW_DEBUG_MSG(("DrawTableParser::sendShape: the zone seems too short\n"));
774
24
    f << "###hSz=" << headerSz << ",";
775
24
    ascii().addPos(pos);
776
24
    ascii().addNote(f.str().c_str());
777
24
    return false;
778
24
  }
779
708
  MWAWGraphicStyle style=MWAWGraphicStyle::emptyStyle();
780
708
  if (headerSz>=8 && type!=9) {
781
234
    int dim[2];
782
468
    for (auto &d : dim) d=int(input->readULong(2));
783
234
    if (dim[1]&3) {
784
104
      int fDim[]= {(dim[0]&0x7fff), (dim[1]>>2)};
785
104
      if (fDim[1]) style.m_lineWidth=72*float(fDim[0])/float(fDim[1]);
786
104
      f << "penSize=" << fDim[0] << "/" << fDim[1];
787
104
      if ((dim[1]&3)!=1) f << "[" << (dim[1]&3) << "]"; // main pt LT, C, BT
788
104
      if (dim[0]&0x8000) f << "_dec"; // decimal or frac
789
104
      f << ",";
790
104
    }
791
663
    for (int st=0; st<2; ++st) {
792
468
      if (st==1 && (type==2 || headerSz<12)) break;
793
429
      f << (st==0 ? "line" : "surface") << "[style]=[";
794
429
      val=int(input->readULong(1));
795
429
      if (val==0)
796
73
        f << "none,";
797
356
      else if (val!=2)
798
354
        f << "pat=" << val << ",";
799
429
      bool ok=true;
800
429
      MWAWGraphicStyle::Pattern pat;
801
429
      ok=val!=0 && m_state->getPattern(val, pat);
802
1.28k
      for (int i=0; i<2; ++i) { // 0: back, 1: front
803
858
        val=int(input->readULong(1));
804
858
        pat.m_colors[i]=m_state->getColor(val);
805
858
        if (val!=i)
806
733
          f << "col" << i << "=" << val << ",";
807
858
      }
808
429
      if (st==0 && type==2) {
809
24
        val=int(input->readULong(1));
810
24
        if (val) f << "arrow=" << val << ",";
811
24
        if (val&1) style.m_arrows[0]=MWAWGraphicStyle::Arrow::plain();
812
24
        if (val&2) style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain();
813
24
      }
814
405
      else
815
405
        input->seek(1, librevenge::RVNG_SEEK_CUR);
816
429
      f << "],";
817
429
      if (st==0) {
818
234
        if (!ok)
819
134
          style.m_lineWidth=0;
820
100
        else
821
100
          pat.getAverageColor(style.m_lineColor);
822
234
      }
823
195
      else if (ok)
824
114
        style.setPattern(pat);
825
429
    }
826
234
  }
827
708
  MWAWGraphicShape shape;
828
708
  MWAWBox2f shapeBox;
829
708
  int numPolyPoints=0;
830
708
  int polyType=0;
831
708
  MWAWBox2i bitmapBox;
832
708
  MWAWFont font;
833
708
  MWAWParagraph para;
834
835
708
  switch (type) {
836
34
  case 2: {
837
34
    if (headerSz!=18) break;
838
0
    val=int(input->readULong(1));
839
0
    if (val!=1) f << "f1=" << val << ",";
840
0
    input->seek(1, librevenge::RVNG_SEEK_CUR);
841
0
    float dim[4];
842
0
    for (auto &d : dim) d=float(input->readLong(2))/10.f;
843
0
    shape=MWAWGraphicShape::line(MWAWVec2f(dim[1],dim[0]),MWAWVec2f(dim[3],dim[2]));
844
0
    f << MWAWBox2f(MWAWVec2f(dim[1],dim[0]),MWAWVec2f(dim[3],dim[2])) << ",";
845
0
    shapeBox=shape.getBdBox();
846
0
    break;
847
34
  }
848
10
  case 3: {
849
10
    if (headerSz!=28) break;
850
0
    int fl=int(input->readULong(2));
851
0
    if (fl==1)
852
0
      f << "round/oval,";
853
0
    else if (fl)
854
0
      f << "##f1=" << fl << ",";
855
0
    int round=int(input->readULong(2));
856
0
    if (round)
857
0
      f << "roundSz=" << round << ",";
858
0
    for (int i=0; i<2; ++i) { // 0,0|-1
859
0
      val=int(input->readLong(2));
860
0
      if (val)
861
0
        f << "f" << i+2 << "=" << val << ",";
862
0
    }
863
0
    float dim[4];
864
0
    for (auto &d : dim) d=float(input->readLong(2))/10.f;
865
0
    shapeBox=MWAWBox2f(MWAWVec2f(dim[1],dim[0]),MWAWVec2f(dim[3],dim[2]));
866
0
    f << shapeBox << ",";
867
0
    if (round || fl!=1)
868
0
      shape=MWAWGraphicShape::rectangle(shapeBox, MWAWVec2f(float(round),float(round)));
869
0
    else
870
0
      shape=MWAWGraphicShape::circle(shapeBox);
871
0
    break;
872
10
  }
873
13
  case 4: {
874
13
    if (headerSz!=26) break;
875
0
    MWAWVec2f pts[2];
876
0
    for (auto &pt : pts) {
877
0
      float dim[2];
878
0
      for (auto &d : dim) d=float(input->readLong(2))/10.f;
879
0
      pt=MWAWVec2f(dim[1],dim[0]);
880
0
    }
881
0
    shapeBox=MWAWBox2f(pts[0]-pts[1],pts[0]+pts[1]);
882
0
    f << shapeBox << ",";
883
0
    val=int(input->readLong(2));
884
0
    if (val)
885
0
      f << "f1=" << val << ",";
886
0
    int fileAngles[2];
887
0
    for (auto &angl : fileAngles) angl=int(input->readLong(2));
888
0
    f << "angle=" << fileAngles[0] << "->" << fileAngles[0]+fileAngles[1] << ",";
889
0
    int angle[2] = { int(90-fileAngles[0]-fileAngles[1]), int(90-fileAngles[0]) };
890
0
    if (angle[1]<angle[0])
891
0
      std::swap(angle[0],angle[1]);
892
0
    if (angle[1]>360) {
893
0
      int numLoop=int(angle[1]/360)-1;
894
0
      angle[0]-=int(numLoop*360);
895
0
      angle[1]-=int(numLoop*360);
896
0
      while (angle[1] > 360) {
897
0
        angle[0]-=360;
898
0
        angle[1]-=360;
899
0
      }
900
0
    }
901
0
    if (angle[0] < -360) {
902
0
      int numLoop=int(angle[0]/360)+1;
903
0
      angle[0]-=int(numLoop*360);
904
0
      angle[1]-=int(numLoop*360);
905
0
      while (angle[0] < -360) {
906
0
        angle[0]+=360;
907
0
        angle[1]+=360;
908
0
      }
909
0
    }
910
0
    MWAWVec2f center = shapeBox.center();
911
0
    MWAWVec2f axis = 0.5f*MWAWVec2f(shapeBox.size());
912
    // we must compute the real bd box
913
0
    float minVal[2] = { 0, 0 }, maxVal[2] = { 0, 0 };
914
0
    int limitAngle[2];
915
0
    for (int i = 0; i < 2; i++)
916
0
      limitAngle[i] = (angle[i] < 0) ? int(angle[i]/90)-1 : int(angle[i]/90);
917
0
    for (int bord = limitAngle[0]; bord <= limitAngle[1]+1; bord++) {
918
0
      float ang = (bord == limitAngle[0]) ? float(angle[0]) :
919
0
                  (bord == limitAngle[1]+1) ? float(angle[1]) : 90 * float(bord);
920
0
      ang *= float(M_PI/180.);
921
0
      float const actVal[2] = { axis[0] *std::cos(ang), -axis[1] *std::sin(ang)};
922
0
      if (actVal[0] < minVal[0]) minVal[0] = actVal[0];
923
0
      else if (actVal[0] > maxVal[0]) maxVal[0] = actVal[0];
924
0
      if (actVal[1] < minVal[1]) minVal[1] = actVal[1];
925
0
      else if (actVal[1] > maxVal[1]) maxVal[1] = actVal[1];
926
0
    }
927
0
    MWAWBox2f realBox(MWAWVec2f(center[0]+minVal[0],center[1]+minVal[1]),
928
0
                      MWAWVec2f(center[0]+maxVal[0],center[1]+maxVal[1]));
929
0
    if (style.hasSurface())
930
0
      shape = MWAWGraphicShape::pie(realBox, shapeBox, MWAWVec2f(float(angle[0]),float(angle[1])));
931
0
    else
932
0
      shape = MWAWGraphicShape::arc(realBox, shapeBox, MWAWVec2f(float(angle[0]),float(angle[1])));
933
0
    shapeBox=realBox;
934
0
    break;
935
13
  }
936
38
  case 5:
937
38
    if (headerSz!=20) break;
938
0
    for (int i=0; i<2; ++i) { // 0,0
939
0
      val=int(input->readLong(2));
940
0
      if (val)
941
0
        f << "f" << i+1 << "=" << val << ",";
942
0
    }
943
0
    numPolyPoints=int(input->readLong(2));
944
0
    f << "num[pts]=" << numPolyPoints << ",";
945
0
    polyType=int(input->readLong(2));
946
0
    f << "type=" << polyType << ","; // (type&1) means closed
947
0
    if (polyType==0) {
948
0
      if (!style.hasSurface())
949
0
        shape=MWAWGraphicShape::polyline(shapeBox);
950
0
      else
951
0
        shape=MWAWGraphicShape::polygon(shapeBox);
952
0
    }
953
0
    else if (polyType==1)
954
0
      shape=MWAWGraphicShape::polygon(shapeBox);
955
0
    else if (polyType==2 || polyType==3)
956
0
      shape=MWAWGraphicShape::path(shapeBox);
957
0
    else {
958
0
      MWAW_DEBUG_MSG(("DrawTableParser::sendShape: unknown polygon type\n"));
959
0
      f << "###";
960
0
      shape=MWAWGraphicShape::polyline(shapeBox);
961
0
      polyType=0;
962
0
    }
963
0
    break;
964
39
  case 7: {
965
39
    if (headerSz!=42) break;
966
12
    val=int(input->readLong(2));
967
12
    style.m_rotate=float(val);
968
12
    if (val) f << "rot=" << val << ",";
969
12
    val=int(input->readLong(2)); // 0
970
12
    if (val)
971
11
      f << "f1=" << val << ",";
972
36
    for (int i=0; i<2; ++i) {
973
24
      int dim[4];
974
96
      for (auto &d : dim) d=int(input->readLong(2));
975
24
      MWAWBox2i box(MWAWVec2i(dim[1],dim[0]),MWAWVec2i(dim[3],dim[2]));
976
24
      if (i==0)
977
12
        bitmapBox=box;
978
24
      f << "dim" << i << "=" << box << ",";
979
24
    }
980
12
    float dim[4];
981
48
    for (auto &d : dim) d=float(input->readLong(2))/10.f;
982
12
    shapeBox=MWAWBox2f(MWAWVec2f(dim[1],dim[0]),MWAWVec2f(dim[3],dim[2]));
983
12
    f << shapeBox << ",";
984
12
    val=int(input->readLong(2)); // 0
985
12
    if (val)
986
10
      f << "f3=" << val << ",";
987
12
    break;
988
39
  }
989
11
  case 8: {
990
11
    if (headerSz!=40) break;
991
0
    val=int(input->readLong(2));
992
0
    style.m_rotate=float(val);
993
0
    if (val) f << "rot=" << val << ",";
994
0
    float dim[4];
995
0
    for (auto &d : dim) d=float(input->readLong(2))/10.f;
996
0
    shapeBox=MWAWBox2f(MWAWVec2f(dim[1],dim[0]),MWAWVec2f(dim[3],dim[2]));
997
0
    f << shapeBox << ",";
998
0
    val=int(input->readLong(2)); // 3
999
0
    if (val)
1000
0
      f << "f2=" << val << ",";
1001
0
    for (auto &d : dim) d=float(input->readLong(2))/10.f;
1002
0
    f << "orig=" << MWAWBox2f(MWAWVec2f(dim[1],dim[0]),MWAWVec2f(dim[3],dim[2])) << ",";
1003
0
    for (int i=0; i<2; ++i)
1004
0
      f << "sz" << i << "=" << std::hex << input->readULong(4) << std::dec << ",";
1005
0
    break;
1006
11
  }
1007
411
  case 9: {
1008
411
    if (headerSz!=24) break;
1009
    // font
1010
153
    font.setId(int(input->readULong(2)));
1011
153
    font.setSize(float(input->readLong(2)));
1012
153
    uint32_t flags=0;
1013
153
    val=int(input->readULong(2));
1014
153
    if (val&0x1) flags |= MWAWFont::boldBit;
1015
153
    if (val&0x2) flags |= MWAWFont::italicBit;
1016
153
    if (val&0x4) font.setUnderlineStyle(MWAWFont::Line::Simple);
1017
153
    if (val&0x8) flags |= MWAWFont::embossBit;
1018
153
    if (val&0x10) flags |= MWAWFont::shadowBit;
1019
153
    font.setFlags(flags);
1020
153
    f << font.getDebugString(getFontConverter());
1021
153
    val&=0xffe0;
1022
153
    if (val) f << "font[fl]=" << std::hex << val << std::dec << ",";
1023
    // paragraph
1024
153
    val=int(input->readULong(1));
1025
153
    switch (val&3) {
1026
23
    case 0: // left
1027
23
      break;
1028
31
    case 1:
1029
31
      para.m_justify = MWAWParagraph::JustificationCenter;
1030
31
      f << "align=center,";
1031
31
      break;
1032
81
    case 2:
1033
81
      para.m_justify = MWAWParagraph::JustificationRight;
1034
81
      f << "align=right,";
1035
81
      break;
1036
18
    case 3:
1037
18
    default:
1038
18
      MWAW_DEBUG_MSG(("DrawTableParser::sendShape: find align=3\n"));
1039
18
      f << "###align=3,";
1040
18
      break;
1041
153
    }
1042
153
    if (val&0xfc) f << "#para[align]=" << (val>>2) << ",";
1043
153
    val=int(input->readULong(1));
1044
153
    switch (val&3) {
1045
26
    case 0: // 1 line
1046
26
      break;
1047
96
    case 1:
1048
96
      para.setInterline(1.5, librevenge::RVNG_PERCENT);
1049
96
      f << "interline=150%,";
1050
96
      break;
1051
26
    case 2:
1052
26
      para.setInterline(2, librevenge::RVNG_PERCENT);
1053
26
      f << "interline=200%,";
1054
26
      break;
1055
5
    default:
1056
5
      MWAW_DEBUG_MSG(("DrawTableParser::sendShape: find unknown interline\n"));
1057
5
      f << "#interline3,";
1058
153
    }
1059
153
    if (val&0xfc) f << "#interline=" << (val>>2) << ",";
1060
153
    val=int(input->readLong(2));
1061
153
    if (val) f << "f3=" << val << ",";
1062
153
    val=int(input->readULong(1));
1063
153
    if (val!=1) f << "f4=" << val << ",";
1064
153
    val=int(input->readULong(1));
1065
153
    if (val!=1) {
1066
148
      MWAWColor color=m_state->getColor(val);
1067
148
      font.setColor(color);
1068
148
      f << "text[color]=" << val << ",";
1069
148
    }
1070
153
    val=int(input->readLong(2));
1071
153
    style.m_rotate=float(val);
1072
153
    if (val) f << "rot=" << val << ",";
1073
153
    float dim[4];
1074
612
    for (auto &d : dim) d=float(input->readLong(2))/10.f;
1075
153
    shapeBox=MWAWBox2f(MWAWVec2f(dim[1],dim[0]),MWAWVec2f(dim[3],dim[2]));
1076
153
    f << shapeBox << ",";
1077
153
    f << "N=" << input->readULong(2) << ",";
1078
153
    break;
1079
153
  }
1080
152
  default:
1081
152
    break;
1082
708
  }
1083
708
  if (input->tell()!=endPos)
1084
462
    ascii().addDelimiter(input->tell(),'|');
1085
708
  ascii().addPos(pos);
1086
708
  ascii().addNote(f.str().c_str());
1087
1088
708
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
1089
708
  MWAWPosition position(shapeBox[0], shapeBox.size(), librevenge::RVNG_POINT);
1090
708
  position.m_anchorTo = MWAWPosition::Page;
1091
708
  if (type>=2 && type<=4)
1092
57
    listener->insertShape(position, shape, style);
1093
651
  else if (type==6 && m_state->m_openedGroup>=0) {
1094
71
    ++m_state->m_openedGroup;
1095
71
    listener->openGroup(position);
1096
71
  }
1097
1.21k
  for (int i=0; i<nbData; ++i) {
1098
545
    pos=input->tell();
1099
    // checkme: find how blocks with size>=65536 are stored
1100
545
    int dSz=int(input->readULong(2));
1101
545
    f.str("");
1102
545
    f << "Shape-" << i << "[" << what << "]:";
1103
545
    if (!input->checkPosition(pos+2+dSz)) {
1104
34
      MWAW_DEBUG_MSG(("DrawTableParser::sendShape: bad size for zone %d\n", i));
1105
34
      f << "###dSz=" << dSz << ",";
1106
34
      ascii().addPos(pos);
1107
34
      ascii().addNote(f.str().c_str());
1108
34
      return false;
1109
34
    }
1110
511
    if (type==5) {
1111
75
      if (i==0 && (dSz%4)==0) {
1112
32
        f << "pts=[";
1113
32
        std::vector<MWAWVec2f> points;
1114
238
        for (int j=0; j<(dSz>>2); ++j) {
1115
206
          float dim[2];
1116
412
          for (auto &d : dim) d=float(input->readLong(2))/10.f;
1117
206
          points.push_back(MWAWVec2f(dim[1],dim[0]));
1118
206
          f << points.back() << ",";
1119
206
        }
1120
32
        f << "],";
1121
32
        if (polyType&1 && points.size()>1)
1122
0
          points.push_back(points[0]);
1123
32
        if (polyType==0 || polyType==1)
1124
32
          shape.m_vertices=points;
1125
0
        else if (!points.empty()) {
1126
0
          shape.m_path.push_back(MWAWGraphicShape::PathData('M', points[0]));
1127
0
          for (size_t j=1; j+1<points.size(); ++j) {
1128
0
            MWAWVec2f dir=points[j+1]-points[j-1];
1129
0
            shape.m_path.push_back(MWAWGraphicShape::PathData('S', points[j], points[j]-0.1f*dir));
1130
0
          }
1131
0
          if (polyType==3)
1132
0
            shape.m_path.push_back(MWAWGraphicShape::PathData('Z'));
1133
0
        }
1134
32
        listener->insertShape(position, shape, style);
1135
32
      }
1136
43
      else if (i==1 && dSz==4) {
1137
12
        for (int j=0; j<2; ++j) { // 0,0
1138
8
          val=int(input->readLong(2));
1139
8
          if (val)
1140
3
            f << "f" << j << "=" << val << ",";
1141
8
        }
1142
4
      }
1143
39
      else {
1144
39
        MWAW_DEBUG_MSG(("DrawTableParser::sendShape: can not read poly's zone %d\n", i));
1145
39
        f << "###";
1146
39
      }
1147
75
    }
1148
436
    else if (type==7) {
1149
36
      MWAWEmbeddedObject obj;
1150
36
      if (getBitmap(bitmapBox, obj, pos+2+dSz)) {
1151
0
        listener->insertPicture(position, obj);
1152
0
        input->seek(pos+2+dSz, librevenge::RVNG_SEEK_SET);
1153
0
        continue;
1154
0
      }
1155
36
      f << "###";
1156
36
    }
1157
400
    else if (type==8) {
1158
15
      if (i==0) { // normally must be a apple picture
1159
8
        MWAWBox2f box;
1160
8
        auto res = MWAWPictData::check(input, dSz, box);
1161
8
        if (res == MWAWPict::MWAW_R_BAD) {
1162
8
          MWAW_DEBUG_MSG(("DrawTableParser::sendShape:: can not find the picture\n"));
1163
8
        }
1164
0
        else {
1165
0
          input->seek(pos+2, librevenge::RVNG_SEEK_SET);
1166
0
          std::shared_ptr<MWAWPict> thePict(MWAWPictData::get(input, dSz));
1167
0
          if (thePict) {
1168
0
            MWAWEmbeddedObject picture;
1169
0
            if (thePict->getBinary(picture))
1170
0
              listener->insertPicture(position, picture);
1171
0
          }
1172
0
        }
1173
8
      }
1174
#ifdef DEBUG_WITH_FILES
1175
      librevenge::RVNGBinaryData file;
1176
      input->seek(pos+2, librevenge::RVNG_SEEK_SET);
1177
      input->readDataBlock(dSz, file);
1178
      static int volatile pictName = 0;
1179
      libmwaw::DebugStream s;
1180
      s << "PICT-" << ++pictName << (i==0 ? ".pct" : ".eps");
1181
      libmwaw::Debug::dumpFile(file, s.str().c_str());
1182
      ascii().skipZone(pos, pos+1+dSz);
1183
#endif
1184
15
      input->seek(pos+2+dSz, librevenge::RVNG_SEEK_SET);
1185
15
      continue;
1186
15
    }
1187
385
    else if (type==9) {
1188
385
      std::string text;
1189
674k
      for (int j=0; j<dSz; ++j) text+=char(input->readULong(1));
1190
385
      f << text << ",";
1191
385
      MWAWEntry entry;
1192
385
      entry.setBegin(pos+2);
1193
385
      entry.setLength(dSz);
1194
385
      std::shared_ptr<MWAWSubDocument> doc(new DrawTableParserInternal::SubDocument(*this, getInput(), entry, font, para));
1195
385
      listener->insertTextBox(position, doc, style);
1196
385
    }
1197
496
    if (input->tell()!=pos+2 && input->tell()!=pos+2+dSz) {
1198
0
      f << "###extra";
1199
0
      MWAW_DEBUG_MSG(("DrawTableParser::sendShape: find extra data in zone %d\n", i));
1200
0
      ascii().addDelimiter(input->tell(),'|');
1201
0
    }
1202
496
    input->seek(pos+2+dSz, librevenge::RVNG_SEEK_SET);
1203
496
    ascii().addPos(pos);
1204
496
    ascii().addNote(f.str().c_str());
1205
496
  }
1206
674
  return true;
1207
708
}
1208
1209
bool DrawTableParser::getBitmap(MWAWBox2i const &box, MWAWEmbeddedObject &obj, long endPos)
1210
36
{
1211
36
  auto input=getInput();
1212
36
  long pos=input->tell();
1213
36
  long dSz=endPos-pos;
1214
36
  int Y=box.size()[1];
1215
36
  if (Y==0 || dSz<0 || (dSz%Y)!=0) {
1216
27
    MWAW_DEBUG_MSG(("DrawTableParser::getBitmap: unexpected bitmap size\n"));
1217
27
    return false;
1218
27
  }
1219
1220
9
  long width=dSz/Y;
1221
9
  int X=box.size()[0];
1222
9
  if (8*width<X) {
1223
2
    MWAW_DEBUG_MSG(("DrawTableParser::getBitmap: unexpected bitmap size\n"));
1224
2
    return false;
1225
2
  }
1226
1227
7
  obj=MWAWEmbeddedObject();
1228
7
  ascii().addPos(pos-2);
1229
7
  ascii().addNote("Entries(Bitmap)");
1230
1231
7
  MWAWPictBitmapIndexed pict(box.size());
1232
7
  std::vector<MWAWColor> colors;
1233
7
  colors.push_back(MWAWColor::black());
1234
7
  colors.push_back(MWAWColor::white());
1235
7
  pict.setColors(colors);
1236
1237
7
  libmwaw::DebugStream f;
1238
70.4k
  for (int y=0; y<Y; ++y) {
1239
70.4k
    pos=input->tell();
1240
70.4k
    f.str("");
1241
70.4k
    f << "Bitmap-" << y << ":";
1242
1243
70.4k
    int x=0;
1244
70.4k
    for (int w=0; w<width; ++w) {
1245
0
      int val=int(input->readULong(1));
1246
0
      for (int v=0, depl=0x80; v<8; ++v, depl>>=1) {
1247
0
        if (x>=X)
1248
0
          break;
1249
0
        pict.set(x++,y, (val &depl) ? 0 : 1);
1250
0
      }
1251
0
    }
1252
70.4k
    ascii().addPos(pos);
1253
70.4k
    ascii().addNote(f.str().c_str());
1254
70.4k
    input->seek(pos+width, librevenge::RVNG_SEEK_SET);
1255
70.4k
  }
1256
7
  return pict.getBinary(obj);
1257
9
}
1258
1259
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: