Coverage Report

Created: 2026-07-20 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/FreeHandParser.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 <algorithm>
35
#include <cmath>
36
#include <iomanip>
37
#include <iostream>
38
#include <limits>
39
#include <map>
40
#include <set>
41
#include <sstream>
42
#include <utility>
43
44
#include <librevenge/librevenge.h>
45
46
#include "MWAWFont.hxx"
47
#include "MWAWFontConverter.hxx"
48
#include "MWAWGraphicListener.hxx"
49
#include "MWAWGraphicShape.hxx"
50
#include "MWAWGraphicStyle.hxx"
51
#include "MWAWHeader.hxx"
52
#include "MWAWParagraph.hxx"
53
#include "MWAWPictBitmap.hxx"
54
#include "MWAWPictData.hxx"
55
#include "MWAWPrinter.hxx"
56
#include "MWAWPosition.hxx"
57
#include "MWAWSubDocument.hxx"
58
59
#include "FreeHandParser.hxx"
60
61
/** Internal: the structures of a FreeHandParser */
62
namespace FreeHandParserInternal
63
{
64
//! the different zone type
65
enum ZoneType { Z_Unknown, Z_Color, Z_ColorGroup, Z_Dash, Z_DashGroup, Z_Data, Z_Fill, Z_FillGroup, Z_Group,
66
                Z_LineStyle, Z_LineStyleGroup, Z_Note, Z_Picture, Z_PictureName, Z_String, Z_Shape, Z_StyleGroup
67
              };
68
69
/** struct which defines the screen parameters in FreeHandParserInternal */
70
struct ScreenMode {
71
  //! constructor
72
  ScreenMode()
73
943k
    : m_function(0)
74
943k
    , m_angle(0)
75
943k
    , m_lineByInch(0)
76
943k
    , m_value(0)
77
943k
  {
78
943k
  }
79
  //! operator<<
80
  friend std::ostream &operator<<(std::ostream &o, ScreenMode const &screen)
81
0
  {
82
0
    switch (screen.m_function) {
83
0
    case 0: // unset
84
0
    case -1: // default
85
0
      break;
86
0
    case 1:
87
0
      o << "function=round,";
88
0
      break;
89
0
    case 2:
90
0
      o << "function=line,";
91
0
      break;
92
0
    default:
93
0
      MWAW_DEBUG_MSG(("FreeHandParserInternal::operator<<(ScreenMode): find unexpected screen function\n"));
94
0
      o << "function=###" << screen.m_function << ",";
95
0
      break;
96
0
    }
97
0
    if (screen.m_angle < 0 || screen.m_angle>0)
98
0
      o << "angle=" << screen.m_angle << ",";
99
0
    if (screen.m_lineByInch==0xFFFF)
100
0
      o << "lineByInch*,";
101
0
    else
102
0
      o << "lineByInch=" << screen.m_lineByInch << ",";
103
0
    if (screen.m_value)
104
0
      o << "unkn0=" << screen.m_value << ",";
105
0
    return o;
106
0
  }
107
108
  //! the  function
109
  int m_function;
110
  //! the  angle
111
  float m_angle;
112
  //! the  line/inch
113
  int m_lineByInch;
114
  //! unknow value
115
  int m_value;
116
};
117
118
/** small structure of FreeHandParserInternal used to stored
119
    a shape header
120
*/
121
struct ShapeHeader {
122
  //! constructor
123
  ShapeHeader()
124
532k
    : m_size(0)
125
532k
    , m_type(0)
126
532k
    , m_note("")
127
532k
    , m_dataId(0)
128
532k
    , m_layerId(-1)
129
532k
    , m_screen()
130
532k
    , m_extra("")
131
532k
  {
132
2.12M
    for (auto &value : m_values) value=0;
133
532k
  }
134
  //! operator<<
135
  friend std::ostream &operator<<(std::ostream &o, ShapeHeader const &shape)
136
0
  {
137
0
    if (shape.m_layerId>=0) o << "layer=" << shape.m_layerId << ",";
138
0
    if (shape.m_dataId) o << "data=Z" << shape.m_dataId << ",";
139
0
    if (!shape.m_note.empty()) o << "note=\"" << shape.m_note << "\",";
140
0
    if (shape.m_screen.isSet()) o << "screen=[" << *shape.m_screen << "],";
141
0
    for (int i=0; i<3; ++i) {
142
0
      if (!shape.m_values[i])
143
0
        continue;
144
0
      int val=shape.m_values[i];
145
0
      if (i==1 && (val&1)) {
146
0
        o << "locked,";
147
0
        val&=0xFFFE;
148
0
      }
149
0
      if (val)
150
0
        o << "unkn" << i << "=" << val << ",";
151
0
    }
152
0
    if (shape.m_values[3]) // always a 1005 zone ?
153
0
      o << "unknZone=Z" << shape.m_values[3] << ",";
154
0
    o << shape.m_extra;
155
0
    return o;
156
0
  }
157
  //! a field related to the zone size
158
  long m_size;
159
  //! the zone type
160
  int m_type;
161
  //! the note
162
  std::string m_note;
163
  //! the data id (used to store a note, ...)
164
  int m_dataId;
165
  //! the layer id
166
  int m_layerId;
167
  //! the screen mode
168
  MWAWVariable<ScreenMode> m_screen;
169
  //! the unknown values
170
  int m_values[4];
171
  //! extra data
172
  std::string m_extra;
173
};
174
175
/** small structure of FreeHandParserInternal used to stored
176
    a fill style
177
*/
178
struct FillStyle {
179
  //! constructor
180
  FillStyle()
181
79.3k
    : m_type(MWAWGraphicStyle::Gradient::G_None)
182
79.3k
    , m_pattern()
183
79.3k
    , m_angle(0)
184
79.3k
    , m_logarithm(false)
185
79.3k
  {
186
158k
    for (auto &colorId : m_colorId) colorId=0;
187
79.3k
  }
188
  //! the gradient type
189
  MWAWGraphicStyle::Gradient::Type m_type;
190
  //! the color id
191
  int m_colorId[2];
192
  //! the pattern
193
  MWAWGraphicStyle::Pattern m_pattern;
194
  //! the angle
195
  float m_angle;
196
  //! flag to know if a flag has logarithmic scale
197
  bool m_logarithm;
198
};
199
200
/** small structure of FreeHandParserInternal used to stored
201
    a line style
202
*/
203
struct LineStyle {
204
  //! constructor
205
  LineStyle()
206
109k
    : m_width(1)
207
109k
    , m_colorId(0)
208
109k
    , m_dashId(0)
209
109k
    , m_pattern()
210
109k
    , m_miterLimit(0)
211
109k
    , m_cap(MWAWGraphicStyle::C_Butt)
212
109k
    , m_join(MWAWGraphicStyle::J_Miter)
213
109k
  {
214
109k
  }
215
  //! the line width
216
  float m_width;
217
  //! the color id
218
  int m_colorId;
219
  //! the dash id
220
  int m_dashId;
221
  //! the pattern
222
  MWAWGraphicStyle::Pattern m_pattern;
223
  //! the miter limit
224
  float m_miterLimit;
225
  //! the line cap
226
  MWAWGraphicStyle::LineCap m_cap;
227
  //! the line join
228
  MWAWGraphicStyle::LineJoin m_join;
229
};
230
/** small structure of FreeHandParserInternal used to stored
231
    a style header
232
*/
233
struct StyleHeader {
234
  //! constructor
235
  StyleHeader()
236
411k
    : m_size(0)
237
411k
    , m_type(0)
238
411k
    , m_labelId(0)
239
411k
    , m_screen()
240
411k
    , m_unknownValue(0)
241
411k
    , m_extra("")
242
411k
  {
243
411k
  }
244
  //! operator<<
245
  friend std::ostream &operator<<(std::ostream &o, StyleHeader const &style)
246
0
  {
247
0
    if (style.m_labelId) o << "label=Z" << style.m_labelId << ",";
248
0
    if (style.m_screen.isSet()) o << "screen=[" << *style.m_screen << "],";
249
0
    if (style.m_unknownValue)
250
0
      o << "unkn0=" << style.m_unknownValue << ",";
251
0
    o << style.m_extra;
252
0
    return o;
253
0
  }
254
  //! a field related to the zone size
255
  long m_size;
256
  //! the zone type
257
  int m_type;
258
  //! the label id
259
  int m_labelId;
260
  //! the screen mode
261
  MWAWVariable<ScreenMode> m_screen;
262
  //! the first unknown value
263
  int m_unknownValue;
264
  //! extra data
265
  std::string m_extra;
266
};
267
268
/** small structure of FreeHandParserInternal used to stored a shape
269
*/
270
struct Shape {
271
  //! the different type
272
  enum Type { Line, Rectangle, Ellipse, Path, BackgroundPicture, Picture, Group, JoinGroup, Unknown };
273
274
  //! constructor
275
  Shape()
276
401k
    : m_id(0)
277
401k
    , m_type(Unknown)
278
401k
    , m_layerId(-1)
279
401k
    , m_lineId(0)
280
401k
    , m_fillId(0)
281
401k
    , m_transformation()
282
401k
    , m_box()
283
401k
    , m_corner()
284
401k
    , m_vertices()
285
401k
    , m_closed(false)
286
401k
    , m_evenOdd(false)
287
401k
    , m_joinDistance(0)
288
401k
    , m_childs()
289
401k
    , m_picture()
290
401k
    , m_dataId(0)
291
401k
    , m_isSent(false)
292
401k
  {
293
401k
  }
294
295
  //! try to returns a shape and position
296
  bool updateShape(MWAWGraphicShape &shape) const
297
17.9k
  {
298
17.9k
    if (m_type==Line || m_type==Rectangle || m_type==Ellipse) {
299
16.0k
      MWAWBox2f box=m_box;
300
16.0k
      if (m_type==Line)
301
3.22k
        shape=MWAWGraphicShape::line(box[0],box[1]);
302
12.8k
      else if (m_type==Rectangle)
303
8.05k
        shape=MWAWGraphicShape::rectangle(box, m_corner);
304
4.74k
      else
305
4.74k
        shape=MWAWGraphicShape::circle(box);
306
16.0k
      return true;
307
16.0k
    }
308
1.90k
    if (m_type!=Path || m_vertices.empty()) return false;
309
1.83k
    if (m_vertices.size()<6) {
310
      // probably an aborted spline, transform in a point
311
23
      MWAWVec2f pt=m_vertices[0];
312
23
      shape=MWAWGraphicShape::line(pt,pt);
313
23
      return true;
314
23
    }
315
1.81k
    shape.m_type=MWAWGraphicShape::Polygon;
316
1.81k
    MWAWBox2f box;
317
1.81k
    bool needSpline=false;
318
37.5k
    for (size_t i=0; i+2<m_vertices.size(); i+=3) {
319
35.6k
      MWAWVec2f pt=m_vertices[i];
320
35.6k
      if (i==0)
321
1.81k
        box=MWAWBox2f(pt,pt);
322
33.8k
      else
323
33.8k
        box=box.getUnion(MWAWBox2f(pt,pt));
324
35.6k
      if (!needSpline && (m_vertices[i]!=m_vertices[i+1] || m_vertices[i]!=m_vertices[i+2]))
325
1.80k
        needSpline=true;
326
35.6k
      shape.m_vertices.push_back(pt);
327
35.6k
    }
328
1.81k
    shape.m_bdBox=box;
329
1.81k
    if (m_closed)
330
175
      shape.m_vertices.push_back(shape.m_vertices.front());
331
1.81k
    if (!needSpline)
332
12
      return true;
333
334
1.80k
    MWAWVec2f prevPoint, pt1;
335
1.80k
    bool hasPrevPoint = false;
336
1.80k
    shape.m_type=MWAWGraphicShape::Path;
337
1.80k
    shape.m_vertices.clear();
338
37.4k
    for (size_t i=0; i+2<m_vertices.size()+3; i+=3) {
339
37.4k
      bool end=i+2>=m_vertices.size();
340
37.4k
      if (end) {
341
1.80k
        if (!m_closed)
342
1.63k
          break;
343
172
        if (end && !hasPrevPoint && m_vertices[0]==m_vertices[1]) {
344
17
          shape.m_path.push_back(MWAWGraphicShape::PathData('Z'));
345
17
          break;
346
17
        }
347
155
        i=0;
348
155
      }
349
35.8k
      MWAWVec2f pt=m_vertices[i];
350
35.8k
      pt1 = m_vertices[i+1];
351
35.8k
      char type = hasPrevPoint ? 'C' : i==0 ? 'M' : (m_vertices[i]!=m_vertices[i+1]) ? 'S' : 'L';
352
35.8k
      shape.m_path.push_back(MWAWGraphicShape::PathData(type, pt, hasPrevPoint ? prevPoint : pt1, pt1));
353
35.8k
      hasPrevPoint = m_vertices[i]!=m_vertices[i+2];
354
35.8k
      if (hasPrevPoint)
355
26.2k
        prevPoint=m_vertices[i+2];
356
35.8k
      if (end)
357
155
        break;
358
35.8k
    }
359
1.80k
    return true;
360
1.81k
  }
361
  //! the zone id
362
  int m_id;
363
  //! the type
364
  Type m_type;
365
  //! the layer
366
  int m_layerId;
367
  //! the line id
368
  int m_lineId;
369
  //! the fill id
370
  int m_fillId;
371
372
  //! the transformation
373
  MWAWTransformation m_transformation;
374
  //! the main box (for line, rectangle, ellipse)
375
  MWAWBox2f m_box;
376
  //! the corner size
377
  MWAWVec2f m_corner;
378
  //! the list of point for path: 3 Vec2f defining each point
379
  std::vector<MWAWVec2f> m_vertices;
380
  //! a flag to know if a path is closed
381
  bool m_closed;
382
  //! a flag to know how path intersection are defined
383
  bool m_evenOdd;
384
  //! the join distance
385
  float m_joinDistance;
386
  //! the list of child (for group and join group )
387
  std::vector<int> m_childs;
388
  //! the picture entry
389
  MWAWEntry m_picture;
390
  //! the id of a the picture date
391
  int m_dataId;
392
  //! flag to known if a shape is sent
393
  mutable bool m_isSent;
394
};
395
396
/** structure of FreeHandParserInternal used to stored a font */
397
struct Font {
398
  //! constructor
399
  Font()
400
1.52M
    : m_font()
401
1.52M
    , m_nameId(0)
402
1.52M
    , m_colorId(0)
403
1.52M
  {
404
1.52M
  }
405
  //! the font
406
  MWAWFont m_font;
407
  //! the font name id
408
  int m_nameId;
409
  //! the font color id
410
  int m_colorId;
411
};
412
413
/** structure of FreeHandParserInternal used to stored a textbox */
414
struct Textbox {
415
  //! constructor
416
  explicit Textbox(int id)
417
134k
    : m_id(id)
418
134k
    , m_layerId(-1)
419
134k
    , m_box()
420
134k
    , m_transformation()
421
134k
    , m_spacings(0,0)
422
134k
    , m_scalings(1,1)
423
134k
    , m_baseline(0)
424
134k
    , m_justify(MWAWParagraph::JustificationLeft)
425
134k
    , m_text()
426
134k
    , m_posToFontMap()
427
134k
    , m_isSent(false)
428
134k
  {
429
134k
  }
430
  //! the textbox id
431
  int m_id;
432
  //! the layer id
433
  int m_layerId;
434
  //! the main box
435
  MWAWBox2f m_box;
436
  //! the transformation
437
  MWAWTransformation m_transformation;
438
  //! the letter/word spacing
439
  MWAWVec2f m_spacings;
440
  //! the horizontal/vertical scalings
441
  MWAWVec2f m_scalings;
442
  //! the baseline
443
  float m_baseline;
444
  //! the paragraph justification
445
  MWAWParagraph::Justification m_justify;
446
  //! the text data
447
  MWAWEntry m_text;
448
  //! map char pos to font
449
  std::map<int, Font> m_posToFontMap;
450
  //! flag to known if a shape is sent
451
  mutable bool m_isSent;
452
};
453
454
////////////////////////////////////////
455
//! Internal: the state of a FreeHandParser
456
struct State {
457
  //! constructor
458
  State()
459
147k
    : m_mainGroupId(0)
460
147k
    , m_transform()
461
147k
    , m_zIdToTypeMap()
462
147k
    , m_zIdToColorMap()
463
147k
    , m_zIdToDashMap()
464
147k
    , m_zIdToDataMap()
465
147k
    , m_zIdToFillStyleMap()
466
147k
    , m_zIdToLineStyleMap()
467
147k
    , m_zIdToStringMap()
468
147k
    , m_zIdToPostscriptMap()
469
147k
    , m_zIdToShapeMap()
470
147k
    , m_zIdToTextboxMap()
471
147k
    , m_actualLayer(-1)
472
147k
    , m_sendIdSet()
473
147k
    , m_sendLayerSet()
474
147k
  {
475
147k
  }
476
  //! try to return a zone type
477
  ZoneType getZoneType(int id) const
478
71.0k
  {
479
71.0k
    if (m_zIdToTypeMap.find(id)==m_zIdToTypeMap.end())
480
7.40k
      return Z_Unknown;
481
63.6k
    return m_zIdToTypeMap.find(id)->second;
482
71.0k
  }
483
  //! try to add a id
484
  bool addZoneId(int id, ZoneType zoneType)
485
5.33M
  {
486
5.33M
    if (m_zIdToTypeMap.find(id)!=m_zIdToTypeMap.end())
487
4.37M
      return m_zIdToTypeMap.find(id)->second==zoneType;
488
958k
    m_zIdToTypeMap[id]=zoneType;
489
958k
    return true;
490
5.33M
  }
491
  //! try to update the fill style
492
  bool updateFillStyle(int zId, MWAWGraphicStyle &style) const;
493
  //! try to update the line style
494
  bool updateLineStyle(int zId, MWAWGraphicStyle &style) const;
495
  //! try to update the group layer id, return 0 or the new layer id
496
  int updateGroupLayerId(int zId, std::set<int> &seen);
497
  //! the main group id
498
  int m_mainGroupId;
499
  //! the main transformation
500
  MWAWTransformation m_transform;
501
  //! the list of id seen
502
  std::map<int, ZoneType> m_zIdToTypeMap;
503
  //! the list zoneId to color
504
  std::map<int, MWAWColor> m_zIdToColorMap;
505
  //! the list zoneId to dash
506
  std::map<int, std::vector<float> > m_zIdToDashMap;
507
  //! the list zoneId to data map
508
  std::map<int, MWAWEntry> m_zIdToDataMap;
509
  //! the list zoneId to fillStyle
510
  std::map<int, FillStyle> m_zIdToFillStyleMap;
511
  //! the list zoneId to lineStyle
512
  std::map<int, LineStyle> m_zIdToLineStyleMap;
513
  //! the list zoneId to string
514
  std::map<int, std::string> m_zIdToStringMap;
515
  //! the list zoneId to postscrip code
516
  std::map<int, std::string> m_zIdToPostscriptMap;
517
  //! the list zoneId to shape
518
  std::map<int, Shape> m_zIdToShapeMap;
519
  //! the list zoneId to textbox
520
  std::map<int, Textbox> m_zIdToTextboxMap;
521
  //! the actual layer
522
  int m_actualLayer;
523
  //! a set of send id used to avoid potential loop
524
  std::set<int> m_sendIdSet;
525
  //! a set of create layer to avoid dupplicating layer
526
  std::set<int> m_sendLayerSet;
527
};
528
529
bool State::updateFillStyle(int zId, MWAWGraphicStyle &style) const
530
12.9k
{
531
12.9k
  if (!zId) return true;
532
  // can be a simple color
533
11.4k
  if (m_zIdToColorMap.find(zId)!=m_zIdToColorMap.end()) {
534
99
    style.setSurfaceColor(m_zIdToColorMap.find(zId)->second);
535
99
    return true;
536
99
  }
537
11.3k
  if (m_zIdToFillStyleMap.find(zId)==m_zIdToFillStyleMap.end()) {
538
7.27k
    static bool first=true;
539
7.27k
    if (first) {
540
13
      first=false;
541
13
      MWAW_DEBUG_MSG(("FreeHandParserInternal::State::updateFillStyle: can not find style %d\n", zId));
542
13
    }
543
7.27k
    return false;
544
7.27k
  }
545
4.06k
  FillStyle const &fill=m_zIdToFillStyleMap.find(zId)->second;
546
4.06k
  int numColors=fill.m_type==MWAWGraphicStyle::Gradient::G_None ? 1 : 2;
547
4.06k
  MWAWColor colors[2];
548
9.76k
  for (int i=0; i<numColors; ++i) {
549
6.11k
    if (fill.m_colorId[i]==0) {
550
2.02k
      colors[i]=MWAWColor::white();
551
2.02k
      continue;
552
2.02k
    }
553
4.09k
    if (m_zIdToColorMap.find(fill.m_colorId[i])==m_zIdToColorMap.end()) {
554
415
      MWAW_DEBUG_MSG(("FreeHandParserInternal::State::updateFillStyle: can not find some color %d\n", fill.m_colorId[i]));
555
415
      return false;
556
415
    }
557
3.68k
    colors[i]=m_zIdToColorMap.find(fill.m_colorId[i])->second;
558
3.68k
  }
559
3.65k
  if (!fill.m_pattern.empty()) {
560
689
    auto pat=fill.m_pattern;
561
689
    pat.m_colors[0]=MWAWColor::white();
562
689
    pat.m_colors[1]=colors[0];
563
689
    style.setPattern(pat);
564
689
    return true;
565
689
  }
566
2.96k
  if (fill.m_type==MWAWGraphicStyle::Gradient::G_None) {
567
969
    style.setSurfaceColor(colors[0]);
568
969
    return true;
569
969
  }
570
1.99k
  auto &finalGrad=style.m_gradient;
571
1.99k
  finalGrad.m_type = fill.m_type;
572
1.99k
  finalGrad.m_angle = 270.f-fill.m_angle;
573
1.99k
  finalGrad.m_stopList.resize(2);
574
5.97k
  for (size_t i=0; i<2; ++i)
575
3.98k
    finalGrad.m_stopList[i]=MWAWGraphicStyle::Gradient::Stop(float(i), colors[i]);
576
1.99k
  return true;
577
2.96k
}
578
579
bool State::updateLineStyle(int zId, MWAWGraphicStyle &style) const
580
17.9k
{
581
17.9k
  if (!zId) {
582
131
    style.m_lineWidth=0;
583
131
    return true;
584
131
  }
585
17.8k
  if (m_zIdToLineStyleMap.find(zId)==m_zIdToLineStyleMap.end()) {
586
14.4k
    MWAW_DEBUG_MSG(("FreeHandParserInternal::State::updateLineStyle: can not find style %d\n", zId));
587
14.4k
    style.m_lineWidth=1;
588
14.4k
    return false;
589
14.4k
  }
590
3.33k
  LineStyle const &line=m_zIdToLineStyleMap.find(zId)->second;
591
3.33k
  style.m_lineWidth=line.m_width;
592
3.33k
  MWAWColor color=MWAWColor::white();
593
3.33k
  if (line.m_colorId) {
594
3.22k
    if (m_zIdToColorMap.find(line.m_colorId)==m_zIdToColorMap.end()) {
595
932
      static bool first=true;
596
932
      if (first) {
597
13
        first=false;
598
13
        MWAW_DEBUG_MSG(("FreeHandParserInternal::State::updateLineStyle: can not find some color %d\n", line.m_colorId));
599
13
      }
600
932
    }
601
2.29k
    else
602
2.29k
      color=m_zIdToColorMap.find(line.m_colorId)->second;
603
3.22k
  }
604
3.33k
  if (!line.m_pattern.empty()) {
605
19
    auto pat=line.m_pattern;
606
    // CHECKME
607
19
    pat.m_colors[0]=MWAWColor::white();
608
19
    pat.m_colors[1]=color;
609
19
    pat.getAverageColor(style.m_lineColor);
610
19
  }
611
3.31k
  else
612
3.31k
    style.m_lineColor=color;
613
3.33k
  if (line.m_dashId) {
614
920
    if (m_zIdToDashMap.find(line.m_dashId)==m_zIdToDashMap.end()) {
615
500
      MWAW_DEBUG_MSG(("FreeHandParserInternal::State::updateLineStyle: can not find dash %d\n", line.m_dashId));
616
500
    }
617
420
    else if (m_zIdToDashMap.find(line.m_dashId)->second.size()>1)
618
406
      style.m_lineDashWidth=m_zIdToDashMap.find(line.m_dashId)->second;
619
920
  }
620
3.33k
  style.m_lineCap=line.m_cap;
621
3.33k
  style.m_lineJoin=line.m_join;
622
3.33k
  return true;
623
17.8k
}
624
625
int State::updateGroupLayerId(int zId, std::set<int> &seen)
626
55.2k
{
627
55.2k
  if (m_zIdToTextboxMap.find(zId)!=m_zIdToTextboxMap.end())
628
2.91k
    return m_zIdToTextboxMap.find(zId)->second.m_layerId;
629
52.3k
  if (m_zIdToShapeMap.find(zId)==m_zIdToShapeMap.end())
630
29.5k
    return -1;
631
22.8k
  Shape &shape=m_zIdToShapeMap.find(zId)->second;
632
22.8k
  if (seen.find(zId)!=seen.end() || (shape.m_type!=Shape::Group && shape.m_type!=Shape::JoinGroup))
633
18.3k
    return shape.m_layerId;
634
4.49k
  int layerId=-1;
635
4.49k
  seen.insert(zId);
636
4.49k
  bool first=true;
637
52.1k
  for (auto const &child : shape.m_childs) {
638
52.1k
    int newLayerId=updateGroupLayerId(child, seen);
639
52.1k
    if (newLayerId==-1 || (!first && layerId!=newLayerId))
640
37.2k
      layerId=-1;
641
14.9k
    else
642
14.9k
      layerId=newLayerId;
643
52.1k
    first=false;
644
52.1k
  }
645
4.49k
  shape.m_layerId=layerId;
646
4.49k
  seen.erase(zId);
647
4.49k
  return layerId;
648
22.8k
}
649
650
////////////////////////////////////////
651
//! Internal: the subdocument of a FreeHandParser
652
class SubDocument final : public MWAWSubDocument
653
{
654
public:
655
  SubDocument(FreeHandParser &pars, MWAWInputStreamPtr const &input, int zoneId)
656
2.91k
    : MWAWSubDocument(&pars, input, MWAWEntry())
657
2.91k
    , m_id(zoneId) {}
658
659
  //! destructor
660
0
  ~SubDocument() final {}
661
662
  //! operator!=
663
  bool operator!=(MWAWSubDocument const &doc) const final
664
0
  {
665
0
    if (MWAWSubDocument::operator!=(doc)) return true;
666
0
    auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
667
0
    if (!sDoc) return true;
668
0
    if (m_id != sDoc->m_id) return true;
669
0
    return false;
670
0
  }
671
672
  //! the parser function
673
  void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
674
675
protected:
676
  //! the subdocument id
677
  int m_id;
678
private:
679
  SubDocument(SubDocument const &orig);
680
  SubDocument &operator=(SubDocument const &orig);
681
};
682
683
void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType)
684
2.91k
{
685
2.91k
  if (!listener || !listener->canWriteText()) {
686
0
    MWAW_DEBUG_MSG(("FreeHandParserInternal::SubDocument::parse: no listener\n"));
687
0
    return;
688
0
  }
689
2.91k
  auto *parser=dynamic_cast<FreeHandParser *>(m_parser);
690
2.91k
  if (!parser) {
691
0
    MWAW_DEBUG_MSG(("FreeHandParserInternal::SubDocument::parse: no parser\n"));
692
0
    return;
693
0
  }
694
2.91k
  long pos = m_input->tell();
695
2.91k
  parser->sendText(m_id);
696
2.91k
  m_input->seek(pos, librevenge::RVNG_SEEK_SET);
697
2.91k
}
698
699
}
700
701
////////////////////////////////////////////////////////////
702
// constructor/destructor, ...
703
////////////////////////////////////////////////////////////
704
FreeHandParser::FreeHandParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header)
705
62.7k
  : MWAWGraphicParser(input, rsrcParser, header)
706
62.7k
  , m_state()
707
62.7k
{
708
62.7k
  init();
709
62.7k
}
710
711
FreeHandParser::~FreeHandParser()
712
62.7k
{
713
62.7k
}
714
715
void FreeHandParser::init()
716
62.7k
{
717
62.7k
  resetGraphicListener();
718
62.7k
  setAsciiName("main-1");
719
720
62.7k
  m_state.reset(new FreeHandParserInternal::State);
721
722
62.7k
  getPageSpan().setMargins(0.1);
723
62.7k
}
724
725
////////////////////////////////////////////////////////////
726
// the parser
727
////////////////////////////////////////////////////////////
728
void FreeHandParser::parse(librevenge::RVNGDrawingInterface *docInterface)
729
21.8k
{
730
21.8k
  if (!getInput().get() || !checkHeader(nullptr))  throw(libmwaw::ParseException());
731
21.8k
  bool ok = false;
732
21.8k
  try {
733
    // create the asciiFile
734
21.8k
    ascii().setStream(getInput());
735
21.8k
    ascii().open(asciiName());
736
21.8k
    checkHeader(nullptr);
737
21.8k
    ok = createZones();
738
21.8k
    if (ok) {
739
6.69k
      createDocument(docInterface);
740
6.69k
      sendZone(m_state->m_mainGroupId, m_state->m_transform);
741
#ifdef DEBUG
742
      flushExtra();
743
#endif
744
6.69k
    }
745
21.8k
    ascii().reset();
746
21.8k
  }
747
21.8k
  catch (...) {
748
0
    MWAW_DEBUG_MSG(("FreeHandParser::parse: exception catched when parsing\n"));
749
0
    ok = false;
750
0
  }
751
752
21.8k
  resetGraphicListener();
753
21.8k
  if (!ok) throw(libmwaw::ParseException());
754
21.8k
}
755
756
////////////////////////////////////////////////////////////
757
// create the document
758
////////////////////////////////////////////////////////////
759
void FreeHandParser::createDocument(librevenge::RVNGDrawingInterface *documentInterface)
760
6.69k
{
761
6.69k
  if (!documentInterface) return;
762
6.69k
  if (getGraphicListener()) {
763
0
    MWAW_DEBUG_MSG(("FreeHandParser::createDocument: listener already exist\n"));
764
0
    return;
765
0
  }
766
767
  // create the page list
768
6.69k
  MWAWPageSpan ps(getPageSpan());
769
6.69k
  ps.setPageSpan(1);
770
6.69k
  std::vector<MWAWPageSpan> pageList(1,ps);
771
6.69k
  MWAWGraphicListenerPtr listen(new MWAWGraphicListener(*getParserState(), pageList, documentInterface));
772
6.69k
  setGraphicListener(listen);
773
6.69k
  listen->startDocument();
774
6.69k
}
775
776
////////////////////////////////////////////////////////////
777
//
778
// Intermediate level
779
//
780
////////////////////////////////////////////////////////////
781
bool FreeHandParser::createZones()
782
21.8k
{
783
21.8k
  MWAWInputStreamPtr input = getInput();
784
21.8k
  long pos;
785
21.8k
  libmwaw::DebugStream f;
786
21.8k
  bool readSome=false;
787
21.8k
  int zId=1;
788
21.8k
  int const vers=version();
789
21.8k
  if (vers==2) {
790
6.21k
    pos=input->tell();
791
6.21k
    libmwaw::PrinterInfo info;
792
6.21k
    if (!info.read(input)) {
793
5.93k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
794
5.93k
      if (input->readULong(4)==0) { // null print info is ok
795
1.86k
        ascii().addPos(pos);
796
1.86k
        ascii().addNote("_");
797
1.86k
        input->seek(pos+0x78, librevenge::RVNG_SEEK_SET);
798
1.86k
      }
799
4.06k
      else
800
4.06k
        input->seek(pos, librevenge::RVNG_SEEK_SET);
801
5.93k
    }
802
287
    else {
803
287
      f.str("");
804
287
      f << "Entries(PrintInfo):" << info;
805
287
      ascii().addPos(pos);
806
287
      ascii().addNote(f.str().c_str());
807
287
    }
808
6.21k
  }
809
482k
  while (!input->isEnd()) {
810
481k
    pos=input->tell();
811
618k
    while ((vers==1 && readZoneV1(zId)) || (vers==2 && readZoneV2(zId))) {
812
136k
      readSome=true;
813
136k
      pos=input->tell();
814
136k
      if (zId) ++zId;
815
136k
    }
816
481k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
817
481k
    if (!input->checkPosition(pos+5))
818
1.27k
      break;
819
    // ok try to continue
820
480k
    bool ok=true;
821
480k
    zId=0;
822
45.7M
    while (!input->isEnd()) {
823
45.7M
      auto val=static_cast<unsigned long>(input->readULong(4));
824
45.7M
      if (input->isEnd()) {
825
19.9k
        input->seek(pos, librevenge::RVNG_SEEK_SET);
826
19.9k
        ok=false;
827
19.9k
        break;
828
19.9k
      }
829
45.6M
      if (!val || (val&0xFF00)) {
830
35.8M
        input->seek(-1, librevenge::RVNG_SEEK_CUR);
831
35.8M
        continue;
832
35.8M
      }
833
9.83M
      if (val&0xFF0000) {
834
4.39M
        input->seek(-2, librevenge::RVNG_SEEK_CUR);
835
4.39M
        continue;
836
4.39M
      }
837
5.43M
      if (val&0xFF000000) {
838
1.70M
        input->seek(-3, librevenge::RVNG_SEEK_CUR);
839
1.70M
        continue;
840
1.70M
      }
841
3.73M
      input->seek(-4, librevenge::RVNG_SEEK_CUR);
842
3.73M
      long actPos=input->tell();
843
3.73M
      if ((vers==1 && readZoneV1(zId)) || (vers==2 && readZoneV2(zId))) {
844
460k
        if (pos!=actPos) {
845
460k
          MWAW_DEBUG_MSG(("FreeHandParser::createZones: find some unexpected data\n"));
846
460k
          ascii().addPos(pos);
847
460k
          ascii().addNote("Entries(Unknown):###");
848
460k
        }
849
460k
        break;
850
460k
      }
851
3.27M
      input->seek(actPos+4, librevenge::RVNG_SEEK_SET);
852
3.27M
    }
853
480k
    if (!ok) break;
854
480k
  }
855
21.8k
  pos=input->tell();
856
21.8k
  f.str("");
857
21.8k
  f << "Entries(End):";
858
21.8k
  if (input->readLong(4)!=-1) {
859
21.1k
    MWAW_DEBUG_MSG(("FreeHandParser::createZones: find unexpected end data\n"));
860
21.1k
    f << "###";
861
21.1k
  }
862
21.8k
  if (readSome && m_state->m_mainGroupId) {
863
3.08k
    std::set<int> seen;
864
3.08k
    m_state->updateGroupLayerId(m_state->m_mainGroupId, seen);
865
3.08k
  }
866
21.8k
  ascii().addPos(pos);
867
21.8k
  ascii().addNote(f.str().c_str());
868
21.8k
  return readSome;
869
21.8k
}
870
871
bool FreeHandParser::readZoneV1(int zId)
872
2.58M
{
873
2.58M
  MWAWInputStreamPtr input = getInput();
874
2.58M
  long pos=input->tell();
875
2.58M
  if (!input->checkPosition(pos+5))
876
965
    return false;
877
2.58M
  auto val=static_cast<int>(input->readULong(4));
878
2.58M
  if (val < 0 || (static_cast<unsigned long>(val)&0xFF000000)) {
879
167k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
880
167k
    return false;
881
167k
  }
882
2.41M
  auto type=static_cast<int>(input->readULong(2));
883
2.41M
  input->seek(pos, librevenge::RVNG_SEEK_SET);
884
2.41M
  switch (type) {
885
  // does type=1 exist ?
886
53.0k
  case 2:
887
53.0k
    return readStyleGroup(zId);
888
66.5k
  case 3:
889
66.5k
    return readStringZone(zId);
890
891
  // 4001-4002
892
5.00k
  case 0xfa1:
893
5.00k
    return readRootGroup(zId);
894
67.8k
  case 0xfa2:
895
67.8k
    return readGroupV1(zId);
896
897
  // 4101-4104
898
10.7k
  case 0x1005:
899
10.7k
    return readTransformGroup(zId);
900
95.9k
  case 0x1006:
901
95.9k
    return readTextboxV1(zId);
902
48.5k
  case 0x1007:
903
48.5k
    return readBackgroundPicture(zId);
904
12.0k
  case 0x1008:
905
12.0k
    return readJoinGroup(zId);
906
907
  // 4202-4204
908
  // does type=0x1069 exist ?
909
7.56k
  case 0x106a:
910
50.4k
  case 0x106b:
911
56.2k
  case 0x106c:
912
56.2k
    return readColor(zId);
913
914
  // 4301-4305
915
18.9k
  case 0x10cd:
916
18.9k
    return readFillStyle(zId);
917
114k
  case 0x10ce:
918
114k
    return readLineStyle(zId);
919
69.3k
  case 0x10cf:
920
69.3k
    return readPostscriptStyle(zId);
921
17.5k
  case 0x10d0:
922
46.5k
  case 0x10d1:
923
46.5k
    return readFillStyle(zId);
924
925
  // 4401-4405
926
20.6k
  case 0x1131: // rectangle
927
71.6k
  case 0x1132: // ellipse
928
  // does type=0x1133 exist ?
929
95.8k
  case 0x1134: // spline
930
106k
  case 0x1135: // line
931
106k
    return readShape(zId);
932
933
  // 4501
934
44.3k
  case 0x1195:
935
44.3k
    return readDash(zId);
936
1.60M
  default:
937
1.60M
    break;
938
2.41M
  }
939
1.60M
  input->seek(pos, librevenge::RVNG_SEEK_SET);
940
1.60M
  return false;
941
2.41M
}
942
943
bool FreeHandParser::readZoneV2(int zId)
944
1.76M
{
945
1.76M
  MWAWInputStreamPtr input = getInput();
946
1.76M
  long pos=input->tell();
947
1.76M
  if (!input->checkPosition(pos+5))
948
308
    return false;
949
1.76M
  auto val=static_cast<int>(input->readULong(4));
950
1.76M
  if (val < 0 || (static_cast<unsigned long>(val)&0xFF000000)) {
951
116k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
952
116k
    return false;
953
116k
  }
954
1.64M
  auto type=static_cast<int>(input->readULong(2));
955
1.64M
  input->seek(pos, librevenge::RVNG_SEEK_SET);
956
1.64M
  switch (type) {
957
39.6k
  case 5: // style group
958
39.6k
    return readStyleGroup(zId);
959
16.3k
  case 6:
960
16.3k
    return readStringZone(zId);
961
2.88k
  case 0x1389:
962
2.88k
    return readRootGroup(zId);
963
24.9k
  case 0x138a:
964
24.9k
    return readGroupV2(zId);
965
5.65k
  case 0x138b:
966
5.65k
    return readDataZone(zId);
967
8.26k
  case 0x13ed:
968
8.26k
    return readTransformGroup(zId);
969
76.0k
  case 0x13ee:
970
76.0k
    return readTextboxV2(zId);
971
2.92k
  case 0x13f0:
972
2.92k
    return readJoinGroup(zId);
973
117k
  case 0x13f8:
974
117k
    return readPictureZone(zId);
975
4.85k
  case 0x1452: // basic
976
7.29k
  case 0x1453: // tint
977
17.0k
  case 0x1454: // cmyk
978
20.4k
  case 0x1455: // pantome ?
979
20.4k
    return readColor(zId);
980
4.90k
  case 0x14b5: // basic
981
4.90k
    return readFillStyle(zId);
982
4.46k
  case 0x14b6: // line style
983
4.46k
    return readLineStyle(zId);
984
6.19k
  case 0x14b7: // gradient linear
985
8.48k
  case 0x14b8: // radial
986
8.48k
    return readFillStyle(zId);
987
2.58k
  case 0x14c9: // line, always follow 14d3
988
5.12k
  case 0x14ca: // surf, always follow 14d4
989
5.12k
    return readPostscriptStyle(zId);
990
4.24k
  case 0x14d3: // pattern
991
4.24k
    return readFillStyle(zId);
992
1.29k
  case 0x14d4: // pattern line style
993
1.29k
    return readLineStyle(zId);
994
2.56k
  case 0x14dd: // tile style
995
2.56k
    return readFillStyle(zId);
996
9.83k
  case 0x1519: // rectangle
997
14.6k
  case 0x151a: // ellipse
998
14.6k
    return readShape(zId);
999
31.5k
  case 0x151c:
1000
31.5k
    return readShape(zId);
1001
7.86k
  case 0x151d: // line
1002
7.86k
    return readShape(zId);
1003
10.4k
  case 0x157d:
1004
10.4k
    return readDash(zId);
1005
1.23M
  default:
1006
1.23M
    break;
1007
1.64M
  }
1008
1.23M
  input->seek(pos, librevenge::RVNG_SEEK_SET);
1009
1.23M
  return false;
1010
1.64M
}
1011
1012
////////////////////////////////////////////////////////////
1013
// read the header
1014
////////////////////////////////////////////////////////////
1015
bool FreeHandParser::checkHeader(MWAWHeader *header, bool strict)
1016
84.5k
{
1017
84.5k
  *m_state = FreeHandParserInternal::State();
1018
84.5k
  MWAWInputStreamPtr input = getInput();
1019
84.5k
  if (!input || !input->hasDataFork() || !input->checkPosition(128))
1020
250
    return false;
1021
1022
84.2k
  libmwaw::DebugStream f;
1023
84.2k
  f << "FileHeader:";
1024
84.2k
  input->seek(0, librevenge::RVNG_SEEK_SET);
1025
84.2k
  auto signature=long(input->readULong(4));
1026
84.2k
  int vers=1, val;
1027
84.2k
  if (signature==0x61636633) {
1028
59.6k
    val=static_cast<int>(input->readULong(2)); // the subversion?
1029
59.6k
    if (strict && val>=9) return false;
1030
59.5k
    if (val!=5)
1031
53.5k
      f << "f0=" << val << ",";
1032
59.5k
  }
1033
24.6k
  else if (signature==0x46484432) {
1034
24.3k
    if (!input->checkPosition(256))
1035
66
      return false;
1036
24.2k
    vers=2;
1037
24.2k
    val=static_cast<int>(input->readULong(2)); // the subversion?
1038
24.2k
    if (strict && val>20) return false;
1039
24.1k
    if (val!=9)
1040
19.4k
      f << "f0=" << val << ",";
1041
24.1k
  }
1042
316
  else
1043
316
    return false;
1044
83.7k
  val=static_cast<int>(input->readULong(2));
1045
83.7k
  if (val!=100) f << "f1=" << val << ",";
1046
83.7k
  float dim[8];
1047
669k
  for (auto &d : dim) d=float(input->readLong(2))/10.f;
1048
83.7k
  f << "page[sz]=" << MWAWVec2f(dim[0],dim[1]) << ",";
1049
83.7k
  f << "paper[sz]=" << MWAWVec2f(dim[2],dim[3]) << ",";
1050
83.7k
  if (dim[4]>0 || dim[5]>0)
1051
52.3k
    f << "unkn[sz]=" << MWAWVec2f(dim[4],dim[5]) << ",";
1052
83.7k
  f << "margins=" << MWAWVec2f(dim[6],dim[7]) << ",";
1053
83.7k
  if (vers>1) {
1054
24.1k
    ascii().addDelimiter(input->tell(),'|');
1055
24.1k
    input->seek(30, librevenge::RVNG_SEEK_CUR);
1056
96.5k
    for (int i=0; i<3; ++i) {
1057
72.4k
      val=static_cast<int>(input->readULong(2));
1058
72.4k
      if (!val) continue;
1059
      // checkme: odd
1060
44.0k
      if (i==0 && (val&0x20) && dim[0]>dim[1]) {
1061
1.90k
        f << "landscape,";
1062
1.90k
        getPageSpan().setFormOrientation(MWAWPageSpan::LANDSCAPE);
1063
9.53k
        for (int j=0; j<4; ++j) {
1064
7.62k
          if (j==1) continue;
1065
5.71k
          std::swap(dim[2*j],dim[2*j+1]);
1066
5.71k
        }
1067
1.90k
        val &= 0xFFDF;
1068
1.90k
      }
1069
44.0k
      if (val)
1070
44.0k
        f << i+2 << "=" << std::hex << val << std::dec << ",";
1071
44.0k
    }
1072
24.1k
  }
1073
59.5k
  else {
1074
178k
    for (int i=0; i<2; ++i) { // f2=1|2|a
1075
119k
      val=static_cast<int>(input->readULong(2));
1076
119k
      if (!val) continue;
1077
84.4k
      if (i==1) {
1078
39.8k
        if (val&1) {
1079
19.9k
          f << "landscape,";
1080
19.9k
          getPageSpan().setFormOrientation(MWAWPageSpan::LANDSCAPE);
1081
99.8k
          for (int j=0; j<4; ++j)
1082
79.9k
            std::swap(dim[2*j],dim[2*j+1]);
1083
19.9k
        }
1084
39.8k
        if (val&2) f << "crop[mark],";
1085
39.8k
        if (val&4) f << "center[mark],";
1086
39.8k
        if (val&8) f << "separation[name],";
1087
39.8k
        if (val&0x10) f << "file[name&date],";
1088
39.8k
        if (val&0x40) f << "include[processColor],";
1089
39.8k
        if (val&0x80) f << "display[quality]=better,";
1090
39.8k
        if (val&0x100) f << "print[quality]=better,";
1091
39.8k
        val &= 0xFE20;
1092
39.8k
      }
1093
84.4k
      if (val)
1094
80.2k
        f << "f" << i+2 << "=" << std::hex << val << std::dec << ",";
1095
84.4k
    }
1096
59.5k
  }
1097
83.7k
  if (dim[2]>0 && dim[3]>0) {
1098
42.9k
    getPageSpan().setFormLength(double(dim[2])/72.);
1099
42.9k
    getPageSpan().setFormWidth(double(dim[3])/72.);
1100
42.9k
    if (dim[0]+dim[6]<=dim[2]) {
1101
29.6k
      getPageSpan().setMarginBottom(double(dim[6])/72.0);
1102
29.6k
      getPageSpan().setMarginTop(double(dim[2]-dim[0]-dim[6])/72.0);
1103
29.6k
    }
1104
13.2k
    else {
1105
13.2k
      MWAW_DEBUG_MSG(("FreeHandParser::checkHeader: the vertical margins seems bad\n"));
1106
13.2k
      if (dim[0]<=dim[2]) {
1107
9.22k
        getPageSpan().setMarginBottom(double(dim[2]-dim[0])/2.0/72.0);
1108
9.22k
        getPageSpan().setMarginTop(double(dim[2]-dim[0])/2.0/72.0);
1109
9.22k
      }
1110
13.2k
    }
1111
42.9k
    if (dim[1]+dim[7]<=dim[3]) {
1112
29.7k
      getPageSpan().setMarginRight(double(dim[7])/72.0);
1113
29.7k
      getPageSpan().setMarginLeft(double(dim[3]-dim[1]-dim[7])/72.0);
1114
29.7k
    }
1115
13.1k
    else {
1116
13.1k
      MWAW_DEBUG_MSG(("FreeHandParser::checkHeader: the horizontal margins seems bad\n"));
1117
13.1k
      if (dim[1]<=dim[3]) {
1118
8.20k
        getPageSpan().setMarginLeft(double(dim[3]-dim[1])/2.0/72.0);
1119
8.20k
        getPageSpan().setMarginRight(double(dim[3]-dim[1])/2.0/72.0);
1120
8.20k
      }
1121
13.1k
    }
1122
42.9k
  }
1123
40.7k
  else {
1124
40.7k
    if (strict)
1125
10.1k
      return false;
1126
30.6k
    MWAW_DEBUG_MSG(("FreeHandParser::checkHeader: the paper size seems bad\n"));
1127
30.6k
  }
1128
  // transform orig from page content LeftBot -> origin form page LeftTop
1129
73.5k
  m_state->m_transform=
1130
73.5k
    MWAWTransformation::translation(72.f *MWAWVec2f(float(getPageSpan().getMarginLeft()),float(getPageSpan().getPageLength()+getPageSpan().getMarginTop()))) *
1131
73.5k
    MWAWTransformation::scale(MWAWVec2f(1, -1));
1132
73.5k
  if (vers==1) {
1133
52.7k
    val=static_cast<int>(input->readULong(4));
1134
52.7k
    switch ((val>>29)) {
1135
33.4k
    case 0: // point
1136
33.4k
      break;
1137
5.51k
    case 1:
1138
5.51k
      f << "unit=picas,";
1139
5.51k
      break;
1140
4.17k
    case 2:
1141
4.17k
      f << "unit=inches,";
1142
4.17k
      break;
1143
1.67k
    case 3:
1144
1.67k
      f << "unit=decimal[inches],";
1145
1.67k
      break;
1146
0
    case 4:
1147
0
      f << "unit=millimeters,";
1148
0
      break;
1149
7.87k
    default:
1150
7.87k
      MWAW_DEBUG_MSG(("FreeHandParser::checkHeader: find unknown unit\n"));
1151
7.87k
      f << "##units=" << ((val>>29)&7) << ",";
1152
52.7k
    }
1153
52.7k
    val &= 0x1FFF;
1154
52.7k
    if (val) f << "grid[size]=" << float(val)/65536.f/10.f << ",";
1155
263k
    for (int i=0; i<4; ++i) { // f4=0|200
1156
210k
      val=static_cast<int>(input->readULong(2));
1157
210k
      if (val)
1158
135k
        f << "f" << i+4 << "=" << std::hex << val << std::dec << ",";
1159
210k
    }
1160
52.7k
  }
1161
1162
215k
  for (int i=0; i<2; ++i) {
1163
    // checkme no sure what are limit
1164
145k
    long actPos=input->tell();
1165
145k
    auto sSz=static_cast<int>(input->readULong(1));
1166
145k
    if (sSz>31) {
1167
39.0k
      if (strict) return false;
1168
35.7k
      MWAW_DEBUG_MSG(("FreeHandParser::checkHeader: string size %d seems bad\n", i));
1169
35.7k
      f << "##sSz,";
1170
35.7k
      sSz=0;
1171
35.7k
    }
1172
141k
    std::string name;
1173
562k
    for (int s=0; s<sSz; ++s) name+=char(input->readULong(1));
1174
141k
    if (!name.empty()) {
1175
46.3k
      char const *wh[]= {"printer", "paper"};
1176
46.3k
      f << wh[i] << "=" << name << ",";
1177
46.3k
    }
1178
141k
    input->seek(actPos+32, librevenge::RVNG_SEEK_SET);
1179
141k
  }
1180
70.2k
  if (vers==1) {
1181
300k
    for (int i=0; i<5; ++i) { // g0=0|41, g1=0|3-7, g3=0|20, g4=0|b4
1182
250k
      val=static_cast<int>(input->readULong(2));
1183
250k
      if (val)
1184
169k
        f << "g" << i << "=" << std::hex << val << std::dec << ",";
1185
250k
    }
1186
    // big number
1187
50.1k
    f << "unkn=" << std::hex << input->readULong(4) << std::dec << ",";
1188
300k
    for (int i=0; i<5; ++i) { // always 0
1189
250k
      val=static_cast<int>(input->readULong(2));
1190
250k
      if (val)
1191
158k
        f << "h" << i << "=" << val << ",";
1192
250k
    }
1193
50.1k
  }
1194
20.0k
  else {
1195
20.0k
    ascii().addDelimiter(input->tell(),'|');
1196
20.0k
    f << "unkn=" << std::hex << input->readULong(4) << std::dec << ",";
1197
    // always 0
1198
1.30M
    for (int i=0; i<64; ++i) {
1199
1.28M
      val=static_cast<int>(input->readULong(2));
1200
1.28M
      if (val)
1201
712k
        f << "h" << i << "=" << val << ",";
1202
1.28M
    }
1203
    // check for printer info or null printer info
1204
20.0k
    if (strict) {
1205
2.84k
      libmwaw::PrinterInfo info;
1206
2.84k
      if (!info.read(input)) {
1207
2.60k
        input->seek(256, librevenge::RVNG_SEEK_SET);
1208
2.60k
        if (input->readULong(4))
1209
550
          return false;
1210
2.60k
      }
1211
2.84k
    }
1212
20.0k
  }
1213
69.6k
  ascii().addPos(0);
1214
69.6k
  ascii().addNote(f.str().c_str());
1215
69.6k
  setVersion(vers);
1216
69.6k
  if (header)
1217
26.0k
    header->reset(MWAWDocument::MWAW_T_FREEHAND, vers, MWAWDocument::MWAW_K_DRAW);
1218
69.6k
  input->seek(vers==1 ? 128 : 256, librevenge::RVNG_SEEK_SET);
1219
1220
69.6k
  return true;
1221
70.2k
}
1222
1223
////////////////////////////////////////////////////////////
1224
// try to read the zone
1225
////////////////////////////////////////////////////////////
1226
bool FreeHandParser::readRootGroup(int zId)
1227
7.88k
{
1228
7.88k
  if ((zId && zId!=1) || !m_state->m_zIdToTypeMap.empty())
1229
3.26k
    return false;
1230
4.62k
  MWAWInputStreamPtr input = getInput();
1231
4.62k
  libmwaw::DebugStream f;
1232
1233
4.62k
  long pos=input->tell();
1234
4.62k
  int const vers=version();
1235
4.62k
  if (!input->checkPosition(pos+(vers==1 ? 24 : 34)))
1236
40
    return false;
1237
4.58k
  f.str("");
1238
4.58k
  f << "Entries(Root):";
1239
4.58k
  auto dSz=static_cast<int>(input->readULong(4)); // probably related to size
1240
4.58k
  auto opCode=static_cast<int>(input->readULong(2));
1241
4.58k
  if ((vers==1 && opCode !=0xfa1) || (vers>1 && opCode != 0x1389))
1242
0
    return false;
1243
4.58k
  if (vers>1) dSz-=4;
1244
4.58k
  if (dSz!=0x34) {
1245
1.50k
    MWAW_DEBUG_MSG(("FreeHandParser::readRootGroup: find unexpected zone size\n"));
1246
1.50k
    f << "#sz?=" << dSz << ",";
1247
1.50k
  }
1248
4.58k
  if (vers==1) {
1249
9.04k
    for (int i=0; i<2; ++i) { // always 0 ?
1250
6.03k
      auto val=static_cast<int>(input->readLong(2));
1251
6.03k
      if (!val) continue;
1252
1.24k
      MWAW_DEBUG_MSG(("FreeHandParser::readRootGroup: find unknown zone %d\n", i));
1253
1.24k
      f << "#f" << i << "=" << val << ",";
1254
1.24k
    }
1255
3.01k
  }
1256
4.58k
  auto id=static_cast<int>(input->readLong(2));
1257
4.58k
  if (id) {
1258
3.28k
    m_state->m_mainGroupId=id;
1259
3.28k
    m_state->addZoneId(id, FreeHandParserInternal::Z_Group);
1260
3.28k
    f << "main=Z" << id << ",";
1261
3.28k
  }
1262
4.58k
  if (vers==1) {
1263
21.1k
    for (int i=0; i<6; ++i) {
1264
18.0k
      id=static_cast<int>(input->readLong(2));
1265
18.0k
      if (!id) continue;
1266
      // the first group is a style group, but I never find any child, so...
1267
7.85k
      FreeHandParserInternal::ZoneType type[6]= {
1268
7.85k
        FreeHandParserInternal::Z_StyleGroup, FreeHandParserInternal::Z_FillGroup, FreeHandParserInternal::Z_LineStyleGroup,
1269
7.85k
        FreeHandParserInternal::Z_ColorGroup, FreeHandParserInternal::Z_DashGroup, FreeHandParserInternal::Z_ColorGroup
1270
7.85k
      };
1271
7.85k
      if (!m_state->addZoneId(id, type[i])) {
1272
165
        MWAW_DEBUG_MSG(("FreeHandParser::readRootGroup: find dupplicated id\n"));
1273
165
        f << "###";
1274
165
      }
1275
7.85k
      char const *wh[6]= { "groupStyle0", "fillStyle", "lineStyle", "colStyle", "dashStyle", "colStyle2" };
1276
7.85k
      f << wh[i] << "=Z" << id << ",";
1277
7.85k
    }
1278
3.01k
  }
1279
1.57k
  else {
1280
    // at least 8, maybe more
1281
14.1k
    for (int i=0; i<8; ++i) {
1282
12.5k
      id=static_cast<int>(input->readLong(2));
1283
12.5k
      if (!id) continue;
1284
10.3k
      FreeHandParserInternal::ZoneType type[8]= {
1285
10.3k
        FreeHandParserInternal::Z_ColorGroup, FreeHandParserInternal::Z_FillGroup, FreeHandParserInternal::Z_LineStyleGroup,
1286
10.3k
        FreeHandParserInternal::Z_StyleGroup, FreeHandParserInternal::Z_FillGroup, FreeHandParserInternal::Z_LineStyleGroup,
1287
10.3k
        FreeHandParserInternal::Z_DashGroup, FreeHandParserInternal::Z_ColorGroup,
1288
10.3k
      };
1289
10.3k
      if (!m_state->addZoneId(id, type[i])) {
1290
284
        MWAW_DEBUG_MSG(("FreeHandParser::readRootGroup: find dupplicated id\n"));
1291
284
        f << "###";
1292
284
      }
1293
10.3k
      char const *wh[8]= { "colStyle", "fillStyle", "lineStyle", "groupStyle3", "fillStyle[unamed]", "lineStyle[unamed]", "dashStyle", "colStyle2"};
1294
10.3k
      f << wh[i] << "=Z" << id << ",";
1295
10.3k
    }
1296
9.43k
    for (int i=0; i<5; ++i) {
1297
7.86k
      auto val=static_cast<int>(input->readULong(2));
1298
7.86k
      if (!val) continue;
1299
751
      MWAW_DEBUG_MSG(("FreeHandParser::readRootGroup: find unknown group id\n"));
1300
751
      f << "###Z" << val << ",";
1301
751
    }
1302
1.57k
  }
1303
4.58k
  ascii().addPos(pos);
1304
4.58k
  ascii().addNote(f.str().c_str());
1305
1306
4.58k
  return true;
1307
4.58k
}
1308
1309
bool FreeHandParser::readGroupV1(int zId)
1310
67.8k
{
1311
67.8k
  MWAWInputStreamPtr input = getInput();
1312
67.8k
  libmwaw::DebugStream f;
1313
1314
67.8k
  long pos=input->tell();
1315
67.8k
  if (!input->checkPosition(pos+20))
1316
631
    return false;
1317
67.2k
  f.str("");
1318
67.2k
  if (zId)
1319
2.11k
    f << "Entries(Group)[Z" << zId << "]:";
1320
65.0k
  else
1321
65.0k
    f << "Entries(Group):";
1322
67.2k
  if (zId) {
1323
2.11k
    auto type=m_state->getZoneType(zId);
1324
2.11k
    if (type!=FreeHandParserInternal::Z_Group && type!=FreeHandParserInternal::Z_Shape) {
1325
252
      MWAW_DEBUG_MSG(("FreeHandParser::readGroupV1: find unexpected zone type for zone %d\n", zId));
1326
252
    }
1327
2.11k
  }
1328
1329
67.2k
  auto dSz=static_cast<int>(input->readULong(4)); // probably related to size
1330
67.2k
  f << "sz=" << dSz << ",";
1331
67.2k
  if (input->readULong(2)!=0xfa2) {
1332
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1333
0
    return false;
1334
0
  }
1335
67.2k
  FreeHandParserInternal::Shape res;
1336
67.2k
  res.m_id=zId;
1337
67.2k
  res.m_type=FreeHandParserInternal::Shape::Group;
1338
67.2k
  ascii().addDelimiter(input->tell(),'|');
1339
67.2k
  input->seek(pos+18, librevenge::RVNG_SEEK_SET);
1340
67.2k
  ascii().addDelimiter(input->tell(),'|');
1341
67.2k
  auto N=static_cast<int>(input->readULong(2));
1342
67.2k
  if (!input->checkPosition(pos+20+2*N)) {
1343
23.3k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1344
23.3k
    return false;
1345
23.3k
  }
1346
43.8k
  f << "childs=[";
1347
1.32M
  for (int i=0; i<N; ++i) {
1348
1.30M
    auto id=static_cast<int>(input->readULong(2));
1349
1.30M
    if (!m_state->addZoneId(id, FreeHandParserInternal::Z_Shape)) {
1350
22.6k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
1351
22.6k
      return false;
1352
22.6k
    }
1353
1.28M
    res.m_childs.push_back(id);
1354
1.28M
    f << "Z" << id << ",";
1355
1.28M
  }
1356
21.2k
  f <<"],";
1357
21.2k
  ascii().addPos(pos);
1358
21.2k
  ascii().addNote(f.str().c_str());
1359
21.2k
  if (zId && m_state->m_zIdToShapeMap.find(zId)==m_state->m_zIdToShapeMap.end())
1360
2.03k
    m_state->m_zIdToShapeMap.insert(std::map<int, FreeHandParserInternal::Shape>::value_type(zId,res));
1361
21.2k
  return true;
1362
43.8k
}
1363
1364
bool FreeHandParser::readGroupV2(int zId)
1365
24.9k
{
1366
24.9k
  MWAWInputStreamPtr input = getInput();
1367
24.9k
  libmwaw::DebugStream f;
1368
1369
24.9k
  long pos=input->tell();
1370
24.9k
  if (!input->checkPosition(pos+20))
1371
121
    return false;
1372
24.8k
  f.str("");
1373
24.8k
  if (zId)
1374
1.44k
    f << "Entries(Group)[Z" << zId << "]:";
1375
23.3k
  else
1376
23.3k
    f << "Entries(Group):";
1377
24.8k
  if (zId) {
1378
1.44k
    auto type=m_state->getZoneType(zId);
1379
1.44k
    if (type!=FreeHandParserInternal::Z_Group && type!=FreeHandParserInternal::Z_Shape) {
1380
68
      MWAW_DEBUG_MSG(("FreeHandParser::readGroupV2: find unexpected zone type for zone %d\n", zId));
1381
68
    }
1382
1.44k
  }
1383
1384
24.8k
  auto dSz=static_cast<int>(input->readULong(4)); // probably related to size
1385
24.8k
  f << "sz=" << dSz << ",";
1386
24.8k
  if (input->readULong(2)!=0x138a) {
1387
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1388
0
    return false;
1389
0
  }
1390
24.8k
  FreeHandParserInternal::Shape res;
1391
24.8k
  res.m_id=zId;
1392
24.8k
  res.m_type=FreeHandParserInternal::Shape::Group;
1393
74.4k
  for (int i=0; i<2; ++i) { // always 0
1394
49.6k
    auto val=static_cast<int>(input->readLong(2));
1395
49.6k
    if (val) f << "f" << i << "=" << val << ",";
1396
49.6k
  }
1397
24.8k
  auto sSz=static_cast<int>(input->readULong(2));
1398
24.8k
  if (!input->checkPosition(input->tell()+sSz+8)) {
1399
1.79k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1400
1.79k
    return false;
1401
1.79k
  }
1402
23.0k
  ascii().addDelimiter(input->tell(),'|');
1403
  /* find
1404
     00000000000000000000000000000000
1405
     000f000a000000000000000000000000a89d800180017fff7fff7fff7fff7fff7fff7fff7fff7fff7fff4ead7fff80017fff52807fff7fff7fff60144ead8fff670a
1406
   */
1407
23.0k
  input->seek(sSz, librevenge::RVNG_SEEK_CUR);
1408
23.0k
  ascii().addDelimiter(input->tell(),'|');
1409
23.0k
  float dim[2];
1410
46.0k
  for (auto &d : dim) d=float(input->readLong(2))/10.f;
1411
23.0k
  if (MWAWVec2f(dim[0],dim[1])!=MWAWVec2f(0,0))
1412
16.1k
    f << "dim?=" << MWAWVec2f(dim[0],dim[1]) << ",";
1413
23.0k
  auto val=static_cast<int>(input->readLong(2));
1414
23.0k
  if (val) f << "f2=" << val << ",";
1415
1416
23.0k
  auto N=static_cast<int>(input->readULong(2));
1417
23.0k
  if (!input->checkPosition(input->tell()+2*N)) {
1418
4.32k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1419
4.32k
    return false;
1420
4.32k
  }
1421
18.6k
  f << "childs=[";
1422
738k
  for (int i=0; i<N; ++i) {
1423
727k
    auto id=static_cast<int>(input->readULong(2));
1424
727k
    if (!m_state->addZoneId(id, FreeHandParserInternal::Z_Shape)) {
1425
7.22k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
1426
7.22k
      return false;
1427
7.22k
    }
1428
719k
    res.m_childs.push_back(id);
1429
719k
    f << "Z" << id << ",";
1430
719k
  }
1431
11.4k
  f <<"],";
1432
11.4k
  ascii().addPos(pos);
1433
11.4k
  ascii().addNote(f.str().c_str());
1434
11.4k
  if (zId && m_state->m_zIdToShapeMap.find(zId)==m_state->m_zIdToShapeMap.end())
1435
1.40k
    m_state->m_zIdToShapeMap.insert(std::map<int, FreeHandParserInternal::Shape>::value_type(zId,res));
1436
11.4k
  return true;
1437
18.6k
}
1438
1439
bool FreeHandParser::readJoinGroup(int zId)
1440
14.9k
{
1441
14.9k
  MWAWInputStreamPtr input = getInput();
1442
14.9k
  libmwaw::DebugStream f;
1443
1444
14.9k
  long pos=input->tell();
1445
14.9k
  FreeHandParserInternal::ShapeHeader shape;
1446
14.9k
  int const vers=version();
1447
14.9k
  if (!readShapeHeader(shape)) {
1448
3.24k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1449
3.24k
    return false;
1450
3.24k
  }
1451
11.7k
  if ((vers==1 && shape.m_type!=0x1008) || (vers>1 && shape.m_type!=0x13f0)
1452
11.7k
      || !input->checkPosition(input->tell()+8)) {
1453
155
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1454
155
    return false;
1455
155
  }
1456
11.5k
  f.str("");
1457
11.5k
  if (zId)
1458
191
    f << "Entries(JoinGrp)[Z" << zId << "]:" << shape;
1459
11.3k
  else
1460
11.3k
    f << "Entries(JoinGrp):" << shape;
1461
11.5k
  if (zId) {
1462
191
    auto type=m_state->getZoneType(zId);
1463
191
    if (type!=FreeHandParserInternal::Z_Shape) {
1464
182
      MWAW_DEBUG_MSG(("FreeHandParser::readJoinGroup: find unexpected zone type for zone %d\n", zId));
1465
182
    }
1466
191
  }
1467
11.5k
  FreeHandParserInternal::Shape res;
1468
11.5k
  res.m_id=zId;
1469
11.5k
  res.m_layerId=shape.m_layerId;
1470
11.5k
  res.m_type=FreeHandParserInternal::Shape::JoinGroup;
1471
11.5k
  if (shape.m_size!=0x24) f << "sz?=" << shape.m_size << ",";
1472
11.5k
  res.m_joinDistance=float(input->readLong(4))/65536.f;
1473
11.5k
  if (res.m_joinDistance<0 || res.m_joinDistance>0)
1474
11.0k
    f << "dist=" << res.m_joinDistance << ",";
1475
11.5k
  f << "childs=[";
1476
34.7k
  for (int i=0; i<2; ++i) {
1477
23.1k
    auto id=static_cast<int>(input->readULong(2));
1478
23.1k
    if (!m_state->addZoneId(id, FreeHandParserInternal::Z_Shape)) {
1479
1.32k
      MWAW_DEBUG_MSG(("FreeHandParser::readJoinGroup: find unexpected child id\n"));
1480
1.32k
      f << "###";
1481
1.32k
    }
1482
23.1k
    res.m_childs.push_back(id);
1483
23.1k
    f << "Z" << id << ",";
1484
23.1k
  }
1485
11.5k
  f <<"],";
1486
11.5k
  ascii().addPos(pos);
1487
11.5k
  ascii().addNote(f.str().c_str());
1488
11.5k
  if (zId && m_state->m_zIdToShapeMap.find(zId)==m_state->m_zIdToShapeMap.end())
1489
191
    m_state->m_zIdToShapeMap.insert(std::map<int, FreeHandParserInternal::Shape>::value_type(zId,res));
1490
11.5k
  static bool first=true;
1491
11.5k
  if (first) {
1492
13
    MWAW_DEBUG_MSG(("FreeHandParser::readJoinGroup: Ooops, sending text on path is unimplemented\n"));
1493
13
    first=false;
1494
13
  }
1495
11.5k
  return true;
1496
11.7k
}
1497
1498
bool FreeHandParser::readTransformGroup(int zId)
1499
18.9k
{
1500
18.9k
  MWAWInputStreamPtr input = getInput();
1501
18.9k
  libmwaw::DebugStream f;
1502
1503
18.9k
  long pos=input->tell();
1504
18.9k
  FreeHandParserInternal::ShapeHeader shape;
1505
18.9k
  if (!readShapeHeader(shape)) {
1506
4.96k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1507
4.96k
    return false;
1508
4.96k
  }
1509
14.0k
  int const vers=version();
1510
14.0k
  if ((vers==1 && shape.m_type!=0x1005) || (vers>1 && shape.m_type!=0x13ed) || !input->checkPosition(input->tell()+30)) {
1511
201
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1512
201
    return false;
1513
201
  }
1514
13.7k
  f.str("");
1515
13.7k
  if (zId)
1516
1.18k
    f << "Entries(TransformGrp)[Z" << zId << "]:" << shape;
1517
12.6k
  else
1518
12.6k
    f << "Entries(TransformGrp):" << shape;
1519
13.7k
  if (shape.m_size!=0x38) f << "sz?=" << shape.m_size << ",";
1520
13.7k
  if (zId) {
1521
1.18k
    auto zType=m_state->getZoneType(zId);
1522
1.18k
    if (zType!=FreeHandParserInternal::Z_Group && zType!=FreeHandParserInternal::Z_Shape) {
1523
106
      MWAW_DEBUG_MSG(("FreeHandParser::readTransformGroup: find unexpected zone type for zone %d\n", zId));
1524
106
    }
1525
1.18k
  }
1526
13.7k
  FreeHandParserInternal::Shape res;
1527
13.7k
  res.m_id=zId;
1528
13.7k
  res.m_layerId=shape.m_layerId;
1529
13.7k
  res.m_type=FreeHandParserInternal::Shape::Group;
1530
13.7k
  auto id=static_cast<int>(input->readULong(2));
1531
13.7k
  if (!m_state->addZoneId(id, FreeHandParserInternal::Z_Group)) {
1532
486
    MWAW_DEBUG_MSG(("FreeHandParser::readTransformGroup: find unexpected child id\n"));
1533
486
    f << "###";
1534
486
  }
1535
13.7k
  f << "child=Z" << id << ",";
1536
13.7k
  res.m_childs.push_back(id);
1537
13.7k
  auto val=static_cast<int>(input->readULong(2)); // always 0
1538
13.7k
  if (val) f << "f0=" << val << ",";
1539
13.7k
  f << "flags=" << std::hex << input->readULong(2) << std::dec << ",";
1540
13.7k
  f << "rot=[";
1541
13.7k
  float dim[6];
1542
68.9k
  for (int i=0; i<4; ++i) {
1543
55.1k
    dim[i]=float(input->readLong(4))/65536.f;
1544
55.1k
    f << dim[i] << ",";
1545
55.1k
  }
1546
13.7k
  f << "],";
1547
13.7k
  f << "trans=[";
1548
41.3k
  for (int i=0; i<2; ++i) {
1549
27.5k
    dim[i+4]=float(input->readLong(4))/65536.f/10.f;
1550
27.5k
    f << dim[i+4] << ",";
1551
27.5k
  }
1552
13.7k
  f << "],";
1553
13.7k
  res.m_transformation=MWAWTransformation(MWAWVec3f(dim[0],dim[2],dim[4]),MWAWVec3f(dim[1],dim[3],dim[5]));
1554
1555
13.7k
  ascii().addPos(pos);
1556
13.7k
  ascii().addNote(f.str().c_str());
1557
13.7k
  if (zId && m_state->m_zIdToShapeMap.find(zId)==m_state->m_zIdToShapeMap.end())
1558
1.18k
    m_state->m_zIdToShapeMap.insert(std::map<int, FreeHandParserInternal::Shape>::value_type(zId,res));
1559
13.7k
  return true;
1560
14.0k
}
1561
1562
bool FreeHandParser::readStyleGroup(int zId)
1563
92.7k
{
1564
92.7k
  int const vers=version();
1565
92.7k
  MWAWInputStreamPtr input = getInput();
1566
92.7k
  libmwaw::DebugStream f;
1567
1568
92.7k
  long pos=input->tell();
1569
92.7k
  if (!input->checkPosition(pos+(vers>1 ? 12 : 16)))
1570
265
    return false;
1571
92.4k
  f.str("");
1572
92.4k
  if (zId)
1573
14.5k
    f << "Entries(StyleGrp)[Z" << zId << "]:";
1574
77.9k
  else
1575
77.9k
    f << "Entries(StyleGrp):";
1576
92.4k
  auto cType=FreeHandParserInternal::Z_Unknown;
1577
92.4k
  bool checkDSize=true;
1578
92.4k
  if (zId) {
1579
14.5k
    auto zType=m_state->getZoneType(zId);
1580
14.5k
    checkDSize=false;
1581
14.5k
    if (zType==FreeHandParserInternal::Z_ColorGroup)
1582
2.74k
      cType=FreeHandParserInternal::Z_Color;
1583
11.8k
    else if (zType==FreeHandParserInternal::Z_DashGroup)
1584
2.53k
      cType=FreeHandParserInternal::Z_Dash;
1585
9.27k
    else if (zType==FreeHandParserInternal::Z_FillGroup)
1586
3.83k
      cType=FreeHandParserInternal::Z_Fill;
1587
5.44k
    else if (zType==FreeHandParserInternal::Z_LineStyleGroup)
1588
3.69k
      cType=FreeHandParserInternal::Z_LineStyle;
1589
1.74k
    else if (zType!=FreeHandParserInternal::Z_StyleGroup) {
1590
678
      checkDSize=true;
1591
678
      MWAW_DEBUG_MSG(("FreeHandParser::readStyleGroup: find unexpected zone type for zone %d\n", zId));
1592
678
    }
1593
14.5k
  }
1594
92.4k
  auto dSz=static_cast<int>(input->readULong(4)); // probably related to size
1595
92.4k
  f << "sz?=" << dSz << ",";
1596
92.4k
  auto opCode=static_cast<int>(input->readULong(2));
1597
92.4k
  if ((vers==1 && opCode!=2) || (vers>1 && opCode!=5))
1598
0
    return false;
1599
92.4k
  if (vers==1) {
1600
158k
    for (int i=0; i<2; ++i) { // always f0=0,f1=16 ?
1601
105k
      auto val=static_cast<int>(input->readLong(2));
1602
105k
      if (val)
1603
58.2k
        f << "f" << i << "=" << val << ",";
1604
105k
    }
1605
52.7k
  }
1606
92.4k
  auto N=static_cast<int>(input->readULong(2));
1607
92.4k
  if (!input->checkPosition(input->tell()+4+2*N) ||
1608
82.0k
      (vers==1 && checkDSize && N!=(dSz-16)/2) ||
1609
59.4k
      (vers>1 && checkDSize && N!=(dSz-12)/2))
1610
51.9k
    return false;
1611
121k
  for (int i=0; i<2; ++i) { // always 0?
1612
80.9k
    auto val=static_cast<int>(input->readLong(2));
1613
80.9k
    if (val)
1614
29.1k
      f << "f" << i+2 << "=" << val << ",";
1615
80.9k
  }
1616
40.4k
  f << "childs=[";
1617
157k
  for (int i=0; i<N; ++i) {
1618
130k
    auto id=static_cast<int>(input->readULong(2));
1619
130k
    if (!m_state->addZoneId(id, cType)) {
1620
17.8k
      if (checkDSize) return false;
1621
5.00k
      MWAW_DEBUG_MSG(("FreeHandParser::readStyleGroup: find unexpected child zone %d\n", id));
1622
5.00k
      f << "###";
1623
5.00k
    }
1624
117k
    f << "Z" << id << ",";
1625
117k
  }
1626
27.6k
  f << "],";
1627
27.6k
  ascii().addPos(pos);
1628
27.6k
  ascii().addNote(f.str().c_str());
1629
1630
27.6k
  return true;
1631
40.4k
}
1632
1633
bool FreeHandParser::readStringZone(int zId)
1634
82.8k
{
1635
82.8k
  MWAWInputStreamPtr input = getInput();
1636
82.8k
  libmwaw::DebugStream f;
1637
1638
82.8k
  long pos=input->tell();
1639
82.8k
  auto dSz=long(input->readULong(4));
1640
82.8k
  auto opCode=static_cast<int>(input->readLong(2));
1641
82.8k
  int const vers=version();
1642
  // v1: opcode=3, v2: opcode=6
1643
82.8k
  if (vers==2) {
1644
16.3k
    dSz-=4;
1645
16.3k
    opCode-=3;
1646
16.3k
  }
1647
82.8k
  if (opCode!=3 || dSz<3 || !input->checkPosition(pos+dSz+2)) {
1648
10.2k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1649
10.2k
    return false;
1650
10.2k
  }
1651
72.6k
  f.str("");
1652
72.6k
  if (zId)
1653
2.31k
    f << "Entries(String)[Z" << zId << "]:";
1654
70.2k
  else
1655
70.2k
    f << "Entries(String):";
1656
72.6k
  if (zId && m_state->getZoneType(zId)!=FreeHandParserInternal::Z_String) {
1657
815
    MWAW_DEBUG_MSG(("FreeHandParser::readStringZone: find unexpected zone type for zone %d\n", zId));
1658
815
  }
1659
72.6k
  auto sSz=int(input->readULong(1));
1660
72.6k
  if (sSz+5>dSz || (!zId && sSz+6<dSz)) {
1661
51.1k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1662
51.1k
    return false;
1663
51.1k
  }
1664
21.4k
  std::string name;
1665
246k
  for (int i=0; i<sSz; ++i) name += char(input->readULong(1));
1666
21.4k
  f << name << ",";
1667
21.4k
  if (zId && m_state->m_zIdToStringMap.find(zId)==m_state->m_zIdToStringMap.end())
1668
2.24k
    m_state->m_zIdToStringMap[zId]=name;
1669
21.4k
  ascii().addPos(pos);
1670
21.4k
  ascii().addNote(f.str().c_str());
1671
21.4k
  input->seek(pos+dSz+2, librevenge::RVNG_SEEK_SET);
1672
21.4k
  return true;
1673
72.6k
}
1674
1675
bool FreeHandParser::readShapeHeader(FreeHandParserInternal::ShapeHeader &shape)
1676
532k
{
1677
532k
  MWAWInputStreamPtr input = getInput();
1678
532k
  libmwaw::DebugStream f;
1679
532k
  long pos=input->tell();
1680
532k
  int const vers=version();
1681
532k
  if (!input->checkPosition(pos+(vers==1 ? 20 : 18))) return false;
1682
528k
  shape.m_size=long(input->readULong(4));
1683
528k
  shape.m_type=static_cast<int>(input->readULong(2));
1684
528k
  if (vers>1) {
1685
257k
    shape.m_dataId=static_cast<int>(input->readULong(2));
1686
257k
    if (shape.m_dataId && !m_state->addZoneId(shape.m_dataId, FreeHandParserInternal::Z_Note)) {
1687
8.83k
      MWAW_DEBUG_MSG(("FreeHandParser::readShapeHeader: find unexpected data id\n"));
1688
8.83k
      f << "###dataId";
1689
8.83k
    }
1690
257k
    shape.m_values[0]=static_cast<int>(input->readLong(2)); // always 0
1691
257k
    shape.m_layerId=static_cast<int>(input->readULong(2));
1692
257k
    shape.m_values[1]=static_cast<int>(input->readLong(2)); // always 0
1693
    // now to multiple of 256 ???
1694
257k
    f << "unkn=[" << float(input->readLong(2))/256.f << "," << float(input->readLong(2))/256.f << "],";
1695
257k
    shape.m_extra=f.str();
1696
257k
    return true;
1697
257k
  }
1698
  // always 0, if not we may have a problem...
1699
271k
  shape.m_values[0]=static_cast<int>(input->readLong(2));
1700
271k
  auto dataSz=static_cast<int>(input->readULong(2));
1701
271k
  if (!input->checkPosition(pos+14+dataSz)) {
1702
23.0k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1703
23.0k
    return false;
1704
23.0k
  }
1705
248k
  if (dataSz) {
1706
139k
    auto sSz=static_cast<int>(input->readULong(1));
1707
139k
    if (sSz==dataSz-1) {
1708
1.37M
      for (int i=0; i<sSz; ++i)
1709
1.35M
        shape.m_note+=char(input->readULong(1));
1710
18.1k
    }
1711
121k
    else {
1712
121k
      MWAW_DEBUG_MSG(("FreeHandParser::readShapeHeader: find unexpected special size\n"));
1713
121k
      f << "##specialSize=" << dataSz << ",";
1714
121k
      input->seek(dataSz-1, librevenge::RVNG_SEEK_CUR);
1715
121k
    }
1716
139k
  }
1717
248k
  shape.m_layerId=static_cast<int>(input->readULong(2));
1718
  /* val1,val2: always 0, if not we may have a problem...
1719
     val3: sometimes a 1005 zone
1720
   */
1721
992k
  for (int i=0; i<3; ++i)
1722
744k
    shape.m_values[i+1]=static_cast<int>(input->readLong(2));
1723
248k
  if (shape.m_values[3]) {
1724
158k
    if (!m_state->addZoneId(shape.m_values[3], FreeHandParserInternal::Z_Shape)) {
1725
14.9k
      MWAW_DEBUG_MSG(("FreeHandParser::readShapeHeader: find unexpected shape id\n"));
1726
14.9k
      f << "###shapeId";
1727
14.9k
    }
1728
158k
  }
1729
  // the special zone
1730
248k
  dataSz=static_cast<int>(input->readULong(2));
1731
248k
  if (!input->checkPosition(input->tell()+dataSz)) {
1732
55.3k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1733
55.3k
    return false;
1734
55.3k
  }
1735
192k
  if (dataSz==8) {
1736
2.85k
    long actPos=input->tell();
1737
2.85k
    if (!readScreenMode(*shape.m_screen)) {
1738
0
      MWAW_DEBUG_MSG(("FreeHandParser::readShapeHeader: can not read screen mode\n"));
1739
0
      f << "##screenMode,";
1740
0
      input->seek(actPos+8, librevenge::RVNG_SEEK_SET);
1741
0
    }
1742
2.85k
  }
1743
189k
  else if (dataSz) {
1744
76.9k
    MWAW_DEBUG_MSG(("FreeHandParser::readShapeHeader: find unexpected special size\n"));
1745
76.9k
    f << "##specialSize=" << dataSz << ",";
1746
76.9k
    input->seek(dataSz, librevenge::RVNG_SEEK_CUR);
1747
76.9k
  }
1748
192k
  shape.m_extra=f.str();
1749
192k
  return true;
1750
248k
}
1751
1752
bool FreeHandParser::readScreenMode(FreeHandParserInternal::ScreenMode &screen)
1753
65.4k
{
1754
65.4k
  MWAWInputStreamPtr input = getInput();
1755
65.4k
  long pos=input->tell();
1756
65.4k
  if (!input->checkPosition(pos+8)) return false;
1757
65.4k
  screen.m_function=static_cast<int>(input->readLong(2));
1758
65.4k
  screen.m_angle=float(input->readLong(2))/10.f;
1759
65.4k
  screen.m_lineByInch=static_cast<int>(input->readULong(2));
1760
65.4k
  screen.m_value=static_cast<int>(input->readLong(2)); // always 0?
1761
65.4k
  return true;
1762
65.4k
}
1763
1764
bool FreeHandParser::readStyleHeader(FreeHandParserInternal::StyleHeader &style)
1765
411k
{
1766
411k
  MWAWInputStreamPtr input = getInput();
1767
411k
  libmwaw::DebugStream f;
1768
411k
  long pos=input->tell();
1769
411k
  if (!input->checkPosition(pos+12)) return false;
1770
411k
  style.m_size=long(input->readULong(4));
1771
411k
  style.m_type=static_cast<int>(input->readULong(2));
1772
411k
  if (version()==1) {
1773
    // always 0, if not we may have a problem...
1774
349k
    style.m_unknownValue=static_cast<int>(input->readLong(2));
1775
349k
    auto dataSz=static_cast<int>(input->readULong(2));
1776
349k
    if (!input->checkPosition(pos+12+dataSz)) {
1777
21.9k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
1778
21.9k
      return false;
1779
21.9k
    }
1780
327k
    if (dataSz==8) {
1781
62.5k
      long actPos=input->tell();
1782
62.5k
      if (!readScreenMode(*style.m_screen)) {
1783
0
        MWAW_DEBUG_MSG(("FreeHandParser::readStyleHeader: can not read screen mode\n"));
1784
0
        f << "##screenMode,";
1785
0
        input->seek(actPos+8, librevenge::RVNG_SEEK_SET);
1786
0
      }
1787
62.5k
    }
1788
264k
    else if (dataSz) {
1789
36.9k
      MWAW_DEBUG_MSG(("FreeHandParser::readStyleHeader: find unexpected special size\n"));
1790
36.9k
      f << "##specialSize=" << dataSz << ",";
1791
36.9k
      input->seek(dataSz, librevenge::RVNG_SEEK_CUR);
1792
36.9k
    }
1793
327k
  }
1794
389k
  auto id=static_cast<int>(input->readULong(2));
1795
389k
  if (id && !m_state->addZoneId(id, FreeHandParserInternal::Z_String)) {
1796
24.5k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1797
24.5k
    return false;
1798
24.5k
  }
1799
364k
  else
1800
364k
    style.m_labelId=id;
1801
364k
  return true;
1802
389k
}
1803
1804
bool FreeHandParser::readColor(int zId)
1805
76.6k
{
1806
76.6k
  MWAWInputStreamPtr input = getInput();
1807
76.6k
  libmwaw::DebugStream f;
1808
1809
76.6k
  long pos=input->tell();
1810
76.6k
  f.str("");
1811
76.6k
  if (zId)
1812
5.49k
    f << "Entries(Color)[Z" << zId << "]:";
1813
71.1k
  else
1814
71.1k
    f << "Entries(Color):";
1815
76.6k
  if (zId && m_state->getZoneType(zId)!=FreeHandParserInternal::Z_Color) {
1816
1.51k
    MWAW_DEBUG_MSG(("FreeHandParser::readColor: find unexpected zone type for zone %d\n", zId));
1817
1.51k
  }
1818
76.6k
  FreeHandParserInternal::StyleHeader zone;
1819
76.6k
  if (!readStyleHeader(zone)) {
1820
4.25k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1821
4.25k
    return false;
1822
4.25k
  }
1823
72.4k
  int expectedSize=0;
1824
72.4k
  int const vers=version();
1825
72.4k
  switch (zone.m_type) {
1826
7.13k
  case 0x106a:
1827
11.9k
  case 0x1452:
1828
11.9k
    f << "color,";
1829
11.9k
    expectedSize=12;
1830
11.9k
    if ((vers==1 && zone.m_size!=0x1c) || (vers>1 && zone.m_size!=0x1e))
1831
5.94k
      f << "#sz?=" << zone.m_size << ",";
1832
11.9k
    break;
1833
39.5k
  case 0x106b:
1834
39.5k
    f << "tint,";
1835
39.5k
    expectedSize=4;
1836
39.5k
    if (zone.m_size!=0x16)
1837
39.0k
      f << "#sz?=" << zone.m_size << ",";
1838
39.5k
    break;
1839
2.41k
  case 0x1453:
1840
2.41k
    f << "tint,";
1841
2.41k
    expectedSize=10;
1842
2.41k
    if (zone.m_size!=0x1e)
1843
32
      f << "#sz?=" << zone.m_size << ",";
1844
2.41k
    break;
1845
5.40k
  case 0x106c:
1846
5.40k
    f << "cmyk,";
1847
5.40k
    expectedSize=8;
1848
5.40k
    if (zone.m_size!=0x18)
1849
5.36k
      f << "#sz?=" << zone.m_size << ",";
1850
5.40k
    break;
1851
9.75k
  case 0x1454:
1852
9.75k
    f << "cmyk,";
1853
9.75k
    expectedSize=14;
1854
9.75k
    if (zone.m_size!=0x20)
1855
9.75k
      f << "#sz?=" << zone.m_size << ",";
1856
9.75k
    break;
1857
3.36k
  case 0x1455:
1858
3.36k
    f << "pantome?,";
1859
3.36k
    expectedSize=22;
1860
3.36k
    if (zone.m_size!=0x28)
1861
3.36k
      f << "#sz?=" << zone.m_size << ",";
1862
3.36k
    break;
1863
0
  default:
1864
0
    break;
1865
72.4k
  }
1866
72.4k
  long endPos=input->tell()+expectedSize;
1867
72.4k
  if (expectedSize==0 || !input->checkPosition(endPos)) {
1868
248
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1869
248
    return false;
1870
248
  }
1871
72.1k
  f << zone;
1872
72.1k
  MWAWColor color;
1873
72.1k
  if (zone.m_type==0x106a || zone.m_type==0x1452) {
1874
11.9k
    unsigned char col[3];
1875
35.7k
    for (auto &c : col) c=static_cast<unsigned char>(input->readULong(2)>>8);
1876
11.9k
    color=MWAWColor(col[0],col[1],col[2]);
1877
11.9k
    f << color << ",";
1878
11.9k
    auto val=static_cast<int>(input->readLong(2));
1879
11.9k
    if (val) f << "id=" << val << ",";
1880
11.9k
    val=static_cast<int>(input->readLong(2)); // flag or big number
1881
11.9k
    if (val) f << "f0=" << val << ",";
1882
11.9k
    val=static_cast<int>(input->readLong(2)); // always 1
1883
11.9k
    if (val!=1) f << "f1=" << val << ",";
1884
11.9k
  }
1885
60.2k
  else if (zone.m_type==0x106b || zone.m_type==0x1453) {
1886
41.8k
    if (zone.m_type==0x1453) {
1887
2.41k
      unsigned char col[3];
1888
7.24k
      for (auto &c : col) c=static_cast<unsigned char>(input->readULong(2)>>8);
1889
2.41k
      color=MWAWColor(col[0],col[1],col[2]);
1890
2.41k
      f << color << ",";
1891
2.41k
    }
1892
41.8k
    auto cId=static_cast<int>(input->readULong(2));
1893
41.8k
    if (cId && !m_state->addZoneId(cId, FreeHandParserInternal::Z_Color)) {
1894
4.98k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
1895
4.98k
      return false;
1896
4.98k
    }
1897
36.8k
    f << "main[color]=Z" << cId << ",";
1898
36.8k
    MWAWColor mainColor(MWAWColor::white());
1899
36.8k
    if (cId && m_state->m_zIdToColorMap.find(cId)!=m_state->m_zIdToColorMap.end())
1900
6.25k
      mainColor=m_state->m_zIdToColorMap.find(cId)->second;
1901
30.5k
    else if (cId) {
1902
16.8k
      static bool first=true;
1903
16.8k
      if (first) {
1904
13
        MWAW_DEBUG_MSG(("FreeHandParser::readColor: can not find some main color\n"));
1905
13
        first=false;
1906
13
      }
1907
16.8k
    }
1908
36.8k
    float tint=float(input->readULong(2))/65535.f;
1909
36.8k
    if (zone.m_type==0x106b)
1910
34.4k
      color=MWAWColor::barycenter(tint, mainColor, 1-tint, MWAWColor::white());
1911
36.8k
    f << "percent=" << tint << ",";
1912
36.8k
  }
1913
18.4k
  else if (zone.m_type==0x1455) {
1914
3.34k
    unsigned char col[3];
1915
10.0k
    for (auto &c : col) c=static_cast<unsigned char>(input->readULong(2)>>8);
1916
3.34k
    color=MWAWColor(col[0],col[1],col[2]);
1917
3.34k
    f << color << ",";
1918
    // what is that ?
1919
30.1k
    for (int i=0; i<8; ++i) { // f0=0|1a5|1f7,f2=0|451e,f4=0|f5c|1c28,f5=147a|2e14|828f,f6=1c2, f7=1
1920
26.7k
      auto val=static_cast<int>(input->readULong(2));
1921
26.7k
      if (val) f << "f" << i << "=" << std::hex << val << std::dec << ",";
1922
26.7k
    }
1923
3.34k
  }
1924
15.0k
  else {
1925
15.0k
    if (zone.m_type==0x1454) {
1926
9.69k
      unsigned char col[3];
1927
29.0k
      for (auto &c : col) c=static_cast<unsigned char>(input->readULong(2)>>8);
1928
9.69k
      color=MWAWColor(col[0],col[1],col[2]);
1929
9.69k
      f << color << ",";
1930
9.69k
    }
1931
15.0k
    unsigned char col[4];
1932
60.3k
    for (auto &c : col) c=static_cast<unsigned char>(input->readULong(2)>>8);
1933
15.0k
    if (zone.m_type==0x106c) {
1934
5.38k
      color=MWAWColor::colorFromCMYK(col[1],col[2],col[3],col[0]);
1935
5.38k
      f << color << ",";
1936
5.38k
    }
1937
15.0k
  }
1938
67.2k
  if (zId && m_state->m_zIdToColorMap.find(zId)==m_state->m_zIdToColorMap.end())
1939
5.38k
    m_state->m_zIdToColorMap[zId]=color;
1940
67.2k
  ascii().addPos(pos);
1941
67.2k
  ascii().addNote(f.str().c_str());
1942
67.2k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
1943
67.2k
  return true;
1944
72.1k
}
1945
1946
bool FreeHandParser::readDash(int zId)
1947
54.7k
{
1948
54.7k
  MWAWInputStreamPtr input = getInput();
1949
54.7k
  libmwaw::DebugStream f;
1950
1951
54.7k
  long pos=input->tell();
1952
54.7k
  f.str("");
1953
54.7k
  if (zId)
1954
4.96k
    f << "Entries(Dash)[Z" << zId << "]:";
1955
49.7k
  else
1956
49.7k
    f << "Entries(Dash):";
1957
54.7k
  if (zId && m_state->getZoneType(zId)!=FreeHandParserInternal::Z_Dash) {
1958
901
    MWAW_DEBUG_MSG(("FreeHandParser::readDash: find unexpected zone type for zone %d\n", zId));
1959
901
  }
1960
54.7k
  FreeHandParserInternal::StyleHeader zone;
1961
54.7k
  if (!readStyleHeader(zone)) {
1962
8.68k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1963
8.68k
    return false;
1964
8.68k
  }
1965
46.0k
  int const vers=version();
1966
46.0k
  if (zone.m_size < 12 || (vers==1 && zone.m_type!=0x1195) || (vers>1 && zone.m_type!=0x157d)) {
1967
16.3k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1968
16.3k
    return false;
1969
16.3k
  }
1970
29.6k
  long endPos;
1971
29.6k
  if (vers==1)
1972
19.3k
    endPos=pos+2+zone.m_size;
1973
10.3k
  else {
1974
10.3k
    endPos=pos-2+zone.m_size;
1975
31.0k
    for (int i=0; i<2; ++i) { // 0
1976
20.7k
      auto val=static_cast<int>(input->readULong(2));
1977
20.7k
      if (val)
1978
815
        f << "f" << i << "=" << val << ",";
1979
20.7k
    }
1980
10.3k
  }
1981
29.6k
  f << zone;
1982
29.6k
  auto N=static_cast<int>(input->readLong(2));
1983
29.6k
  if (endPos!=input->tell()+2*N || !input->checkPosition(endPos)) {
1984
14.6k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
1985
14.6k
    return false;
1986
14.6k
  }
1987
14.9k
  f << "dash=[";
1988
14.9k
  std::vector<float> dashes;
1989
52.1k
  for (int j=0; j<N; ++j) {
1990
37.1k
    dashes.push_back(float(input->readLong(2))/10.f);
1991
37.1k
    f << dashes.back() << ",";
1992
37.1k
  }
1993
14.9k
  f << "],";
1994
14.9k
  if (zId && m_state->m_zIdToDashMap.find(zId)==m_state->m_zIdToDashMap.end())
1995
4.79k
    m_state->m_zIdToDashMap[zId]=dashes;
1996
14.9k
  ascii().addPos(pos);
1997
14.9k
  ascii().addNote(f.str().c_str());
1998
14.9k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
1999
2000
14.9k
  return true;
2001
29.6k
}
2002
2003
bool FreeHandParser::readFillStyle(int zId)
2004
85.6k
{
2005
85.6k
  MWAWInputStreamPtr input = getInput();
2006
85.6k
  libmwaw::DebugStream f;
2007
2008
85.6k
  long pos=input->tell();
2009
85.6k
  if (!input->checkPosition(pos+13))
2010
365
    return false;
2011
85.2k
  f.str("");
2012
85.2k
  if (zId)
2013
9.20k
    f << "Entries(FillStyle)[Z" << zId << "]:";
2014
76.0k
  else
2015
76.0k
    f << "Entries(FillStyle):";
2016
85.2k
  if (zId && m_state->getZoneType(zId)!=FreeHandParserInternal::Z_Fill) {
2017
1.39k
    MWAW_DEBUG_MSG(("FreeHandParser::readFillStyle: find unexpected zone type for zone %d\n", zId));
2018
1.39k
  }
2019
85.2k
  FreeHandParserInternal::StyleHeader zone;
2020
85.2k
  if (!readStyleHeader(zone)) {
2021
14.9k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2022
14.9k
    return false;
2023
14.9k
  }
2024
70.2k
  FreeHandParserInternal::FillStyle style;
2025
70.2k
  int expectedSize=0;
2026
70.2k
  int const vers=version();
2027
70.2k
  switch (zone.m_type) {
2028
14.3k
  case 0x10cd:
2029
14.3k
    f << "basic,";
2030
14.3k
    if (zone.m_size!=0x12) f << "sz?=" << zone.m_size << ",";
2031
14.3k
    expectedSize=3;
2032
14.3k
    break;
2033
14.7k
  case 0x10d0:
2034
14.7k
    f << "gradient,";
2035
14.7k
    style.m_type=MWAWGraphicStyle::Gradient::G_Linear;
2036
14.7k
    if (zone.m_size!=0x18) f << "sz?=" << zone.m_size << ",";
2037
14.7k
    expectedSize=8;
2038
14.7k
    break;
2039
21.2k
  case 0x10d1:
2040
21.2k
    f << "radial,";
2041
21.2k
    style.m_type=MWAWGraphicStyle::Gradient::G_Radial;
2042
21.2k
    if (zone.m_size!=0x14) f << "sz?=" << zone.m_size << ",";
2043
21.2k
    expectedSize=4;
2044
21.2k
    break;
2045
4.88k
  case 0x14b5:
2046
4.88k
    f << "basic,";
2047
4.88k
    if (zone.m_size!=0x16) f << "sz?=" << zone.m_size << ",";
2048
4.88k
    expectedSize=8;
2049
4.88k
    break;
2050
6.01k
  case 0x14b7:
2051
6.01k
    f << "gradient,";
2052
6.01k
    style.m_type=MWAWGraphicStyle::Gradient::G_Linear;
2053
6.01k
    if (zone.m_size!=0x1c) f << "sz?=" << zone.m_size << ",";
2054
6.01k
    expectedSize=12;
2055
6.01k
    break;
2056
2.25k
  case 0x14b8:
2057
2.25k
    f << "radial,";
2058
2.25k
    style.m_type=MWAWGraphicStyle::Gradient::G_Radial;
2059
2.25k
    if (zone.m_size!=0x1e) f << "sz?=" << zone.m_size << ",";
2060
2.25k
    expectedSize=14;
2061
2.25k
    break;
2062
4.23k
  case 0x14d3:
2063
4.23k
    f << "pattern,";
2064
4.23k
    if (zone.m_size!=0x1c) f << "sz?=" << zone.m_size << ",";
2065
4.23k
    expectedSize=14;
2066
4.23k
    break;
2067
2.55k
  case 0x14dd:
2068
2.55k
    f << "tiled,";
2069
2.55k
    if (zone.m_size!=0x44) f << "sz?=" << zone.m_size << ",";
2070
2.55k
    expectedSize=54;
2071
2.55k
    break;
2072
0
  default:
2073
0
    break;
2074
70.2k
  }
2075
70.2k
  long endPos=input->tell()+expectedSize;
2076
70.2k
  if (expectedSize==0 || !input->checkPosition(endPos)) {
2077
345
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2078
345
    return false;
2079
345
  }
2080
69.9k
  f << zone;
2081
69.9k
  if (vers>1) {
2082
59.3k
    for (int i=0; i<2; ++i) { // always 0
2083
39.5k
      auto val=static_cast<int>(input->readLong(2));
2084
39.5k
      if (val) f << "f" << i << "=" << val << ",";
2085
39.5k
    }
2086
19.7k
  }
2087
69.9k
  auto id=static_cast<int>(input->readULong(2));
2088
69.9k
  if (zone.m_type==0x14dd) {
2089
2.40k
    if (id && !m_state->addZoneId(id, FreeHandParserInternal::Z_Group)) {
2090
100
      input->seek(pos, librevenge::RVNG_SEEK_SET);
2091
100
      return false;
2092
100
    }
2093
2.30k
    else if (id) {
2094
1.27k
      static bool first=true;
2095
1.27k
      if (first) {
2096
13
        MWAW_DEBUG_MSG(("FreeHandParser::readFillStyle: retrieving tiled style is not implemented\n"));
2097
13
        first=false;
2098
13
      }
2099
1.27k
      f << "group=Z" << id << ",";
2100
1.27k
    }
2101
11.5k
    for (int i=0; i<4; ++i) { // always 0
2102
9.22k
      auto val=static_cast<int>(input->readLong(2));
2103
9.22k
      if (val) f << "f" << i+2 << "=" << val << ",";
2104
9.22k
    }
2105
2.30k
    f << "scale=" << float(input->readLong(4))/65536.f << "x" << float(input->readLong(4))/65536.f << ",";
2106
2.30k
    f << "decal=" << float(input->readLong(2))/10.f << "x" << float(input->readLong(2))/10.f << ",";
2107
2.30k
    f << "angle=" << float(input->readLong(2))/10.f << ",";
2108
2.30k
    f << "fl=" << std::hex << input->readULong(2) << std::dec << ","; // 39|49
2109
2.30k
    f << "rot=[";
2110
11.5k
    for (int i=0; i<4; ++i)
2111
9.22k
      f << float(input->readLong(4))/65536.f << ",";
2112
2.30k
    f << "],";
2113
2.30k
    f << "trans=[";
2114
6.91k
    for (int i=0; i<2; ++i)
2115
4.61k
      f << float(input->readLong(4))/65536.f/10.f << ",";
2116
2.30k
    f << "],";
2117
2.30k
  }
2118
67.5k
  else if (id && !m_state->addZoneId(id, FreeHandParserInternal::Z_Color)) {
2119
6.69k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2120
6.69k
    return false;
2121
6.69k
  }
2122
60.8k
  else if (id) {
2123
46.3k
    style.m_colorId[0]=id;
2124
46.3k
    f << "color=Z" << id << ",";
2125
46.3k
  }
2126
63.1k
  if (zone.m_type==0x10d0 || zone.m_type==0x10d1 || zone.m_type==0x14b7 || zone.m_type==0x14b8) {
2127
39.4k
    id=static_cast<int>(input->readULong(2));
2128
39.4k
    if (id && !m_state->addZoneId(id, FreeHandParserInternal::Z_Color)) {
2129
6.89k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
2130
6.89k
      return false;
2131
6.89k
    }
2132
32.5k
    else if (id) {
2133
20.4k
      style.m_colorId[1]=id;
2134
20.4k
      f << "color2=Z" << id << ",";
2135
20.4k
    }
2136
39.4k
  }
2137
56.2k
  if (zone.m_type==0x10d0 || zone.m_type==0x14b7) {
2138
17.3k
    style.m_angle = float(input->readULong(2))/10.f;
2139
17.3k
    f << "angle=" << style.m_angle << ",";
2140
17.3k
    auto val=static_cast<int>(input->readULong(vers==1 ? 1 : 2));
2141
17.3k
    switch (val) {
2142
3.85k
    case 1:
2143
3.85k
      f << "linear,";
2144
3.85k
      break;
2145
6.84k
    case 2:
2146
6.84k
      style.m_logarithm=true;
2147
6.84k
      f << "logarithm,";
2148
6.84k
      break;
2149
6.66k
    default:
2150
6.66k
      MWAW_DEBUG_MSG(("FreeHandParser::readFillStyle: find unexpected gradient type\n"));
2151
6.66k
      f << "#gradient[type]=" << val << ",";
2152
17.3k
    }
2153
17.3k
  }
2154
38.8k
  else if (zone.m_type==0x14b8) {
2155
8.52k
    for (int i=0; i<3; ++i) { // always 0
2156
6.39k
      auto val=static_cast<int>(input->readLong(2));
2157
6.39k
      if (val) f << "g" << i << "=" << val << ",";
2158
6.39k
    }
2159
2.13k
  }
2160
36.7k
  else if (zone.m_type==0x14d3) {
2161
4.10k
    MWAWGraphicStyle::Pattern pattern;
2162
4.10k
    pattern.m_colors[0]=MWAWColor::white();
2163
4.10k
    pattern.m_colors[1]=MWAWColor::black();
2164
4.10k
    pattern.m_dim=MWAWVec2i(8,8);
2165
4.10k
    pattern.m_data.resize(8);
2166
4.10k
    for (auto &data : pattern.m_data)
2167
32.8k
      data=static_cast<uint8_t>(input->readULong(1));
2168
4.10k
    style.m_pattern=pattern;
2169
4.10k
    f << pattern;
2170
4.10k
  }
2171
56.2k
  if ((vers==1 && zone.m_type!=0x10d1) || (vers>1 && zone.m_type==0x14b5)) {
2172
28.7k
    auto val=static_cast<int>(input->readULong(vers==1 ? 1 : 2)); // always 0
2173
28.7k
    if (val==1)
2174
1.37k
      f << "overprint,";
2175
27.4k
    else
2176
27.4k
      f << "g0=" << val << ",";
2177
28.7k
  }
2178
56.2k
  if (zId && m_state->m_zIdToFillStyleMap.find(zId)==m_state->m_zIdToFillStyleMap.end())
2179
9.10k
    m_state->m_zIdToFillStyleMap[zId]=style;
2180
56.2k
  ascii().addPos(pos);
2181
56.2k
  ascii().addNote(f.str().c_str());
2182
56.2k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
2183
2184
56.2k
  return true;
2185
56.2k
}
2186
2187
bool FreeHandParser::readLineStyle(int zId)
2188
120k
{
2189
120k
  MWAWInputStreamPtr input = getInput();
2190
120k
  libmwaw::DebugStream f;
2191
2192
120k
  long pos=input->tell();
2193
120k
  if (!input->checkPosition(pos+13))
2194
284
    return false;
2195
120k
  f.str("");
2196
120k
  if (zId)
2197
3.43k
    f << "Entries(LinStyle)[Z" << zId << "]:";
2198
116k
  else
2199
116k
    f << "Entries(LinStyle):";
2200
120k
  if (zId && m_state->getZoneType(zId)!=FreeHandParserInternal::Z_LineStyle) {
2201
1.16k
    MWAW_DEBUG_MSG(("FreeHandParser::readLineStyle: find unexpected zone type for zone %d\n", zId));
2202
1.16k
  }
2203
120k
  FreeHandParserInternal::StyleHeader zone;
2204
120k
  int const vers=version();
2205
120k
  if (!readStyleHeader(zone)) {
2206
13.9k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2207
13.9k
    return false;
2208
13.9k
  }
2209
106k
  f << zone;
2210
106k
  long endPos=0;
2211
106k
  bool ok=false;
2212
106k
  switch (zone.m_type) {
2213
100k
  case 0x10ce:
2214
100k
    ok=(vers==1);
2215
100k
    endPos=input->tell()+12;
2216
100k
    if (zone.m_size!=0x1c) f << "sz?=" << zone.m_size << ",";
2217
100k
    break;
2218
4.44k
  case 0x14b6:
2219
4.44k
    ok=(vers>1);
2220
4.44k
    endPos=input->tell()+18;
2221
4.44k
    if (zone.m_size!=0x22) f << "sz?=" << zone.m_size << ",";
2222
4.44k
    break;
2223
1.29k
  case 0x14d4:
2224
1.29k
    f << "pattern,";
2225
1.29k
    ok=(vers>1);
2226
1.29k
    endPos=input->tell()+22;
2227
1.29k
    if (zone.m_size!=0x24) f << "sz?=" << zone.m_size << ",";
2228
1.29k
    break;
2229
0
  default:
2230
0
    ok=false;
2231
0
    break;
2232
106k
  }
2233
106k
  if (!ok || !input->checkPosition(endPos)) {
2234
435
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2235
435
    return false;
2236
435
  }
2237
105k
  if (vers>1) {
2238
17.1k
    for (int i=0; i<2; ++i) { // 0
2239
11.4k
      auto val=static_cast<int>(input->readLong(2));
2240
11.4k
      if (val)
2241
845
        f << "f" << i << "=" << val << ",";
2242
11.4k
    }
2243
5.71k
  }
2244
105k
  FreeHandParserInternal::LineStyle style;
2245
105k
  auto id=static_cast<int>(input->readULong(2));
2246
105k
  if (id && !m_state->addZoneId(id, FreeHandParserInternal::Z_Color)) {
2247
12.4k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2248
12.4k
    return false;
2249
12.4k
  }
2250
93.4k
  else if (id) {
2251
77.1k
    style.m_colorId=id;
2252
77.1k
    f << "color=Z" << id << ",";
2253
77.1k
  }
2254
93.4k
  if (zone.m_type==0x14d4) {
2255
1.07k
    MWAWGraphicStyle::Pattern pattern;
2256
1.07k
    pattern.m_colors[0]=MWAWColor::white();
2257
1.07k
    pattern.m_colors[1]=MWAWColor::black();
2258
1.07k
    pattern.m_dim=MWAWVec2i(8,8);
2259
1.07k
    pattern.m_data.resize(8);
2260
1.07k
    for (auto &data : pattern.m_data)
2261
8.60k
      data=static_cast<uint8_t>(input->readULong(1));
2262
1.07k
    style.m_pattern=pattern;
2263
1.07k
    f << pattern;
2264
1.07k
  }
2265
92.4k
  else {
2266
92.4k
    id=static_cast<int>(input->readULong(2));
2267
92.4k
    if (id && !m_state->addZoneId(id, FreeHandParserInternal::Z_Dash)) {
2268
7.32k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
2269
7.32k
      return false;
2270
7.32k
    }
2271
85.0k
    else if (id) {
2272
65.6k
      style.m_dashId=id;
2273
65.6k
      f << "dash=Z" << id << ",";
2274
65.6k
    }
2275
92.4k
  }
2276
  // probably cosecant(miter/2)
2277
86.1k
  float value=float(input->readLong(4))/65536.f;
2278
86.1k
  if (value<=-1||value>=1) {
2279
66.0k
    style.m_miterLimit=float(360./M_PI)*float(std::asin(1/value));
2280
66.0k
    f << "miter[limit]=" << style.m_miterLimit << ",";
2281
66.0k
  }
2282
20.0k
  else if (value<0||value>0) {
2283
11.3k
    f << "##miter[limit]=2*asin(" << 1/value << "),";
2284
11.3k
  }
2285
8.74k
  else
2286
8.74k
    f << "miter[limit]*,";
2287
86.1k
  style.m_width=vers==1 ? float(input->readLong(2))/10.0f  : float(input->readLong(4))/65536.f/10.0f;
2288
86.1k
  f << "width=" << style.m_width << ",";
2289
86.1k
  if (zone.m_type!=0x14d4) {
2290
85.0k
    auto val=static_cast<int>(input->readULong(1));
2291
85.0k
    switch (val) {
2292
18.3k
    case 0: // default
2293
18.3k
      break;
2294
5.37k
    case 1:
2295
5.37k
      style.m_join=MWAWGraphicStyle::J_Bevel;
2296
5.37k
      f << "join=bevel,";
2297
5.37k
      break;
2298
16.6k
    case 2:
2299
16.6k
      style.m_join=MWAWGraphicStyle::J_Round;
2300
16.6k
      f << "join=round,";
2301
16.6k
      break;
2302
44.7k
    default:
2303
44.7k
      MWAW_DEBUG_MSG(("FreeHandParser::readLineStyle: find unknown join\n"));
2304
44.7k
      f << "#join=" << val << ",";
2305
85.0k
    }
2306
85.0k
    val=static_cast<int>(input->readULong(1));
2307
85.0k
    switch (val) {
2308
20.7k
    case 0: // default
2309
20.7k
      break;
2310
16.0k
    case 1:
2311
16.0k
      style.m_cap=MWAWGraphicStyle::C_Round;
2312
16.0k
      f << "cap=round,";
2313
16.0k
      break;
2314
6.27k
    case 2:
2315
6.27k
      style.m_cap=MWAWGraphicStyle::C_Square;
2316
6.27k
      f << "cap=square,";
2317
6.27k
      break;
2318
42.0k
    default:
2319
42.0k
      MWAW_DEBUG_MSG(("FreeHandParser::readLineStyle: find unknown cap\n"));
2320
42.0k
      f << "#cap=" << val << ",";
2321
85.0k
    }
2322
85.0k
  }
2323
86.1k
  if (zId && m_state->m_zIdToLineStyleMap.find(zId)==m_state->m_zIdToLineStyleMap.end())
2324
3.32k
    m_state->m_zIdToLineStyleMap[zId]=style;
2325
86.1k
  ascii().addPos(pos);
2326
86.1k
  ascii().addNote(f.str().c_str());
2327
86.1k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
2328
2329
86.1k
  return true;
2330
86.1k
}
2331
2332
bool FreeHandParser::readPostscriptStyle(int zId)
2333
74.5k
{
2334
74.5k
  MWAWInputStreamPtr input = getInput();
2335
74.5k
  libmwaw::DebugStream f;
2336
2337
74.5k
  long pos=input->tell();
2338
74.5k
  if (!input->checkPosition(pos+12))
2339
123
    return false;
2340
74.4k
  f.str("");
2341
74.4k
  if (zId)
2342
2.37k
    f << "Entries(Postscript)[Z" << zId << "]:";
2343
72.0k
  else
2344
72.0k
    f << "Entries(Postscript):";
2345
74.4k
  if (zId) {
2346
2.37k
    auto type=m_state->getZoneType(zId);
2347
2.37k
    if (type!=FreeHandParserInternal::Z_Fill && type!=FreeHandParserInternal::Z_LineStyle) {
2348
504
      MWAW_DEBUG_MSG(("FreeHandParser::readPostscriptStyle: find unexpected zone type for zone %d\n", zId));
2349
504
    }
2350
2.37k
  }
2351
74.4k
  FreeHandParserInternal::StyleHeader zone;
2352
74.4k
  if (!readStyleHeader(zone)) {
2353
5.00k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2354
5.00k
    return false;
2355
5.00k
  }
2356
69.3k
  f << zone;
2357
69.3k
  long endPos;
2358
69.3k
  int sSz;
2359
69.3k
  if (version()==1) {
2360
64.2k
    if (zone.m_type!=0x10cf) {
2361
0
      input->seek(pos, librevenge::RVNG_SEEK_SET);
2362
0
      return false;
2363
0
    }
2364
64.2k
    if (zone.m_size!=0x12) f << "sz?=" << zone.m_size << ",";
2365
64.2k
    sSz=static_cast<int>(input->readULong(1));
2366
64.2k
    endPos=input->tell()+sSz;
2367
64.2k
  }
2368
5.11k
  else {
2369
5.11k
    bool ok=true;
2370
5.11k
    if (zone.m_type==0x14c9)
2371
2.57k
      f << "surf,";
2372
2.53k
    else if (zone.m_type==0x14ca)
2373
2.53k
      f << "line,";
2374
0
    else
2375
0
      ok=false;
2376
5.11k
    if (!ok || zone.m_size<16) {
2377
164
      input->seek(pos, librevenge::RVNG_SEEK_SET);
2378
164
      return false;
2379
164
    }
2380
14.8k
    for (int i=0; i<2; ++i) { // always 0?
2381
9.89k
      auto val=static_cast<int>(input->readLong(2));
2382
9.89k
      if (val) f << "f" << i << "=" << val << ",";
2383
9.89k
    }
2384
4.94k
    endPos=pos+zone.m_size-4;
2385
4.94k
    sSz=int(zone.m_size-16);
2386
4.94k
  }
2387
69.2k
  if (!input->checkPosition(endPos)) {
2388
414
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2389
414
    return false;
2390
414
  }
2391
68.8k
  std::string text;
2392
1.01M
  for (int i=0; i<sSz; ++i) text+=char(input->readULong(1));
2393
68.8k
  if (!text.empty())
2394
31.1k
    f << "ps=\"" << text << "\",";
2395
68.8k
  if (zId && m_state->m_zIdToPostscriptMap.find(zId)==m_state->m_zIdToPostscriptMap.end())
2396
2.32k
    m_state->m_zIdToPostscriptMap[zId]=text;
2397
68.8k
  ascii().addPos(pos);
2398
68.8k
  ascii().addNote(f.str().c_str());
2399
68.8k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
2400
2401
68.8k
  return true;
2402
69.2k
}
2403
2404
bool FreeHandParser::readBackgroundPicture(int zId)
2405
48.5k
{
2406
48.5k
  MWAWInputStreamPtr input = getInput();
2407
48.5k
  libmwaw::DebugStream f;
2408
2409
48.5k
  long pos=input->tell();
2410
48.5k
  FreeHandParserInternal::ShapeHeader shape;
2411
48.5k
  if (!readShapeHeader(shape) || shape.m_type!=0x1007 || !input->checkPosition(input->tell()+32)) {
2412
13.5k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2413
13.5k
    return false;
2414
13.5k
  }
2415
34.9k
  FreeHandParserInternal::Shape res;
2416
34.9k
  res.m_type=FreeHandParserInternal::Shape::BackgroundPicture;
2417
34.9k
  res.m_layerId=shape.m_layerId;
2418
34.9k
  if (zId)
2419
94
    f << "Entries(BackgroundPicture)[Z" << zId << "]:" << shape;
2420
34.8k
  else
2421
34.8k
    f << "Entries(BackgroundPicture):" << shape;
2422
524k
  for (int i=0; i<14; ++i) { // f1=29|39, f2=1, f8=1, f10=0|-5, f12=109|113|118
2423
489k
    auto val=static_cast<int>(input->readLong(2));
2424
489k
    if (val) f << "f" << i << "=" << val << ",";
2425
489k
  }
2426
34.9k
  auto picSize=long(input->readLong(4));
2427
34.9k
  res.m_picture.setBegin(input->tell());
2428
34.9k
  res.m_picture.setLength(picSize);
2429
34.9k
  if (picSize<0 || !input->checkPosition(res.m_picture.end())) {
2430
26.3k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2431
26.3k
    return false;
2432
26.3k
  }
2433
8.64k
  ascii().skipZone(res.m_picture.begin(), res.m_picture.end()-1);
2434
8.64k
  input->seek(picSize, librevenge::RVNG_SEEK_CUR);
2435
8.64k
  ascii().addPos(pos);
2436
8.64k
  ascii().addNote(f.str().c_str());
2437
2438
8.64k
  if (zId && m_state->m_zIdToShapeMap.find(zId)==m_state->m_zIdToShapeMap.end())
2439
29
    m_state->m_zIdToShapeMap.insert(std::map<int, FreeHandParserInternal::Shape>::value_type(zId,res));
2440
8.64k
  return true;
2441
34.9k
}
2442
2443
bool FreeHandParser::readPictureZone(int zId)
2444
117k
{
2445
117k
  MWAWInputStreamPtr input = getInput();
2446
117k
  libmwaw::DebugStream f;
2447
2448
117k
  long pos=input->tell();
2449
117k
  FreeHandParserInternal::ShapeHeader shape;
2450
117k
  if (!readShapeHeader(shape) || shape.m_type!=0x13f8 || !input->checkPosition(input->tell()+58)) {
2451
1.56k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2452
1.56k
    return false;
2453
1.56k
  }
2454
115k
  long endPos=input->tell()+58;
2455
115k
  FreeHandParserInternal::Shape res;
2456
115k
  res.m_type=FreeHandParserInternal::Shape::Picture;
2457
115k
  res.m_layerId=shape.m_layerId;
2458
115k
  if (zId)
2459
248
    f << "Entries(Picture)[Z" << zId << "]:" << shape;
2460
115k
  else
2461
115k
    f << "Entries(Picture):" << shape;
2462
115k
  if (zId && m_state->getZoneType(zId)!=FreeHandParserInternal::Z_Shape) {
2463
245
    MWAW_DEBUG_MSG(("FreeHandParser::readPictureZone: find unexpected zone type for zone %d\n", zId));
2464
245
  }
2465
290k
  for (int i=0; i<2; ++i) {
2466
215k
    auto id=static_cast<int>(input->readULong(2));
2467
215k
    if (!id) continue;
2468
187k
    if (!m_state->addZoneId(id, i==0 ? FreeHandParserInternal::Z_Picture : FreeHandParserInternal::Z_PictureName)) {
2469
40.9k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
2470
40.9k
      return false;
2471
40.9k
    }
2472
146k
    if (i==0) {
2473
84.2k
      res.m_dataId=id;
2474
84.2k
      f << "data=Z" << id << ",";
2475
84.2k
    }
2476
61.9k
    else
2477
61.9k
      f << "name=Z" << id << ",";
2478
146k
  }
2479
74.9k
  auto val=static_cast<int>(input->readLong(2)); // 0
2480
74.9k
  if (val) f << "f0=" << val << ",";
2481
74.9k
  float dim[6];
2482
224k
  for (int i=0; i<2; ++i) dim[i]=float(input->readLong(2))/10.f;
2483
74.9k
  f << "dim=" << MWAWVec2f(dim[1],dim[0]) << ",";
2484
  // checkme: why are the coord inverted ?
2485
74.9k
  res.m_box=MWAWBox2f(MWAWVec2f(0,0), MWAWVec2f(dim[1],dim[0]));
2486
224k
  for (int i=0; i<2; ++i) { // 0?
2487
149k
    val=static_cast<int>(input->readLong(2)); // 0
2488
149k
    if (val) f << "f" << i+1 << "=" << val << ",";
2489
149k
  }
2490
74.9k
  f << "flags=" << std::hex << input->readULong(2) << std::dec << ",";
2491
74.9k
  f << "rot=[";
2492
374k
  for (int i=0; i<4; ++i) {
2493
299k
    dim[i]=float(input->readLong(4))/65536.f;
2494
299k
    f << dim[i] << ",";
2495
299k
  }
2496
74.9k
  f << "],";
2497
74.9k
  f << "trans=[";
2498
224k
  for (int i=0; i<2; ++i) {
2499
149k
    dim[i+4]=float(input->readLong(4))/65536.f/10.f;
2500
149k
    f << dim[i+4] << ",";
2501
149k
  }
2502
74.9k
  f << "],";
2503
74.9k
  res.m_transformation=MWAWTransformation(MWAWVec3f(dim[0],dim[2],dim[4]),MWAWVec3f(dim[1],dim[3],dim[5]));
2504
74.9k
  auto id=static_cast<int>(input->readULong(2));
2505
74.9k
  if (id && !m_state->addZoneId(id, FreeHandParserInternal::Z_Color)) {
2506
19.1k
    MWAW_DEBUG_MSG(("FreeHandParser::readPictureZone: find unexpected colorId\n"));
2507
19.1k
    f << "###colorId,";
2508
19.1k
  }
2509
55.7k
  else if (id)
2510
30.4k
    f << "color=Z" << id << ",";
2511
224k
  for (int i=0; i<2; ++i) {
2512
149k
    int iDim[4];
2513
599k
    for (auto &d : iDim) d=static_cast<int>(input->readLong(2));
2514
149k
    f << "box" << i << "=" << MWAWBox2i(MWAWVec2i(iDim[0],iDim[1]),MWAWVec2i(iDim[2],iDim[3])) << ",";
2515
149k
  }
2516
74.9k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
2517
74.9k
  ascii().addPos(pos);
2518
74.9k
  ascii().addNote(f.str().c_str());
2519
2520
74.9k
  if (zId && m_state->m_zIdToShapeMap.find(zId)==m_state->m_zIdToShapeMap.end())
2521
237
    m_state->m_zIdToShapeMap.insert(std::map<int, FreeHandParserInternal::Shape>::value_type(zId,res));
2522
74.9k
  return true;
2523
115k
}
2524
2525
bool FreeHandParser::readShape(int zId)
2526
160k
{
2527
160k
  MWAWInputStreamPtr input = getInput();
2528
160k
  libmwaw::DebugStream f;
2529
2530
160k
  long pos=input->tell();
2531
160k
  FreeHandParserInternal::ShapeHeader shape;
2532
160k
  if (!readShapeHeader(shape)) {
2533
26.3k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2534
26.3k
    return false;
2535
26.3k
  }
2536
133k
  bool canHaveMatrix=true, hasDimension=true;
2537
133k
  int dataSize=-1;
2538
133k
  FreeHandParserInternal::Shape res;
2539
133k
  res.m_layerId=shape.m_layerId;
2540
133k
  const int vers=version();
2541
133k
  switch (shape.m_type) {
2542
16.3k
  case 0x1131:
2543
26.1k
  case 0x1519:
2544
26.1k
    if (zId)
2545
8.91k
      f << "Entries(Rectangle)[Z" << zId << "]:" << shape;
2546
17.2k
    else
2547
17.2k
      f << "Entries(Rectangle):" << shape;
2548
26.1k
    dataSize=4;
2549
26.1k
    res.m_type=FreeHandParserInternal::Shape::Rectangle;
2550
26.1k
    break;
2551
38.6k
  case 0x1132:
2552
43.4k
  case 0x151a:
2553
43.4k
    if (zId)
2554
4.83k
      f << "Entries(Circle)[Z" << zId << "]:" << shape;
2555
38.5k
    else
2556
38.5k
      f << "Entries(Circle):" << shape;
2557
43.4k
    dataSize=0;
2558
43.4k
    res.m_type=FreeHandParserInternal::Shape::Ellipse;
2559
43.4k
    break;
2560
16.5k
  case 0x1134:
2561
48.1k
  case 0x151c:
2562
48.1k
    if (zId)
2563
1.50k
      f << "Entries(Spline)[Z" << zId << "]:" << shape;
2564
46.6k
    else
2565
46.6k
      f << "Entries(Spline):" << shape;
2566
48.1k
    dataSize=4;
2567
48.1k
    hasDimension=canHaveMatrix=false;
2568
48.1k
    res.m_type=FreeHandParserInternal::Shape::Path;
2569
48.1k
    break;
2570
8.23k
  case 0x1135:
2571
16.0k
  case 0x151d:
2572
16.0k
    if (zId)
2573
4.33k
      f << "Entries(Line)[Z" << zId << "]:" << shape;
2574
11.7k
    else
2575
11.7k
      f << "Entries(Line):" << shape;
2576
16.0k
    dataSize=0;
2577
16.0k
    canHaveMatrix=false;
2578
16.0k
    res.m_type=FreeHandParserInternal::Shape::Line;
2579
16.0k
    break;
2580
0
  default:
2581
0
    break;
2582
133k
  }
2583
133k
  if (dataSize<0 || !input->checkPosition(input->tell()+4+(vers>1 ? 6 : 0)+(hasDimension ? 8 : 0)+(canHaveMatrix ? 4 : 0)+dataSize)) {
2584
1.27k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2585
1.27k
    return false;
2586
1.27k
  }
2587
132k
  f << "sz?=" << shape.m_size << ",";
2588
132k
  if (zId && m_state->getZoneType(zId)!=FreeHandParserInternal::Z_Shape) {
2589
2.67k
    MWAW_DEBUG_MSG(("FreeHandParser::readShape: find unexpected zone type for zone %d\n", zId));
2590
2.67k
  }
2591
132k
  if (vers>1) {
2592
53.8k
    auto id=static_cast<int>(input->readULong(2));
2593
53.8k
    if (id && !m_state->addZoneId(id, FreeHandParserInternal::Z_Group)) {
2594
6.55k
      MWAW_DEBUG_MSG(("FreeHandParser::readShapeHeader: find unexpected group id\n"));
2595
6.55k
      f << "###groupId,";
2596
6.55k
    }
2597
47.3k
    else if (id) {
2598
28.7k
      f << "group=Z" << id << ",";
2599
28.7k
      res.m_childs.push_back(id);
2600
28.7k
    }
2601
53.8k
  }
2602
132k
  auto id=static_cast<int>(input->readLong(2)); // always 0?
2603
132k
  if (id &&  !m_state->addZoneId(id, FreeHandParserInternal::Z_Fill)) {
2604
20.1k
    MWAW_DEBUG_MSG(("FreeHandParser::readShape: find a bad color\n"));
2605
20.1k
    f << "###";
2606
20.1k
  }
2607
132k
  if (id) f << "fill=Z" << id << ",";
2608
132k
  res.m_fillId=id;
2609
132k
  id=static_cast<int>(input->readULong(2));
2610
132k
  if (id &&  !m_state->addZoneId(id, FreeHandParserInternal::Z_LineStyle)) {
2611
19.8k
    MWAW_DEBUG_MSG(("FreeHandParser::readShape: find a bad style\n"));
2612
19.8k
    f << "###";
2613
19.8k
  }
2614
132k
  if (id) f << "line[style]=Z" << id << ",";
2615
132k
  res.m_lineId=id;
2616
132k
  if (vers>1) {
2617
161k
    for (int i=0; i<2; ++i) { // always 0?
2618
107k
      auto val=static_cast<int>(input->readULong(2));
2619
107k
      if (val) f << "f" << i << "=" << val << ",";
2620
107k
    }
2621
53.8k
  }
2622
132k
  if (hasDimension) {
2623
84.6k
    float dim[4];
2624
338k
    for (auto &d : dim) d=float(input->readLong(2))/10.f;
2625
84.6k
    res.m_box=MWAWBox2f(MWAWVec2f(dim[0],dim[1]),MWAWVec2f(dim[2],dim[3]));
2626
84.6k
    f << "rect=" << res.m_box << ",";
2627
84.6k
  }
2628
132k
  int dSz=canHaveMatrix ? static_cast<int>(input->readULong(4)) : 0;
2629
132k
  if (dSz<0 || !input->checkPosition(input->tell()+dSz+dataSize)) {
2630
42.3k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2631
42.3k
    return false;
2632
42.3k
  }
2633
90.2k
  if (dSz==0x1a) {
2634
2.05k
    f << "flags=" << std::hex << input->readULong(2) << std::dec << ",";
2635
2.05k
    float dim[6];
2636
2.05k
    f << "rot=[";
2637
10.2k
    for (int i=0; i<4; ++i) {
2638
8.20k
      dim[i]=float(input->readLong(4))/65536.f;
2639
8.20k
      f << dim[i] << ",";
2640
8.20k
    }
2641
2.05k
    f << "],";
2642
2.05k
    f << "trans=[";
2643
6.15k
    for (int i=0; i<2; ++i) {
2644
4.10k
      dim[i+4]=float(input->readLong(4))/65536.f/10.f;
2645
4.10k
      f << dim[i+4] << ",";
2646
4.10k
    }
2647
2.05k
    f << "],";
2648
2.05k
    res.m_transformation=MWAWTransformation(MWAWVec3f(dim[0],dim[2],dim[4]),MWAWVec3f(dim[1],dim[3],dim[5]));
2649
2.05k
  }
2650
88.1k
  else if (dSz) {
2651
5.11k
    MWAW_DEBUG_MSG(("FreeHandParser::readShape: find unknown matrix size\n"));
2652
5.11k
    f << "###matrix,";
2653
5.11k
    input->seek(dSz, librevenge::RVNG_SEEK_CUR);
2654
5.11k
  }
2655
90.2k
  if (shape.m_type==0x1131 || shape.m_type==0x1519) {
2656
16.5k
    float dim[2];
2657
33.0k
    for (auto &d : dim) d=float(input->readLong(2))/10.f;
2658
16.5k
    res.m_corner=MWAWVec2f(dim[0],dim[1]);
2659
16.5k
    if (res.m_corner!=MWAWVec2f(0,0))
2660
6.29k
      f << "corner=" << res.m_corner << ",";
2661
16.5k
  }
2662
90.2k
  if (shape.m_type==0x1134 || shape.m_type==0x151c) {
2663
47.8k
    auto val=static_cast<int>(input->readULong(2));
2664
47.8k
    if (val&1) {
2665
16.4k
      res.m_closed=true;
2666
16.4k
      f << "closed,";
2667
16.4k
    }
2668
47.8k
    if (val&2) {
2669
21.2k
      res.m_evenOdd=true;
2670
21.2k
      f << "even/odd,";
2671
21.2k
    }
2672
47.8k
    val &= 0xFFFC;
2673
    // find also 4
2674
47.8k
    if (val) f << "fl=" << std::hex << val << std::dec << ",";
2675
47.8k
    auto nPt=static_cast<int>(input->readULong(2));
2676
47.8k
    f << "N=" << nPt << ",";
2677
47.8k
    if (!input->checkPosition(input->tell()+16*nPt)) {
2678
24.1k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
2679
24.1k
      return false;
2680
24.1k
    }
2681
23.7k
    ascii().addPos(pos);
2682
23.7k
    ascii().addNote(f.str().c_str());
2683
526k
    for (int i=0; i<nPt; ++i) {
2684
503k
      pos=input->tell();
2685
503k
      f.str("");
2686
503k
      f << "Spline-" << i << ":";
2687
503k
      val=static_cast<int>(input->readULong(2));
2688
503k
      switch (val) {
2689
190k
      case 0: // corner
2690
190k
        break;
2691
5.42k
      case 1:
2692
5.42k
        f << "connector,";
2693
5.42k
        break;
2694
11.7k
      case 2:
2695
11.7k
        f << "curve,";
2696
11.7k
        break;
2697
295k
      default:
2698
        // find also 0xf0
2699
295k
        MWAW_DEBUG_MSG(("FreeHandParser::readShape: find unknown point type\n"));
2700
295k
        f << "#type=" << val << ",";
2701
503k
      }
2702
503k
      val=static_cast<int>(input->readULong(2));
2703
503k
      if (val&0x100) f << "no[autoCurvature],";
2704
503k
      val &= 0xFEFF;
2705
      // find unknow [01][4|9|b]
2706
503k
      if (val) f << "fl=" << std::hex << val << std::dec << ",";
2707
503k
      MWAWVec2f coord[3];
2708
1.50M
      for (auto &pt : coord) {
2709
1.50M
        float dim[2];
2710
3.01M
        for (auto &d : dim) d=float(input->readLong(2))/10.f;
2711
1.50M
        pt=MWAWVec2f(dim[0], dim[1]);
2712
1.50M
        res.m_vertices.push_back(pt);
2713
1.50M
      }
2714
503k
      if (coord[0]==coord[1] && coord[0]==coord[2])
2715
151k
        f << coord[0] << ",";
2716
351k
      else
2717
351k
        f << "pts=[" << coord[0] << "," << coord[1] << "," << coord[2] << "],";
2718
503k
      ascii().addPos(pos);
2719
503k
      ascii().addNote(f.str().c_str());
2720
503k
    }
2721
23.7k
  }
2722
42.3k
  else {
2723
42.3k
    ascii().addPos(pos);
2724
42.3k
    ascii().addNote(f.str().c_str());
2725
42.3k
  }
2726
66.0k
  if (zId && m_state->m_zIdToShapeMap.find(zId)==m_state->m_zIdToShapeMap.end())
2727
19.2k
    m_state->m_zIdToShapeMap.insert(std::map<int, FreeHandParserInternal::Shape>::value_type(zId,res));
2728
66.0k
  return true;
2729
90.2k
}
2730
2731
bool FreeHandParser::readTextboxV1(int zId)
2732
95.9k
{
2733
95.9k
  MWAWInputStreamPtr input = getInput();
2734
95.9k
  libmwaw::DebugStream f;
2735
2736
95.9k
  long pos=input->tell();
2737
95.9k
  FreeHandParserInternal::ShapeHeader shape;
2738
95.9k
  if (!readShapeHeader(shape) || shape.m_type!=0x1006 || !input->checkPosition(input->tell()+4+8+54)) {
2739
34.9k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2740
34.9k
    return false;
2741
34.9k
  }
2742
61.0k
  if (zId)
2743
2.71k
    f << "Entries(Textbox)[Z" << zId << "]:" << shape;
2744
58.2k
  else
2745
58.2k
    f << "Entries(Textbox):" << shape;
2746
61.0k
  FreeHandParserInternal::Textbox textbox(zId);
2747
61.0k
  textbox.m_layerId=shape.m_layerId;
2748
61.0k
  f << "sz?=" << shape.m_size << ",";
2749
61.0k
  if (zId && m_state->getZoneType(zId)!=FreeHandParserInternal::Z_Shape) {
2750
656
    MWAW_DEBUG_MSG(("FreeHandParser::readTextboxV1: find unexpected zone type for zone %d\n", zId));
2751
656
  }
2752
61.0k
  auto val=static_cast<int>(input->readLong(2)); // always 0?
2753
61.0k
  if (val) f << "f0=" << val << ",";
2754
61.0k
  auto nbPt=static_cast<int>(input->readULong(2)); // nbPt=4*textSz
2755
61.0k
  f << "N=" << nbPt << ",";
2756
61.0k
  long actPos=input->tell();
2757
61.0k
  if ((nbPt%2) || !input->checkPosition(actPos+3*(nbPt/2)+8+54)) {
2758
25.2k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2759
25.2k
    return false;
2760
25.2k
  }
2761
  // probably nbPt/2 float (size of each char)+ nbPt/2 bytes (flag?)
2762
35.7k
  ascii().skipZone(actPos, actPos+3*(nbPt/2)-1);
2763
2764
35.7k
  actPos+=3*(nbPt/2);
2765
35.7k
  ascii().addPos(pos);
2766
35.7k
  ascii().addNote(f.str().c_str());
2767
2768
35.7k
  input->seek(actPos, librevenge::RVNG_SEEK_SET);
2769
35.7k
  f.str("");
2770
35.7k
  f << "Textbox-A:";
2771
143k
  for (int i=0; i<3; ++i) { // f0=0|2|-82|-123|-225, f1=0|-41|-82|-123|-151, f2=0
2772
107k
    val=static_cast<int>(input->readLong(2));
2773
107k
    if (val) f << "f" << i << "=" << val << ",";
2774
107k
  }
2775
35.7k
  auto sSz=static_cast<int>(input->readULong(2));
2776
35.7k
  if (!input->checkPosition(input->tell()+sSz+54)) {
2777
6.76k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2778
6.76k
    return false;
2779
6.76k
  }
2780
29.0k
  f << "text[sz]=" << sSz << ",";
2781
29.0k
  ascii().addPos(actPos);
2782
29.0k
  ascii().addNote(f.str().c_str());
2783
2784
29.0k
  textbox.m_text.setBegin(input->tell());
2785
29.0k
  textbox.m_text.setLength(sSz);
2786
29.0k
  input->seek(textbox.m_text.end(), librevenge::RVNG_SEEK_SET);
2787
2788
29.0k
  actPos=input->tell();
2789
29.0k
  f.str("");
2790
29.0k
  f << "Textbox-B:";
2791
29.0k
  float dim[6];
2792
145k
  for (int i=0; i<4; ++i) dim[i]=float(input->readLong(2))/10.f;
2793
29.0k
  textbox.m_box=MWAWBox2f(MWAWVec2f(dim[0],dim[1]),MWAWVec2f(dim[2],dim[3]));
2794
29.0k
  f << "dim=" << textbox.m_box << ",";
2795
29.0k
  f << "flags=" << std::hex << input->readULong(2) << std::dec << ",";
2796
29.0k
  f << "rot=[";
2797
145k
  for (int i=0; i<4; ++i) {
2798
116k
    dim[i]=float(input->readLong(4))/65536.f;
2799
116k
    f << dim[i] << ",";
2800
116k
  }
2801
29.0k
  f << "],";
2802
29.0k
  f << "trans=[";
2803
87.0k
  for (int i=0; i<2; ++i) {
2804
58.0k
    dim[i+4]=float(input->readLong(4))/65536.f/10.f;
2805
58.0k
    f << dim[i+4] << ",";
2806
58.0k
  }
2807
29.0k
  f << "],";
2808
29.0k
  textbox.m_transformation=MWAWTransformation(MWAWVec3f(dim[0],dim[2],dim[4]),MWAWVec3f(dim[1],dim[3],dim[5]));
2809
29.0k
  f << "spacing=["; // letter and word
2810
87.0k
  for (int i=0; i<2; ++i) {
2811
58.0k
    dim[i]=float(input->readLong(4))/65536.f/10.f;
2812
58.0k
    f << dim[i] << ",";
2813
58.0k
  }
2814
29.0k
  f << "],";
2815
29.0k
  textbox.m_spacings=MWAWVec2f(dim[0],dim[1]);
2816
29.0k
  f << "scaling=[";
2817
87.0k
  for (int i=0; i<2; ++i) {
2818
58.0k
    dim[i]=float(input->readLong(4))/65536.f;
2819
58.0k
    f << dim[i] << ",";
2820
58.0k
  }
2821
29.0k
  f << "],";
2822
29.0k
  textbox.m_scalings=MWAWVec2f(dim[0],dim[1]);
2823
29.0k
  val=static_cast<int>(input->readLong(1)); // 0|1|2
2824
29.0k
  if (val) f << "f0=" << val << ",";
2825
29.0k
  val=static_cast<int>(input->readLong(1));
2826
29.0k
  switch (val) {
2827
11.2k
  case 0: // left
2828
11.2k
    break;
2829
1.25k
  case 1:
2830
1.25k
    f << "right,";
2831
1.25k
    textbox.m_justify=MWAWParagraph::JustificationRight;
2832
1.25k
    break;
2833
6.01k
  case 2:
2834
6.01k
    f << "center,";
2835
6.01k
    textbox.m_justify=MWAWParagraph::JustificationCenter;
2836
6.01k
    break;
2837
407
  case 3:
2838
407
    f << "justify=all,";
2839
407
    textbox.m_justify=MWAWParagraph::JustificationFull;
2840
407
    break;
2841
10.0k
  default:
2842
10.0k
    MWAW_DEBUG_MSG(("FreeHandParser::readTextboxV1: find unexpected align\n"));
2843
10.0k
    f << "###align=" << val << ",";
2844
10.0k
    break;
2845
29.0k
  }
2846
29.0k
  auto nPLC=static_cast<int>(input->readULong(2));
2847
29.0k
  f << "NPLC=" << nPLC << ",";
2848
29.0k
  if (!input->checkPosition(input->tell()+18*nPLC)) {
2849
16.4k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2850
16.4k
    return false;
2851
16.4k
  }
2852
12.5k
  ascii().addPos(actPos);
2853
12.5k
  ascii().addNote(f.str().c_str());
2854
1.14M
  for (int plc=0; plc<nPLC; ++plc) {
2855
1.13M
    actPos=input->tell();
2856
1.13M
    f.str("");
2857
1.13M
    f << "Textbox-PLC" << plc << ":";
2858
1.13M
    FreeHandParserInternal::Font font;
2859
1.13M
    if (plc+1!=nPLC) {
2860
1.12M
      auto id=static_cast<int>(input->readULong(2));
2861
1.12M
      if (id && !m_state->addZoneId(id, FreeHandParserInternal::Z_String)) {
2862
250k
        MWAW_DEBUG_MSG(("FreeHandParser::readTextboxV1: find bad font name\n"));
2863
250k
        f << "###";
2864
250k
      }
2865
1.12M
      font.m_nameId=id;
2866
1.12M
      if (id)
2867
830k
        f << "font[name]=Z" << id << ",";
2868
1.12M
      id=static_cast<int>(input->readULong(2));
2869
1.12M
      if (id && !m_state->addZoneId(id, FreeHandParserInternal::Z_Color)) {
2870
344k
        MWAW_DEBUG_MSG(("FreeHandParser::readTextboxV1: find bad color\n"));
2871
344k
        f << "###";
2872
344k
      }
2873
1.12M
      if (id)
2874
831k
        f << "color=Z" << id << ",";
2875
1.12M
      font.m_colorId=id;
2876
1.12M
      float sz=float(input->readLong(4))/65536.f;
2877
1.12M
      font.m_font.setSize(sz);
2878
1.12M
      f << "font[sz]=" << sz << ",";
2879
1.12M
      val=static_cast<int>(input->readLong(4));
2880
1.12M
      switch (val) { // useme
2881
3.65k
      case -2: // solid
2882
3.65k
        break;
2883
20.0k
      case -1:
2884
20.0k
        f << "leading=auto,";
2885
20.0k
        break;
2886
1.10M
      default:
2887
1.10M
        f << "leading=" << float(val)/65536.f << ",";
2888
1.12M
      }
2889
1.12M
    }
2890
8.29k
    else
2891
8.29k
      input->seek(12, librevenge::RVNG_SEEK_CUR);
2892
1.13M
    auto cPos=static_cast<int>(input->readULong(2));
2893
1.13M
    f << "pos=" << cPos << ",";
2894
1.13M
    uint32_t flags=0;
2895
1.13M
    val=static_cast<int>(input->readULong(2));
2896
1.13M
    if (val & 1) {
2897
367k
      flags |= MWAWFont::boldBit;
2898
367k
      f << "bold,";
2899
367k
    }
2900
1.13M
    if (val & 2) {
2901
305k
      flags |= MWAWFont::italicBit;
2902
305k
      f << "italic,";
2903
305k
    }
2904
1.13M
    val &= 0xFFFC;
2905
1.13M
    if (val && plc+1!=nPLC) {
2906
794k
      MWAW_DEBUG_MSG(("FreeHandParser::readTextboxV1: find unknown font flag1\n"));
2907
794k
      f << "##flag1=" << std::hex << val << std::dec << ",";
2908
794k
    }
2909
1.13M
    val=static_cast<int>(input->readULong(2));
2910
1.13M
    switch (val) {
2911
17.9k
    case 1: // solid
2912
17.9k
      break;
2913
8.84k
    case 2:
2914
8.84k
      flags |= MWAWFont::boldBit;
2915
8.84k
      f << "heavy,";
2916
8.84k
      break;
2917
9.40k
    case 3:
2918
9.40k
      flags |= MWAWFont::italicBit;
2919
9.40k
      f << "oblique,";
2920
9.40k
      break;
2921
6.65k
    case 4:
2922
6.65k
      flags |= MWAWFont::outlineBit;
2923
6.65k
      f << "outline,";
2924
6.65k
      break;
2925
7.09k
    case 5:
2926
7.09k
      flags |= MWAWFont::shadowBit;
2927
7.09k
      f << "shadow,";
2928
7.09k
      break;
2929
1.08M
    default:
2930
1.08M
      if (plc+1==nPLC) break;
2931
1.07M
      MWAW_DEBUG_MSG(("FreeHandParser::readTextboxV1: find unknown font flag2\n"));
2932
1.07M
      f << "##flag2=" << val << ",";
2933
1.07M
      break;
2934
1.13M
    }
2935
1.13M
    font.m_font.setFlags(flags);
2936
1.13M
    textbox.m_posToFontMap[cPos]=font;
2937
1.13M
    ascii().addPos(actPos);
2938
1.13M
    ascii().addNote(f.str().c_str());
2939
1.13M
  }
2940
12.5k
  if (zId && m_state->m_zIdToTextboxMap.find(zId)==m_state->m_zIdToTextboxMap.end())
2941
2.49k
    m_state->m_zIdToTextboxMap.insert(std::map<int, FreeHandParserInternal::Textbox>::value_type(zId,textbox));
2942
2943
12.5k
  return true;
2944
12.5k
}
2945
2946
bool FreeHandParser::readTextboxV2(int zId)
2947
76.0k
{
2948
76.0k
  MWAWInputStreamPtr input = getInput();
2949
76.0k
  libmwaw::DebugStream f;
2950
2951
76.0k
  long pos=input->tell();
2952
76.0k
  FreeHandParserInternal::ShapeHeader shape;
2953
76.0k
  if (!readShapeHeader(shape) || shape.m_type!=0x13ee || !input->checkPosition(input->tell()+66)) {
2954
2.97k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
2955
2.97k
    return false;
2956
2.97k
  }
2957
73.0k
  if (zId)
2958
981
    f << "Entries(Textbox)[Z" << zId << "]:" << shape;
2959
72.0k
  else
2960
72.0k
    f << "Entries(Textbox):" << shape;
2961
73.0k
  FreeHandParserInternal::Textbox textbox(zId);
2962
73.0k
  textbox.m_layerId=shape.m_layerId;
2963
73.0k
  f << "sz?=" << shape.m_size << ",";
2964
73.0k
  if (zId && m_state->getZoneType(zId)!=FreeHandParserInternal::Z_Shape) {
2965
205
    MWAW_DEBUG_MSG(("FreeHandParser::readTextboxV2: find unexpected zone type for zone %d\n", zId));
2966
205
  }
2967
511k
  for (int i=0; i<6; ++i) { // f3=0|2, f4=0|1
2968
438k
    auto val=static_cast<int>(input->readLong(2));
2969
438k
    if (val) f << "f" << i << "=" << val << ",";
2970
438k
  }
2971
73.0k
  auto val=static_cast<int>(input->readULong(2)); // 1a|7b|c3|eb|f4|fb|114|1af|7d00|7d02
2972
73.0k
  if (val) f << "f6=" << val << ",";
2973
73.0k
  float dim[6];
2974
365k
  for (int i=0; i<4; ++i) dim[i]=float(input->readLong(2))/10.f;
2975
73.0k
  textbox.m_box=MWAWBox2f(MWAWVec2f(dim[0],dim[1]),MWAWVec2f(dim[2],dim[3]));
2976
73.0k
  f << "dim=" << textbox.m_box << ",";
2977
73.0k
  val=static_cast<int>(input->readULong(2)); // 0
2978
73.0k
  if (val) f << "f7=" << val << ",";
2979
73.0k
  f << "flags=" << std::hex << input->readULong(2) << std::dec << ",";
2980
73.0k
  f << "rot=[";
2981
365k
  for (int i=0; i<4; ++i) {
2982
292k
    dim[i]=float(input->readLong(4))/65536.f;
2983
292k
    f << dim[i] << ",";
2984
292k
  }
2985
73.0k
  f << "],";
2986
73.0k
  f << "trans=[";
2987
219k
  for (int i=0; i<2; ++i) {
2988
146k
    dim[i+4]=float(input->readLong(4))/65536.f/10.f;
2989
146k
    f << dim[i+4] << ",";
2990
146k
  }
2991
73.0k
  f << "],";
2992
73.0k
  textbox.m_transformation=MWAWTransformation(MWAWVec3f(dim[0],dim[2],dim[4]),MWAWVec3f(dim[1],dim[3],dim[5]));
2993
73.0k
  val=static_cast<int>(input->readLong(1));
2994
73.0k
  switch (val) {
2995
39.5k
  case 0: // left
2996
39.5k
    break;
2997
1.29k
  case 1:
2998
1.29k
    f << "center,";
2999
1.29k
    textbox.m_justify=MWAWParagraph::JustificationCenter;
3000
1.29k
    break;
3001
2.11k
  case 2:
3002
2.11k
    f << "right,";
3003
2.11k
    textbox.m_justify=MWAWParagraph::JustificationRight;
3004
2.11k
    break;
3005
6.32k
  case 3:
3006
6.32k
    f << "justify=all,";
3007
6.32k
    textbox.m_justify=MWAWParagraph::JustificationFull;
3008
6.32k
    break;
3009
23.8k
  default:
3010
23.8k
    MWAW_DEBUG_MSG(("FreeHandParser::readTextboxV2: find unexpected align\n"));
3011
23.8k
    f << "###align=" << val << ",";
3012
23.8k
    break;
3013
73.0k
  }
3014
73.0k
  ascii().addDelimiter(input->tell(), '|');
3015
73.0k
  ascii().addPos(pos);
3016
73.0k
  ascii().addNote(f.str().c_str());
3017
73.0k
  input->seek(11, librevenge::RVNG_SEEK_CUR);
3018
3019
73.0k
  pos=input->tell();
3020
73.0k
  f.str("");
3021
73.0k
  f << "Textbox-A:";
3022
73.0k
  auto dSz=static_cast<int>(input->readULong(2));
3023
73.0k
  auto sSz=static_cast<int>(input->readULong(2));
3024
73.0k
  long endPos=pos+dSz-18-80;
3025
73.0k
  if (dSz-18-80<58 || !input->checkPosition(endPos)) {
3026
46.6k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
3027
46.6k
    return false;
3028
46.6k
  }
3029
26.4k
  f << "text[sz]=" << sSz << ",";
3030
26.4k
  val=static_cast<int>(input->readULong(2));
3031
26.4k
  if (val!=sSz) f << "text[pos]=" << val << ",";
3032
26.4k
  val=static_cast<int>(input->readULong(2)); // always 7ffd ?
3033
26.4k
  if (val!=0x7ffd) f << "f0=" << val << ",";
3034
79.3k
  for (int i=0; i<2; ++i) {
3035
52.8k
    val=static_cast<int>(input->readLong(2));
3036
52.8k
    if (val) f << "f" << i+1 << "=" << val << ",";
3037
52.8k
  }
3038
26.4k
  FreeHandParserInternal::Font font;
3039
26.4k
  auto id=static_cast<int>(input->readULong(2));
3040
26.4k
  if (id && !m_state->addZoneId(id, FreeHandParserInternal::Z_String)) {
3041
172
    MWAW_DEBUG_MSG(("FreeHandParser::readTextboxV2: find bad font name\n"));
3042
172
    f << "###";
3043
172
  }
3044
26.4k
  font.m_nameId=id;
3045
26.4k
  if (id)
3046
23.1k
    f << "font[name]=Z" << id << ",";
3047
26.4k
  float sz=float(input->readLong(4))/65536.f;
3048
26.4k
  font.m_font.setSize(sz);
3049
26.4k
  f << "font[sz]=" << sz << ",";
3050
26.4k
  val=static_cast<int>(input->readULong(4));
3051
  // use me
3052
26.4k
  if (val==static_cast<int>(0xFFFE0000))
3053
0
    f << "leading=auto,";
3054
26.4k
  else if (val!=static_cast<int>(0xFFFF0000)) // no solid
3055
26.4k
    f << "leading=" << float(val)/65536.f << ",";
3056
26.4k
  val=static_cast<int>(input->readLong(2));
3057
26.4k
  if (val) f << "f4=" << val << ",";
3058
26.4k
  uint32_t flags=0;
3059
26.4k
  val=static_cast<int>(input->readULong(2));
3060
26.4k
  if (val & 1) {
3061
16.7k
    flags |= MWAWFont::boldBit;
3062
16.7k
    f << "bold,";
3063
16.7k
  }
3064
26.4k
  if (val & 2) {
3065
18.3k
    flags |= MWAWFont::italicBit;
3066
18.3k
    f << "italic,";
3067
18.3k
  }
3068
26.4k
  val &= 0xFFFC;
3069
26.4k
  if (val) {
3070
5.29k
    MWAW_DEBUG_MSG(("FreeHandParser::readTextboxV2: find unknown font flag1\n"));
3071
5.29k
    f << "##flag1=" << std::hex << val << std::dec << ",";
3072
5.29k
  }
3073
26.4k
  id=static_cast<int>(input->readULong(2));
3074
26.4k
  if (id && !m_state->addZoneId(id, FreeHandParserInternal::Z_Color)) {
3075
1.18k
    MWAW_DEBUG_MSG(("FreeHandParser::readTextboxV2: find bad color\n"));
3076
1.18k
    f << "###";
3077
1.18k
  }
3078
26.4k
  if (id)
3079
7.19k
    f << "color=Z" << id << ",";
3080
26.4k
  font.m_colorId=id;
3081
26.4k
  val=static_cast<int>(input->readLong(2)); // 0
3082
26.4k
  if (val) f << "f6=" << val << ",";
3083
26.4k
  auto special=static_cast<int>(input->readLong(2));
3084
26.4k
  int specialData[6];
3085
185k
  for (int i=0; i<6; ++i) specialData[i]=static_cast<int>(input->readULong(i>=4 ? 1 : 2));
3086
26.4k
  if (!m_state->addZoneId(specialData[0], FreeHandParserInternal::Z_Color)) {
3087
907
    MWAW_DEBUG_MSG(("FreeHandParser::readTextboxV2: find bad text color\n"));
3088
907
    f << "###";
3089
907
  }
3090
26.4k
  if (specialData[0])
3091
7.15k
    f << "col2=Z" << specialData[0] << ",";
3092
26.4k
  switch (special) {
3093
22
  case 1: // solid
3094
22
    break;
3095
1.47k
  case 2:
3096
1.47k
    flags |= MWAWFont::boldBit;
3097
1.47k
    f << "heavy,";
3098
1.47k
    break;
3099
356
  case 3:
3100
356
    flags |= MWAWFont::italicBit;
3101
356
    f << "oblique,";
3102
356
    break;
3103
1.82k
  case 4:
3104
1.82k
    flags |= MWAWFont::outlineBit;
3105
1.82k
    f << "outline,";
3106
1.82k
    break;
3107
280
  case 5:
3108
280
    flags |= MWAWFont::shadowBit;
3109
280
    f << "shadow,";
3110
280
    break;
3111
15.4k
  case 6:
3112
15.4k
    f << "fillAndStroke,";
3113
15.4k
    if (specialData[1]||specialData[2]) {
3114
6.50k
      f << "stroke[w]=" << float((specialData[1]<<16)+specialData[2])/65536.f << ",";
3115
6.50k
      specialData[1]=specialData[2]=0;
3116
6.50k
    }
3117
15.4k
    if (specialData[3]&0x100) f << "fill[set],";
3118
15.4k
    if (specialData[3]&0x1) f << "fill[overprint],";
3119
15.4k
    specialData[3]&=0xfefe;
3120
46.3k
    for (int i=0; i<2; ++i) {
3121
30.9k
      if (!specialData[4+i]) continue;
3122
3123
10.3k
      char const *wh[]= {"stroke[set]", "stroke[overprint]"};
3124
10.3k
      f << wh[i] << "=" << specialData[4+i] << ",";
3125
10.3k
      specialData[4+i]=0;
3126
10.3k
    }
3127
15.4k
    break;
3128
158
  case 0x79:
3129
158
    f << "char,";
3130
790
    for (int i=1; i<5; ++i) {
3131
632
      if (!specialData[i]) continue;
3132
456
      char const *wh[]= {"", "fill[sz]", "line[spacing]", "stroke[width]", "has[stroke]"};
3133
456
      if (i==3)
3134
156
        f << wh[i] << "=" << float(specialData[i])/10.f << ",";
3135
300
      else
3136
300
        f << wh[i] << "=" << specialData[i] << ",";
3137
456
      specialData[i]=0;
3138
456
    }
3139
158
    break;
3140
886
  case 0x7a:
3141
886
    f << "zoom,";
3142
3.54k
    for (int i=1; i<4; ++i) {
3143
2.65k
      if (!specialData[i]) continue;
3144
2.61k
      char const *wh[]= {"", "zoom[horOffset]", "zoom[verOffset]", "zoom[%]"};
3145
2.61k
      f << wh[i] << "=" << specialData[i] << ",";
3146
2.61k
      specialData[i]=0;
3147
2.61k
    }
3148
886
    break;
3149
5.96k
  default:
3150
5.96k
    MWAW_DEBUG_MSG(("FreeHandParser::readTextboxV2: find unknown font flag2\n"));
3151
5.96k
    f << "##flag2=" << special << ",";
3152
5.96k
    break;
3153
26.4k
  }
3154
158k
  for (int i=1; i<6; ++i) {
3155
132k
    if (specialData[i])
3156
37.4k
      f << "#special" << i << "=" << specialData[i] << ",";
3157
132k
  }
3158
26.4k
  font.m_font.setFlags(flags);
3159
26.4k
  textbox.m_posToFontMap[0]=font;
3160
26.4k
  f << "spacing=["; // letter and word
3161
79.3k
  for (int i=0; i<2; ++i) {
3162
52.8k
    dim[i]=float(input->readLong(4))/65536.f;
3163
52.8k
    f << dim[i] << ",";
3164
52.8k
  }
3165
26.4k
  f << "],";
3166
26.4k
  textbox.m_spacings=MWAWVec2f(dim[0],dim[1]);
3167
26.4k
  textbox.m_scalings[0]=float(input->readLong(4))/65536.f;
3168
26.4k
  f << "scalings[hor]=" << textbox.m_scalings[0] << ",";
3169
26.4k
  textbox.m_baseline=float(input->readLong(4))/65536.f;
3170
26.4k
  if (textbox.m_baseline<0||textbox.m_baseline>0)
3171
23.2k
    f << "baseline=" << textbox.m_baseline << ",";
3172
26.4k
  ascii().addPos(pos);
3173
26.4k
  ascii().addNote(f.str().c_str());
3174
  /* CHECKME: find some blocks here : [12bytes]* followed by [unkn]* and [22bytes]*
3175
     for instance
3176
     00290003007a9ce0000ffed1
3177
     002a00190069046000100000
3178
     0012000...
3179
     001a0000000000c9f280000ac3de00033c22000f0000
3180
     00290000000000690460000ac3de00033c22000f0000
3181
     004d0000000000e2f160000ac3de00033c2200120000
3182
     006000000000007a6860000ac3de00033c22000f0000
3183
   */
3184
26.4k
  if (endPos!=input->tell()) {
3185
26.0k
    pos=input->tell();
3186
26.0k
    f.str("");
3187
26.0k
    f << "Textbox-B:";
3188
26.0k
    ascii().addPos(pos);
3189
26.0k
    ascii().addNote(f.str().c_str());
3190
26.0k
  }
3191
26.4k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
3192
3193
26.4k
  textbox.m_text.setBegin(input->tell());
3194
26.4k
  textbox.m_text.setLength(sSz);
3195
26.4k
  input->seek(textbox.m_text.end(), librevenge::RVNG_SEEK_SET);
3196
3197
26.4k
  if (zId && m_state->m_zIdToTextboxMap.find(zId)==m_state->m_zIdToTextboxMap.end())
3198
828
    m_state->m_zIdToTextboxMap.insert(std::map<int, FreeHandParserInternal::Textbox>::value_type(zId,textbox));
3199
3200
26.4k
  return true;
3201
26.4k
}
3202
3203
bool FreeHandParser::readDataZone(int zId)
3204
5.65k
{
3205
5.65k
  MWAWInputStreamPtr input = getInput();
3206
5.65k
  libmwaw::DebugStream f;
3207
5.65k
  long pos=input->tell();
3208
5.65k
  if (!input->checkPosition(pos+10)) return false;
3209
5.60k
  auto dSz=long(input->readULong(4));
3210
5.60k
  auto opCode=static_cast<int>(input->readULong(2));
3211
5.60k
  auto dataSize=long(input->readULong(4));
3212
5.60k
  long endPos=pos+10+dataSize;
3213
5.60k
  if (opCode!=0x138b || dataSize<0 || !input->checkPosition(endPos)) {
3214
2.78k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
3215
2.78k
    return false;
3216
2.78k
  }
3217
2.82k
  auto type=zId ? m_state->getZoneType(zId) : FreeHandParserInternal::Z_Unknown;
3218
2.82k
  if (type==FreeHandParserInternal::Z_Note) {
3219
234
    f << "Entries(Note)[Z" << zId << "]:";
3220
234
    if (dataSize) {
3221
229
      auto sSz=static_cast<int>(input->readULong(1));
3222
229
      if (sSz+1>dataSize) {
3223
9
        MWAW_DEBUG_MSG(("FreeHandParser::readDataZone: can not read the note size\n"));
3224
9
        f << "##sSz";
3225
9
      }
3226
220
      else {
3227
220
        std::string note;
3228
2.43k
        for (int i=0; i<sSz; ++i) note+=char(input->readULong(1));
3229
220
        f << note;
3230
220
      }
3231
229
    }
3232
234
  }
3233
2.58k
  else if (type==FreeHandParserInternal::Z_PictureName) {
3234
0
    f << "Picture[name][Z" << zId << "]:";
3235
0
    if (dataSize<6) {
3236
0
      MWAW_DEBUG_MSG(("FreeHandParser::readDataZone: can not read the picture name zone\n"));
3237
0
      f << "##sSz";
3238
0
    }
3239
0
    else {
3240
0
      auto val=static_cast<int>(input->readLong(4)); // disk id?
3241
0
      if (val) f << "f0=" << std::hex << val << std::dec << ",";
3242
0
      for (int i=0; i<2; ++i) { // disk name ?, file name
3243
0
        auto sSz=static_cast<int>(input->readULong(1));
3244
0
        if (input->tell()+sSz>endPos) {
3245
0
          MWAW_DEBUG_MSG(("FreeHandParser::readDataZone: can not read some string\n"));
3246
0
          f << "##sSz";
3247
0
          break;
3248
0
        }
3249
0
        std::string name;
3250
0
        for (int c=0; c<sSz; ++c) name+=char(input->readULong(1));
3251
0
        f << name << ",";
3252
0
      }
3253
0
    }
3254
0
  }
3255
2.58k
  else if (type==FreeHandParserInternal::Z_Picture) {
3256
0
    f << "Picture[data][Z" << zId << "]:";
3257
0
    if (dataSize) {
3258
0
      MWAWEntry entry;
3259
0
      entry.setBegin(input->tell());
3260
0
      entry.setLength(dataSize);
3261
0
      if (zId && m_state->m_zIdToDataMap.find(zId)==m_state->m_zIdToDataMap.end())
3262
0
        m_state->m_zIdToDataMap[zId]=entry;
3263
0
      ascii().skipZone(entry.begin(), entry.end()-1);
3264
0
    }
3265
0
  }
3266
2.58k
  else {
3267
2.58k
    MWAW_DEBUG_MSG(("FreeHandParser::readDataZone: find unknown zone\n"));
3268
2.58k
    if (zId)
3269
69
      f << "Entries(DataZone)[Z" << zId << "]:";
3270
2.51k
    else
3271
2.51k
      f << "Entries(DataZone):";
3272
2.58k
    if (dSz!=dataSize+5)
3273
161
      f << "sz?=" << dSz << ",";
3274
2.58k
  }
3275
2.82k
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
3276
2.82k
  ascii().addPos(pos);
3277
2.82k
  ascii().addNote(f.str().c_str());
3278
2.82k
  return true;
3279
5.60k
}
3280
3281
////////////////////////////////////////////////////////////
3282
//
3283
// send data
3284
//
3285
////////////////////////////////////////////////////////////
3286
bool FreeHandParser::openLayer(int zId)
3287
15.0k
{
3288
15.0k
  if (zId<0 || m_state->m_actualLayer>=0 || m_state->m_sendLayerSet.find(zId)!=m_state->m_sendLayerSet.end())
3289
11.6k
    return false;
3290
3.32k
  if (!getGraphicListener()) {
3291
0
    MWAW_DEBUG_MSG(("FreeHandParser::openLayer: can not find the listener\n"));
3292
0
    return false;
3293
0
  }
3294
3.32k
  m_state->m_sendLayerSet.insert(zId);
3295
3.32k
  librevenge::RVNGString layer;
3296
3.32k
  layer.sprintf("%d", zId);
3297
3.32k
  if (!getGraphicListener()->openLayer(layer))
3298
0
    return false;
3299
3.32k
  m_state->m_actualLayer=zId;
3300
3.32k
  return true;
3301
3.32k
}
3302
3303
void FreeHandParser::closeLayer()
3304
3.32k
{
3305
3.32k
  if (m_state->m_actualLayer<0)
3306
0
    return;
3307
3.32k
  getGraphicListener()->closeLayer();
3308
3.32k
  m_state->m_actualLayer=-1;
3309
3.32k
}
3310
3311
bool FreeHandParser::sendZone(int zId, MWAWTransformation const &transform)
3312
58.8k
{
3313
58.8k
  if (!getGraphicListener()) {
3314
0
    MWAW_DEBUG_MSG(("FreeHandParser::sendZone: can not find the listener\n"));
3315
0
    return false;
3316
0
  }
3317
58.8k
  if (m_state->m_zIdToTextboxMap.find(zId)!=m_state->m_zIdToTextboxMap.end())
3318
2.91k
    return sendTextbox(m_state->m_zIdToTextboxMap.find(zId)->second, transform);
3319
55.9k
  if (m_state->m_zIdToShapeMap.find(zId)==m_state->m_zIdToShapeMap.end()) {
3320
33.1k
    MWAW_DEBUG_MSG(("FreeHandParser::sendZone: can not find the zone %d\n", zId));
3321
33.1k
    return false;
3322
33.1k
  }
3323
22.8k
  auto const &shape=m_state->m_zIdToShapeMap.find(zId)->second;
3324
22.8k
  shape.m_isSent=true;
3325
22.8k
  if (shape.m_type==FreeHandParserInternal::Shape::Group ||
3326
17.9k
      shape.m_type==FreeHandParserInternal::Shape::JoinGroup)
3327
4.88k
    return sendGroup(shape, transform);
3328
17.9k
  if (shape.m_type==FreeHandParserInternal::Shape::Picture)
3329
4
    return sendPicture(shape, transform);
3330
17.9k
  if (shape.m_type==FreeHandParserInternal::Shape::BackgroundPicture)
3331
13
    return sendBackgroundPicture(shape, transform);
3332
17.9k
  if (shape.m_type!=FreeHandParserInternal::Shape::Unknown)
3333
17.9k
    return sendShape(shape, transform);
3334
0
  return false;
3335
17.9k
}
3336
3337
bool FreeHandParser::sendGroup(FreeHandParserInternal::Shape const &group, MWAWTransformation const &transform)
3338
4.88k
{
3339
4.88k
  MWAWGraphicListenerPtr listener=getGraphicListener();
3340
4.88k
  if (!listener) {
3341
0
    MWAW_DEBUG_MSG(("FreeHandParser::sendGroup: can not find the listener\n"));
3342
0
    return false;
3343
0
  }
3344
4.88k
  if (group.m_childs.empty()) return true;
3345
4.79k
  if (m_state->m_sendIdSet.find(group.m_id)!=m_state->m_sendIdSet.end()) {
3346
389
    MWAW_DEBUG_MSG(("FreeHandParser::sendGroup: sorry the zone %d is already sent\n", group.m_id));
3347
389
    return false;
3348
389
  }
3349
4.40k
  m_state->m_sendIdSet.insert(group.m_id);
3350
4.40k
  MWAWTransformation transf=transform*group.m_transformation;
3351
4.40k
  bool createGroup=group.m_childs.size()>1 && group.m_id!=m_state->m_mainGroupId;
3352
  // TODO check for join group
3353
4.40k
  bool newLayer=openLayer(group.m_layerId);
3354
4.40k
  if (createGroup) {
3355
475
    MWAWPosition pos(MWAWVec2f(0,0), MWAWVec2f(0,0), librevenge::RVNG_POINT);
3356
475
    pos.m_anchorTo = MWAWPosition::Page;
3357
475
    listener->openGroup(pos);
3358
475
  }
3359
4.40k
  bool checkLayer=m_state->m_actualLayer==-1;
3360
4.40k
  int actualLayerId=-1;
3361
52.1k
  for (int cId : group.m_childs) {
3362
52.1k
    if (checkLayer) {
3363
51.1k
      int newLayerId=-1;
3364
51.1k
      if (m_state->m_zIdToTextboxMap.find(cId)!=m_state->m_zIdToTextboxMap.end())
3365
2.68k
        newLayerId=m_state->m_zIdToTextboxMap.find(cId)->second.m_layerId;
3366
48.4k
      else if (m_state->m_zIdToShapeMap.find(cId)!=m_state->m_zIdToShapeMap.end())
3367
19.1k
        newLayerId=m_state->m_zIdToShapeMap.find(cId)->second.m_layerId;
3368
51.1k
      if (newLayerId!=actualLayerId) {
3369
10.6k
        if (actualLayerId>=0)
3370
2.90k
          closeLayer();
3371
10.6k
        if (openLayer(newLayerId))
3372
3.23k
          actualLayerId=newLayerId;
3373
7.37k
        else
3374
7.37k
          actualLayerId=-1;
3375
10.6k
      }
3376
51.1k
    }
3377
52.1k
    sendZone(cId, transf);
3378
52.1k
  }
3379
4.40k
  if (actualLayerId>=0) closeLayer();
3380
4.40k
  if (createGroup)
3381
475
    listener->closeGroup();
3382
4.40k
  m_state->m_sendIdSet.erase(group.m_id);
3383
4.40k
  if (newLayer) closeLayer();
3384
4.40k
  return true;
3385
4.79k
}
3386
3387
bool FreeHandParser::sendBackgroundPicture(FreeHandParserInternal::Shape const &picture, MWAWTransformation const &)
3388
13
{
3389
13
  MWAWGraphicListenerPtr listener=getGraphicListener();
3390
13
  if (!listener) {
3391
0
    MWAW_DEBUG_MSG(("FreeHandParser::sendBackgroundPicture: can not find the listener\n"));
3392
0
    return false;
3393
0
  }
3394
13
  if (!picture.m_picture.valid()) {
3395
11
    MWAW_DEBUG_MSG(("FreeHandParser::sendBackgroundPicture: can not find the background picture\n"));
3396
11
    return false;
3397
11
  }
3398
2
  MWAWInputStreamPtr input=getInput();
3399
2
  input->seek(picture.m_picture.begin(), librevenge::RVNG_SEEK_SET);
3400
2
  librevenge::RVNGBinaryData data;
3401
2
  if (!input->readDataBlock(picture.m_picture.length(), data) || data.empty()) {
3402
0
    MWAW_DEBUG_MSG(("FreeHandParser::sendBackgroundPicture: oops the picture is empty\n"));
3403
0
    return false;
3404
0
  }
3405
#ifdef DEBUG_WITH_FILES
3406
  static int volatile pictName = 0;
3407
  libmwaw::DebugStream f;
3408
  f << "PICT-" << ++pictName << ".pct";
3409
  libmwaw::Debug::dumpFile(data, f.str().c_str());
3410
#endif
3411
2
  MWAWPosition pos(MWAWVec2f(float(getPageSpan().getMarginLeft()), float(getPageSpan().getMarginTop())),
3412
2
                   MWAWVec2f(float(getPageSpan().getPageWidth()), float(getPageSpan().getPageLength())), librevenge::RVNG_INCH);
3413
2
  pos.m_anchorTo = MWAWPosition::Page;
3414
2
  pos.setOrder(-1);
3415
2
  MWAWEmbeddedObject pict(data);
3416
2
  listener->insertPicture(pos, pict);
3417
2
  return true;
3418
2
}
3419
3420
bool FreeHandParser::sendPicture(FreeHandParserInternal::Shape const &picture, MWAWTransformation const &transform)
3421
4
{
3422
4
  MWAWGraphicListenerPtr listener=getGraphicListener();
3423
4
  if (!listener) {
3424
0
    MWAW_DEBUG_MSG(("FreeHandParser::sendPicture: can not find the listener\n"));
3425
0
    return false;
3426
0
  }
3427
4
  if (m_state->m_zIdToDataMap.find(picture.m_dataId)==m_state->m_zIdToDataMap.end() ||
3428
4
      !m_state->m_zIdToDataMap.find(picture.m_dataId)->second.valid()) {
3429
4
    MWAW_DEBUG_MSG(("FreeHandParser::sendPicture: can not find the  picture\n"));
3430
4
    return false;
3431
4
  }
3432
0
  MWAWInputStreamPtr input=getInput();
3433
0
  MWAWEntry entry=m_state->m_zIdToDataMap.find(picture.m_dataId)->second;
3434
0
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
3435
0
  librevenge::RVNGBinaryData data;
3436
0
  if (!input->readDataBlock(entry.length(), data) || data.empty()) {
3437
0
    MWAW_DEBUG_MSG(("FreeHandParser::sendPicture: oops the picture is empty\n"));
3438
0
    return false;
3439
0
  }
3440
#ifdef DEBUG_WITH_FILES
3441
  static int volatile pictName = 0;
3442
  libmwaw::DebugStream f;
3443
  f << "PICT-" << ++pictName << ".pct";
3444
  libmwaw::Debug::dumpFile(data, f.str().c_str());
3445
#endif
3446
0
  MWAWGraphicStyle style=MWAWGraphicStyle::emptyStyle();
3447
0
  MWAWTransformation finalTransformation=transform*picture.m_transformation;
3448
0
  MWAWTransformation transf;
3449
0
  float rotation=0;
3450
0
  MWAWBox2f box;
3451
0
  if (decomposeMatrix(finalTransformation,rotation,transf,picture.m_box.center())) {
3452
0
    box=transf*picture.m_box;
3453
0
    style.m_rotate=rotation;
3454
0
  }
3455
0
  else
3456
0
    box=finalTransformation*picture.m_box;
3457
0
  for (int c=0; c<2; ++c) {
3458
0
    if (box.min()[c]>box.max()[c])
3459
0
      std::swap(box.min()[c],box.max()[c]);
3460
0
  }
3461
0
  MWAWPosition pos(box[0], box.size(), librevenge::RVNG_POINT);
3462
0
  pos.m_anchorTo = MWAWPosition::Page;
3463
0
  MWAWEmbeddedObject pict(data);
3464
0
  listener->insertPicture(pos, pict, style);
3465
0
  return true;
3466
0
}
3467
3468
bool FreeHandParser::sendShape(FreeHandParserInternal::Shape const &shape, MWAWTransformation const &transform)
3469
17.9k
{
3470
17.9k
  MWAWGraphicListenerPtr listener=getGraphicListener();
3471
17.9k
  if (!listener) {
3472
0
    MWAW_DEBUG_MSG(("FreeHandParser::sendShape: can not find the listener\n"));
3473
0
    return false;
3474
0
  }
3475
17.9k
  MWAWGraphicStyle style;
3476
17.9k
  m_state->updateLineStyle(shape.m_lineId, style);
3477
17.9k
  if (shape.m_type!=FreeHandParserInternal::Shape::Line &&
3478
14.7k
      (shape.m_type!=FreeHandParserInternal::Shape::Path || shape.m_closed))
3479
12.9k
    m_state->updateFillStyle(shape.m_fillId, style);
3480
17.9k
  MWAWTransformation finalTransformation=transform*shape.m_transformation;
3481
17.9k
  MWAWGraphicShape res;
3482
17.9k
  if (shape.updateShape(res)) {
3483
17.8k
    res=res.transform(finalTransformation);
3484
17.8k
    MWAWPosition pos(res.m_bdBox[0], res.m_bdBox.size(), librevenge::RVNG_POINT);
3485
17.8k
    pos.m_anchorTo = MWAWPosition::Page;
3486
17.8k
    listener->insertShape(pos, res, style);
3487
17.8k
    return true;
3488
17.8k
  }
3489
65
  MWAW_DEBUG_MSG(("FreeHandParser::sendShape: found some unexpected shape\n"));
3490
65
  return false;
3491
17.9k
}
3492
3493
bool FreeHandParser::sendTextbox(FreeHandParserInternal::Textbox const &textbox, MWAWTransformation const &transform)
3494
2.91k
{
3495
2.91k
  textbox.m_isSent=true;
3496
2.91k
  MWAWGraphicListenerPtr listener=getGraphicListener();
3497
2.91k
  if (!listener) {
3498
0
    MWAW_DEBUG_MSG(("FreeHandParser::sendTextbox: can not find the listener\n"));
3499
0
    return false;
3500
0
  }
3501
2.91k
  MWAWGraphicStyle style(MWAWGraphicStyle::emptyStyle());
3502
2.91k
  MWAWTransformation finalTransformation=transform*textbox.m_transformation;
3503
2.91k
  MWAWTransformation transf;
3504
2.91k
  float rotation=0;
3505
2.91k
  MWAWBox2f box;
3506
2.91k
  if (decomposeMatrix(finalTransformation,rotation,transf,textbox.m_box.center())) {
3507
912
    box=transf*textbox.m_box;
3508
912
    style.m_rotate=rotation;
3509
912
  }
3510
2.00k
  else
3511
2.00k
    box=finalTransformation*textbox.m_box;
3512
8.74k
  for (int c=0; c<2; ++c) {
3513
5.83k
    if (box.min()[c]>box.max()[c])
3514
752
      std::swap(box.min()[c],box.max()[c]);
3515
5.83k
  }
3516
2.91k
  MWAWPosition pos(box[0], box.size(), librevenge::RVNG_POINT);
3517
2.91k
  pos.m_anchorTo = MWAWPosition::Page;
3518
2.91k
  std::shared_ptr<MWAWSubDocument> doc(new FreeHandParserInternal::SubDocument(*this, getInput(), textbox.m_id));
3519
2.91k
  listener->insertTextBox(pos, doc, style);
3520
2.91k
  return false;
3521
2.91k
}
3522
3523
bool FreeHandParser::sendText(int zId)
3524
2.91k
{
3525
2.91k
  MWAWGraphicListenerPtr listener=getGraphicListener();
3526
2.91k
  if (!listener) {
3527
0
    MWAW_DEBUG_MSG(("FreeHandParser::sendText: can not find the listener\n"));
3528
0
    return false;
3529
0
  }
3530
2.91k
  if (m_state->m_zIdToTextboxMap.find(zId)==m_state->m_zIdToTextboxMap.end()) {
3531
0
    MWAW_DEBUG_MSG(("FreeHandParser::sendText: can not find the text shape\n"));
3532
0
    return false;
3533
0
  }
3534
2.91k
  auto &textbox=m_state->m_zIdToTextboxMap.find(zId)->second;
3535
2.91k
  MWAWParagraph para;
3536
2.91k
  para.m_justify = textbox.m_justify;
3537
2.91k
  listener->setParagraph(para);
3538
2.91k
  if (!textbox.m_text.valid())
3539
86
    return true;
3540
2.83k
  MWAWInputStreamPtr input=getInput();
3541
2.83k
  input->seek(textbox.m_text.begin(), librevenge::RVNG_SEEK_SET);
3542
3543
2.83k
  libmwaw::DebugStream f;
3544
2.83k
  f << "Textbox[text]:";
3545
2.83k
  long endPos=textbox.m_text.end();
3546
2.83k
  int cPos=0;
3547
2.83k
  float deltaSpacing=textbox.m_spacings[0];
3548
292k
  while (!input->isEnd()) {
3549
292k
    if (input->tell()>=endPos)
3550
2.79k
      break;
3551
289k
    if (textbox.m_posToFontMap.find(cPos)!=textbox.m_posToFontMap.end()) {
3552
5.26k
      auto &font=textbox.m_posToFontMap.find(cPos)->second;
3553
5.26k
      if (font.m_nameId && m_state->m_zIdToStringMap.find(font.m_nameId)!= m_state->m_zIdToStringMap.end())
3554
474
        font.m_font.setId(getParserState()->m_fontConverter->getId(m_state->m_zIdToStringMap.find(font.m_nameId)->second));
3555
      // color
3556
5.26k
      if (font.m_colorId && m_state->m_zIdToColorMap.find(font.m_colorId) != m_state->m_zIdToColorMap.end())
3557
1.53k
        font.m_font.setColor(m_state->m_zIdToColorMap.find(font.m_colorId)->second);
3558
      // spacing
3559
5.26k
      font.m_font.setDeltaLetterSpacing(deltaSpacing, librevenge::RVNG_POINT);
3560
      // streching
3561
5.26k
      bool needStreching=false;
3562
5.26k
      if (textbox.m_scalings[1]<1||textbox.m_scalings[1]>1) {
3563
3.24k
        font.m_font.setSize(font.m_font.size()*textbox.m_scalings[1]);
3564
3.24k
        needStreching=true;
3565
3.24k
      }
3566
5.26k
      if ((needStreching || textbox.m_scalings[0]<1 || textbox.m_scalings[0]>1) && textbox.m_scalings[1]>0)
3567
3.14k
        font.m_font.setWidthStreching(textbox.m_scalings[0]/textbox.m_scalings[1]);
3568
5.26k
      listener->setFont(font.m_font);
3569
5.26k
      f << "[F]";
3570
5.26k
    }
3571
289k
    ++cPos;
3572
289k
    auto c = char(input->readULong(1));
3573
289k
    if (c==0) {
3574
113k
      MWAW_DEBUG_MSG(("FreeHandParser::sendText: find char 0\n"));
3575
113k
      f << "#[0]";
3576
113k
      continue;
3577
113k
    }
3578
176k
    f << c;
3579
176k
    switch (c) {
3580
4.04k
    case 9:
3581
4.04k
      listener->insertTab();
3582
4.04k
      break;
3583
7.28k
    case 0xd:
3584
7.28k
      listener->insertEOL();
3585
7.28k
      break;
3586
165k
    default:
3587
165k
      listener->insertCharacter(static_cast<unsigned char>(c), input, endPos);
3588
165k
      break;
3589
176k
    }
3590
176k
  }
3591
2.83k
  ascii().addPos(textbox.m_text.begin());
3592
2.83k
  ascii().addNote(f.str().c_str());
3593
3594
2.83k
  return true;
3595
2.83k
}
3596
3597
void FreeHandParser::flushExtra()
3598
0
{
3599
0
  bool first=true;
3600
0
  for (auto const &it : m_state->m_zIdToShapeMap) {
3601
0
    if (it.second.m_isSent) continue;
3602
0
    if (first) {
3603
0
      MWAW_DEBUG_MSG(("FreeHandParser::flushExtra: find some unused shape: %d\n", it.first));
3604
0
      first=false;
3605
0
    }
3606
0
    sendZone(it.first, m_state->m_transform);
3607
0
  }
3608
0
  first=true;
3609
0
  for (auto const &it : m_state->m_zIdToTextboxMap) {
3610
0
    if (it.second.m_isSent) continue;
3611
0
    if (first) {
3612
0
      MWAW_DEBUG_MSG(("FreeHandParser::flushExtra: find some unsed textbox %d\n", it.first));
3613
0
      first=false;
3614
0
    }
3615
0
    sendZone(it.first, m_state->m_transform);
3616
0
  }
3617
0
}
3618
3619
bool FreeHandParser::decomposeMatrix(MWAWTransformation const &matrix, float &rot, MWAWTransformation &transform, MWAWVec2f const &origCenter)
3620
2.91k
{
3621
  // FIXME: this assumes that there is no skewing, ...
3622
2.91k
  MWAWVec3f const &yRow=matrix[1];
3623
2.91k
  if (matrix.isIdentity() || (yRow[0]>=0 && yRow[0]<=0)) return false;
3624
912
  rot=std::atan2(yRow[0], -yRow[1]);
3625
  rot *= float(180/M_PI);
3626
912
  transform=MWAWTransformation::rotation(-rot, matrix *origCenter) * matrix;
3627
912
  return true;
3628
2.91k
}
3629
3630
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: