/src/libmwaw/src/lib/GreatWksGraph.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */ |
2 | | |
3 | | /* libmwaw |
4 | | * Version: MPL 2.0 / LGPLv2+ |
5 | | * |
6 | | * The contents of this file are subject to the Mozilla Public License Version |
7 | | * 2.0 (the "License"); you may not use this file except in compliance with |
8 | | * the License or as specified alternatively below. You may obtain a copy of |
9 | | * the License at http://www.mozilla.org/MPL/ |
10 | | * |
11 | | * Software distributed under the License is distributed on an "AS IS" basis, |
12 | | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
13 | | * for the specific language governing rights and limitations under the |
14 | | * License. |
15 | | * |
16 | | * Major Contributor(s): |
17 | | * Copyright (C) 2002 William Lachance (wrlach@gmail.com) |
18 | | * Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net) |
19 | | * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch) |
20 | | * Copyright (C) 2006, 2007 Andrew Ziem |
21 | | * Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr) |
22 | | * |
23 | | * |
24 | | * All Rights Reserved. |
25 | | * |
26 | | * For minor contributions see the git repository. |
27 | | * |
28 | | * Alternatively, the contents of this file may be used under the terms of |
29 | | * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"), |
30 | | * in which case the provisions of the LGPLv2+ are applicable |
31 | | * instead of those above. |
32 | | */ |
33 | | |
34 | | #include <cmath> |
35 | | #include <iomanip> |
36 | | #include <iostream> |
37 | | #include <limits> |
38 | | #include <map> |
39 | | #include <set> |
40 | | #include <sstream> |
41 | | |
42 | | #include <librevenge/librevenge.h> |
43 | | |
44 | | #include "MWAWFont.hxx" |
45 | | #include "MWAWGraphicEncoder.hxx" |
46 | | #include "MWAWGraphicListener.hxx" |
47 | | #include "MWAWGraphicShape.hxx" |
48 | | #include "MWAWGraphicStyle.hxx" |
49 | | #include "MWAWListener.hxx" |
50 | | #include "MWAWParser.hxx" |
51 | | #include "MWAWPictMac.hxx" |
52 | | #include "MWAWPosition.hxx" |
53 | | #include "MWAWRSRCParser.hxx" |
54 | | #include "MWAWSubDocument.hxx" |
55 | | |
56 | | #include "GreatWksDocument.hxx" |
57 | | #include "GreatWksGraph.hxx" |
58 | | |
59 | | /** Internal: the structures of a GreatWksGraph */ |
60 | | namespace GreatWksGraphInternal |
61 | | { |
62 | | //////////////////////////////////////// |
63 | | //! Internal: the graphic zone of a GreatWksGraph |
64 | | struct Frame { |
65 | | //! the frame type |
66 | | enum Type { T_BAD, T_BASIC, T_GROUP, T_PICTURE, T_TEXT, T_DBFIELD, T_UNSET }; |
67 | | //! constructor |
68 | | Frame() |
69 | 349k | : m_type(-1) |
70 | 349k | , m_styleId(-1) |
71 | 349k | , m_parent(0) |
72 | 349k | , m_order(-1) |
73 | 349k | , m_dataSize(0) |
74 | 349k | , m_box() |
75 | 349k | , m_page(-1) |
76 | 349k | , m_extra("") |
77 | 349k | , m_parsed(false) |
78 | 349k | { |
79 | 349k | } |
80 | 47.1k | Frame(Frame const &)=default; |
81 | | //! destructor |
82 | | virtual ~Frame(); |
83 | | //! return the frame type |
84 | | virtual Type getType() const |
85 | 2.17k | { |
86 | 2.17k | return T_UNSET; |
87 | 2.17k | } |
88 | | //! operator<< |
89 | | friend std::ostream &operator<<(std::ostream &o, Frame const &zone) |
90 | 0 | { |
91 | 0 | zone.print(o); |
92 | 0 | return o; |
93 | 0 | } |
94 | | //! a virtual print function |
95 | | virtual void print(std::ostream &o) const |
96 | 0 | { |
97 | 0 | switch (m_type) { |
98 | 0 | case 1: |
99 | 0 | o << "text,"; |
100 | 0 | break; |
101 | 0 | case 2: |
102 | 0 | o << "line,"; |
103 | 0 | break; |
104 | 0 | case 3: |
105 | 0 | o << "rect,"; |
106 | 0 | break; |
107 | 0 | case 4: |
108 | 0 | o << "roundrect,"; |
109 | 0 | break; |
110 | 0 | case 5: |
111 | 0 | o << "oval,"; |
112 | 0 | break; |
113 | 0 | case 6: |
114 | 0 | o << "arc,"; |
115 | 0 | break; |
116 | 0 | case 7: |
117 | 0 | o << "poly[regular],"; |
118 | 0 | break; |
119 | 0 | case 8: |
120 | 0 | o << "poly,"; |
121 | 0 | break; |
122 | 0 | case 10: |
123 | 0 | o << "database[field],"; |
124 | 0 | break; |
125 | 0 | case 11: |
126 | 0 | o << "picture,"; |
127 | 0 | break; |
128 | 0 | case 12: |
129 | 0 | o << "spline,"; |
130 | 0 | break; |
131 | 0 | case 15: |
132 | 0 | o << "group,"; |
133 | 0 | break; |
134 | 0 | default: |
135 | 0 | o << "type=" << m_type << ","; |
136 | 0 | break; |
137 | 0 | } |
138 | 0 | if (m_styleId >= 0) |
139 | 0 | o << "S" << m_styleId << ","; |
140 | 0 | if (m_order >= 0) |
141 | 0 | o << "order=" << m_order << ","; |
142 | 0 | if (m_parent > 0) |
143 | 0 | o << "F" << m_parent << "[parent],"; |
144 | 0 | if (m_dataSize > 0) |
145 | 0 | o << "dataSize=" << m_dataSize << ","; |
146 | 0 | o << "box=" << m_box << ","; |
147 | 0 | if (m_page>0) |
148 | 0 | o << "page=" << m_page << ","; |
149 | 0 | o << m_extra; |
150 | 0 | } |
151 | | //! the zone type |
152 | | int m_type; |
153 | | //! the style identifier |
154 | | int m_styleId; |
155 | | //! the parent identifier |
156 | | int m_parent; |
157 | | //! the z order |
158 | | int m_order; |
159 | | //! the data size ( if know) |
160 | | long m_dataSize; |
161 | | //! the zone bdbox |
162 | | MWAWBox2f m_box; |
163 | | //! the page |
164 | | int m_page; |
165 | | //! extra data |
166 | | std::string m_extra; |
167 | | //! true if the frame is send |
168 | | mutable bool m_parsed; |
169 | | }; |
170 | | |
171 | | Frame::~Frame() |
172 | 396k | { |
173 | 396k | } |
174 | | |
175 | | //////////////////////////////////////// |
176 | | //! Internal: a unknown zone of a GreatWksGraph |
177 | | struct FrameBad final : public Frame { |
178 | | //! constructor |
179 | 151k | FrameBad() : Frame() |
180 | 151k | { |
181 | 151k | } |
182 | | //! destructor |
183 | | ~FrameBad() final; |
184 | | //! return the frame type |
185 | | Type getType() const final |
186 | 1.54k | { |
187 | 1.54k | return T_BAD; |
188 | 1.54k | } |
189 | | }; |
190 | | |
191 | | FrameBad::~FrameBad() |
192 | | { |
193 | | } |
194 | | |
195 | | //////////////////////////////////////// |
196 | | //! Internal: the basic shape of a GreatWksGraph |
197 | | struct FrameShape final : public Frame { |
198 | | //! constructor |
199 | | explicit FrameShape(Frame const &frame) |
200 | 13.9k | : Frame(frame) |
201 | 13.9k | , m_shape() |
202 | 13.9k | , m_lineArrow(0) |
203 | 13.9k | , m_lineFormat(0) |
204 | 13.9k | { |
205 | 13.9k | } |
206 | | //! destructor |
207 | | ~FrameShape() final; |
208 | | //! return the frame type |
209 | | Type getType() const final |
210 | 18.3k | { |
211 | 18.3k | return T_BASIC; |
212 | 18.3k | } |
213 | | //! print function |
214 | | void print(std::ostream &o) const final |
215 | 0 | { |
216 | 0 | Frame::print(o); |
217 | 0 | switch (m_lineArrow) { |
218 | 0 | case 0: // unset |
219 | 0 | case 1: // none |
220 | 0 | break; |
221 | 0 | case 2: |
222 | 0 | o << "arrow=\'>\',"; |
223 | 0 | break; |
224 | 0 | case 3: |
225 | 0 | o << "arrow=\'<\',"; |
226 | 0 | break; |
227 | 0 | case 4: |
228 | 0 | o << "arrow=\'<>\',"; |
229 | 0 | break; |
230 | 0 | default: |
231 | 0 | o<< "#arrow=" << m_lineArrow << ","; |
232 | 0 | } |
233 | 0 | if (m_lineFormat) |
234 | 0 | o << "L" << m_lineFormat << ","; |
235 | 0 | } |
236 | | //! update the style |
237 | | void updateStyle(MWAWGraphicStyle &style) const |
238 | 8.08k | { |
239 | 8.08k | if (m_shape.m_type!=MWAWGraphicShape::Line) { |
240 | 4.85k | style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow(); |
241 | 4.85k | style.m_lineDashWidth.resize(0); |
242 | 4.85k | } |
243 | 3.23k | else if (m_lineArrow > 1) { |
244 | 866 | switch (m_lineArrow) { |
245 | 734 | case 2: |
246 | 734 | style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain(); |
247 | 734 | break; |
248 | 60 | case 3: |
249 | 60 | style.m_arrows[0]=MWAWGraphicStyle::Arrow::plain(); |
250 | 60 | break; |
251 | 3 | case 4: |
252 | 3 | style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain(); |
253 | 3 | break; |
254 | 69 | default: |
255 | 69 | break; |
256 | 866 | } |
257 | 866 | } |
258 | 8.08k | } |
259 | | //! the shape |
260 | | MWAWGraphicShape m_shape; |
261 | | //! the line arrow style (in v1) |
262 | | int m_lineArrow; |
263 | | //! the line format? |
264 | | int m_lineFormat; |
265 | | private: |
266 | | FrameShape(FrameShape const &) = delete; |
267 | | FrameShape &operator=(FrameShape const &) = delete; |
268 | | }; |
269 | | |
270 | | FrameShape::~FrameShape() |
271 | 13.9k | { |
272 | 13.9k | } |
273 | | |
274 | | //////////////////////////////////////// |
275 | | //! Internal: the group zone of a GreatWksGraph |
276 | | struct FrameGroup final : public Frame { |
277 | | //! constructor |
278 | | explicit FrameGroup(Frame const &frame) |
279 | 203 | : Frame(frame) |
280 | 203 | , m_numChild(0) |
281 | 203 | , m_childList() |
282 | 203 | { |
283 | 203 | } |
284 | | //! destructor |
285 | | ~FrameGroup() final; |
286 | | //! return the frame type |
287 | | Type getType() const final |
288 | 262 | { |
289 | 262 | return T_GROUP; |
290 | 262 | } |
291 | | //! print funtion |
292 | | void print(std::ostream &o) const final |
293 | 0 | { |
294 | 0 | Frame::print(o); |
295 | 0 | if (m_numChild) |
296 | 0 | o << "nChild=" << m_numChild << ","; |
297 | 0 | } |
298 | | //! the number of child |
299 | | int m_numChild; |
300 | | //! the list of child |
301 | | std::vector<int> m_childList; |
302 | | }; |
303 | | |
304 | | FrameGroup::~FrameGroup() |
305 | 203 | { |
306 | 203 | } |
307 | | |
308 | | //////////////////////////////////////// |
309 | | //! Internal: the picture zone of a GreatWksGraph |
310 | | struct FramePicture final : public Frame { |
311 | | //! constructor |
312 | | explicit FramePicture(Frame const &frame) |
313 | 121 | : Frame(frame) |
314 | 121 | , m_entry() |
315 | 121 | { |
316 | 121 | } |
317 | | //! destructor |
318 | | ~FramePicture() final; |
319 | | //! return the frame type |
320 | | Type getType() const final |
321 | 159 | { |
322 | 159 | return T_PICTURE; |
323 | 159 | } |
324 | | //! print funtion |
325 | | void print(std::ostream &o) const final |
326 | 0 | { |
327 | 0 | Frame::print(o); |
328 | 0 | if (m_entry.valid()) |
329 | 0 | o << "pos=" << std::hex << m_entry.begin() << "->" << m_entry.end() << std::dec << ","; |
330 | 0 | } |
331 | | //! the picture entry |
332 | | MWAWEntry m_entry; |
333 | | }; |
334 | | |
335 | | FramePicture::~FramePicture() |
336 | 121 | { |
337 | 121 | } |
338 | | |
339 | | //////////////////////////////////////// |
340 | | //! Internal: the text zone of a GreatWksGraph |
341 | | struct FrameText final : public Frame { |
342 | | //! constructor |
343 | | explicit FrameText(Frame const &frame) |
344 | 5.82k | : Frame(frame) |
345 | 5.82k | , m_entry() |
346 | 5.82k | , m_rotate(0) |
347 | 5.82k | { |
348 | 11.6k | for (auto &flip : m_flip) flip=false; |
349 | 5.82k | } |
350 | | //! destructor |
351 | | ~FrameText() final; |
352 | | //! return the frame type |
353 | | Type getType() const final |
354 | 7.50k | { |
355 | 7.50k | return T_TEXT; |
356 | 7.50k | } |
357 | | //! print funtion |
358 | | void print(std::ostream &o) const final |
359 | 0 | { |
360 | 0 | Frame::print(o); |
361 | 0 | if (m_entry.valid()) |
362 | 0 | o << "pos=" << std::hex << m_entry.begin() << "->" << m_entry.end() << std::dec << ","; |
363 | 0 | if (m_rotate) o << "rot=" << m_rotate << ","; |
364 | 0 | if (m_flip[0]) o << "flipX=" << m_flip[0] << ","; |
365 | 0 | if (m_flip[1]) o << "flipY=" << m_flip[1] << ","; |
366 | 0 | } |
367 | | //! return the text style |
368 | | MWAWGraphicStyle getStyle(MWAWGraphicStyle const &zoneStyle) const |
369 | 1.24k | { |
370 | 1.24k | MWAWGraphicStyle res(zoneStyle); |
371 | 1.24k | res.m_lineWidth=0; // no border |
372 | 1.24k | res.m_flip[0]=m_flip[0]; |
373 | 1.24k | res.m_flip[1]=m_flip[1]; |
374 | 1.24k | res.m_rotate = float(m_rotate); |
375 | 1.24k | return res; |
376 | 1.24k | } |
377 | | /** return true if the has some transforms. |
378 | | |
379 | | \note as we have no way to retrieve mirror, we consider only rotation here*/ |
380 | | bool hasTransform() const |
381 | 1.48k | { |
382 | 1.48k | return (m_flip[0]&m_flip[1]) || m_rotate; |
383 | 1.48k | } |
384 | | //! the text entry |
385 | | MWAWEntry m_entry; |
386 | | //! two bool to know if we must flip x or y |
387 | | bool m_flip[2]; |
388 | | //! the rotate angle |
389 | | int m_rotate; |
390 | | }; |
391 | | |
392 | | FrameText::~FrameText() |
393 | 5.82k | { |
394 | 5.82k | } |
395 | | |
396 | | //////////////////////////////////////// |
397 | | //! Internal: the DBField zone of a GreatWksGraph |
398 | | struct FrameDBField final : public Frame { |
399 | | //! constructor |
400 | | explicit FrameDBField(Frame const &frame) |
401 | 1.22k | : Frame(frame) |
402 | 1.22k | { |
403 | 1.22k | } |
404 | | //! destructor |
405 | | ~FrameDBField() final; |
406 | | //! return the frame type |
407 | | Type getType() const final |
408 | 589 | { |
409 | 589 | return T_DBFIELD; |
410 | 589 | } |
411 | | //! print funtion |
412 | | void print(std::ostream &o) const final |
413 | 0 | { |
414 | 0 | Frame::print(o); |
415 | 0 | } |
416 | | }; |
417 | | |
418 | | FrameDBField::~FrameDBField() |
419 | | { |
420 | | } |
421 | | |
422 | | //////////////////////////////////////// |
423 | | //! Internal: a list of graphic corresponding to a page |
424 | | struct Zone { |
425 | | //! constructor |
426 | | Zone() |
427 | 10.3k | : m_page(-1) |
428 | 10.3k | , m_frameList() |
429 | 10.3k | , m_rootList() |
430 | 10.3k | , m_styleList() |
431 | 10.3k | , m_parsed(false) |
432 | 10.3k | { |
433 | 10.3k | } |
434 | | //! the page number (if known) |
435 | | int m_page; |
436 | | //! the list of frame |
437 | | std::vector<std::shared_ptr<Frame> > m_frameList; |
438 | | //! the list of root id |
439 | | std::vector<int> m_rootList; |
440 | | //! the list of style |
441 | | std::vector<MWAWGraphicStyle> m_styleList; |
442 | | //! true if we have send the data |
443 | | mutable bool m_parsed; |
444 | | }; |
445 | | |
446 | | //////////////////////////////////////// |
447 | | //! Internal: the state of a GreatWksGraph |
448 | | struct State { |
449 | | //! constructor |
450 | | State() |
451 | 99.3k | : m_zoneList() |
452 | 99.3k | , m_numPages(0) { } |
453 | | //! the list of zone ( one by page) |
454 | | std::vector<Zone> m_zoneList; |
455 | | int m_numPages /* the number of pages */; |
456 | | }; |
457 | | |
458 | | |
459 | | //////////////////////////////////////// |
460 | | //! Internal: the subdocument of a GreatWksGraph |
461 | | class SubDocument final : public MWAWSubDocument |
462 | | { |
463 | | public: |
464 | | //! constructor |
465 | | SubDocument(GreatWksGraph &pars, MWAWInputStreamPtr const &input, MWAWEntry const &entry) |
466 | 2.25k | : MWAWSubDocument(pars.m_mainParser, input, MWAWEntry(entry)) |
467 | 2.25k | , m_graphParser(&pars) {} |
468 | | |
469 | | |
470 | | //! destructor |
471 | 0 | ~SubDocument() final {} |
472 | | |
473 | | //! operator!= |
474 | | bool operator!=(MWAWSubDocument const &doc) const final; |
475 | | |
476 | | //! the parser function |
477 | | void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType) final; |
478 | | |
479 | | protected: |
480 | | /** the graph parser */ |
481 | | GreatWksGraph *m_graphParser; |
482 | | |
483 | | private: |
484 | | SubDocument(SubDocument const &orig) = delete; |
485 | | SubDocument &operator=(SubDocument const &orig) = delete; |
486 | | }; |
487 | | |
488 | | void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType) |
489 | 2.25k | { |
490 | 2.25k | if (!listener || !listener->canWriteText()) { |
491 | 0 | MWAW_DEBUG_MSG(("GreatWksGraphInternal::SubDocument::parse: no listener\n")); |
492 | 0 | return; |
493 | 0 | } |
494 | 2.25k | if (!m_graphParser) { |
495 | 0 | MWAW_DEBUG_MSG(("GreatWksGraphInternal::SubDocument::parse: no parser\n")); |
496 | 0 | return; |
497 | 0 | } |
498 | 2.25k | long pos = m_input->tell(); |
499 | 2.25k | m_graphParser->sendTextbox(m_zone,listener); |
500 | 2.25k | m_input->seek(pos, librevenge::RVNG_SEEK_SET); |
501 | 2.25k | } |
502 | | |
503 | | bool SubDocument::operator!=(MWAWSubDocument const &doc) const |
504 | 0 | { |
505 | 0 | if (MWAWSubDocument::operator!=(doc)) return true; |
506 | 0 | auto const *sDoc = dynamic_cast<SubDocument const *>(&doc); |
507 | 0 | if (!sDoc) return true; |
508 | 0 | if (m_graphParser != sDoc->m_graphParser) return true; |
509 | 0 | return false; |
510 | 0 | } |
511 | | } |
512 | | |
513 | | //////////////////////////////////////////////////////////// |
514 | | // constructor/destructor, ... |
515 | | //////////////////////////////////////////////////////////// |
516 | | GreatWksGraph::GreatWksGraph(GreatWksDocument &document) |
517 | 99.3k | : m_document(document) |
518 | 99.3k | , m_parserState(document.m_parserState) |
519 | 99.3k | , m_state(new GreatWksGraphInternal::State) |
520 | 99.3k | , m_mainParser(&document.getMainParser()) |
521 | 99.3k | { |
522 | 99.3k | } |
523 | | |
524 | | GreatWksGraph::~GreatWksGraph() |
525 | 99.3k | { } |
526 | | |
527 | | int GreatWksGraph::version() const |
528 | 14.4M | { |
529 | 14.4M | return m_parserState->m_version; |
530 | 14.4M | } |
531 | | |
532 | | |
533 | | int GreatWksGraph::numPages() const |
534 | 14.1k | { |
535 | 14.1k | if (m_state->m_numPages) |
536 | 0 | return m_state->m_numPages; |
537 | 14.1k | int nPages = 0; |
538 | 14.1k | for (auto const &zone : m_state->m_zoneList) { |
539 | 7.74k | if (zone.m_page>nPages) |
540 | 944 | nPages=zone.m_page>nPages; |
541 | 7.74k | } |
542 | | |
543 | 14.1k | m_state->m_numPages = nPages; |
544 | 14.1k | return nPages; |
545 | 14.1k | } |
546 | | |
547 | | bool GreatWksGraph::sendTextbox(MWAWEntry const &entry, MWAWListenerPtr listener) |
548 | 2.25k | { |
549 | 2.25k | return m_document.sendTextbox(entry, listener); |
550 | 2.25k | } |
551 | | |
552 | | //////////////////////////////////////////////////////////// |
553 | | // |
554 | | // Intermediate level |
555 | | // |
556 | | //////////////////////////////////////////////////////////// |
557 | | |
558 | | //////////////////////////////////////////////////////////// |
559 | | // read the patterns list |
560 | | //////////////////////////////////////////////////////////// |
561 | | bool GreatWksGraph::readPatterns(MWAWEntry const &entry) |
562 | 760 | { |
563 | 760 | if (!entry.valid() || (entry.length()%8) != 2) { |
564 | 330 | MWAW_DEBUG_MSG(("GreatWksGraph::readPatterns: the entry is bad\n")); |
565 | 330 | return false; |
566 | 330 | } |
567 | | |
568 | 430 | long pos = entry.begin(); |
569 | 430 | MWAWInputStreamPtr input = m_parserState->m_rsrcParser->getInput(); |
570 | 430 | libmwaw::DebugFile &ascFile = m_parserState->m_rsrcParser->ascii(); |
571 | 430 | libmwaw::DebugStream f; |
572 | 430 | entry.setParsed(true); |
573 | | |
574 | 430 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
575 | 430 | f << "Entries(Pattern):"; |
576 | 430 | auto N=static_cast<int>(input->readLong(2)); |
577 | 430 | f << "N=" << N << ","; |
578 | 430 | if (2+8*N!=int(entry.length())) { |
579 | 85 | f << "###"; |
580 | 85 | MWAW_DEBUG_MSG(("GreatWksGraph::readPatterns: the number of entries seems bad\n")); |
581 | 85 | ascFile.addPos(pos-4); |
582 | 85 | ascFile.addNote(f.str().c_str()); |
583 | 85 | return true; |
584 | 85 | } |
585 | 345 | ascFile.addPos(pos-4); |
586 | 345 | ascFile.addNote(f.str().c_str()); |
587 | 33.4k | for (int i=0; i < N; ++i) { |
588 | 33.1k | pos = input->tell(); |
589 | 33.1k | f.str(""); |
590 | 33.1k | f << "Pattern-" << i << ":"; |
591 | 33.1k | MWAWGraphicStyle::Pattern pat; |
592 | 33.1k | pat.m_dim=MWAWVec2i(8,8); |
593 | 33.1k | pat.m_data.resize(8); |
594 | 298k | for (size_t j=0; j < 8; ++j) |
595 | 264k | pat.m_data[j]=static_cast<unsigned char>(input->readLong(1)); |
596 | 33.1k | f << pat; |
597 | 33.1k | input->seek(pos+8, librevenge::RVNG_SEEK_SET); |
598 | 33.1k | ascFile.addPos(pos); |
599 | 33.1k | ascFile.addNote(f.str().c_str()); |
600 | 33.1k | } |
601 | 345 | return true; |
602 | 430 | } |
603 | | |
604 | | bool GreatWksGraph::readPalettes(MWAWEntry const &entry) |
605 | 483 | { |
606 | 483 | if (!entry.valid() || entry.length() != 0x664) { |
607 | 254 | MWAW_DEBUG_MSG(("GreatWksGraph::readPalettes: the entry is bad\n")); |
608 | 254 | return false; |
609 | 254 | } |
610 | | |
611 | 229 | long pos = entry.begin(); |
612 | 229 | MWAWInputStreamPtr input = m_parserState->m_rsrcParser->getInput(); |
613 | 229 | libmwaw::DebugFile &ascFile = m_parserState->m_rsrcParser->ascii(); |
614 | 229 | libmwaw::DebugStream f; |
615 | 229 | entry.setParsed(true); |
616 | | |
617 | 229 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
618 | 229 | f << "Entries(Palette):"; |
619 | 229 | auto val=static_cast<int>(input->readLong(2)); |
620 | 229 | if (val!=2) |
621 | 0 | f << "#f0=" << val << ","; |
622 | 229 | val=static_cast<int>(input->readLong(2)); |
623 | 229 | if (val!=8) |
624 | 0 | f << "#f1=" << val << ","; |
625 | 229 | ascFile.addPos(pos-4); |
626 | 229 | ascFile.addNote(f.str().c_str()); |
627 | | |
628 | | // 16 sets like: ffff, 6464, 0202 : maybe some color |
629 | 3.89k | for (int i=0; i < 16; ++i) { |
630 | 3.66k | pos = input->tell(); |
631 | 3.66k | f.str(""); |
632 | 3.66k | f << "Palette-" << i << ":"; |
633 | 14.6k | for (int j=0; j < 3; ++j) |
634 | 10.9k | f << std::hex << input->readULong(2) << std::dec << ","; |
635 | 3.66k | input->seek(pos+6, librevenge::RVNG_SEEK_SET); |
636 | 3.66k | ascFile.addPos(pos); |
637 | 3.66k | ascFile.addNote(f.str().c_str()); |
638 | 3.66k | } |
639 | | |
640 | 58.8k | for (int i=0; i < 256; ++i) { |
641 | 58.6k | pos = input->tell(); |
642 | 58.6k | f.str(""); |
643 | 58.6k | if (i==0) f << "Entries(Colors)-0:"; |
644 | 58.3k | else f << "Colors-" << i << ":"; |
645 | 58.6k | unsigned char col[3]; |
646 | 175k | for (auto &c : col) c=static_cast<unsigned char>(input->readULong(2)>>8); |
647 | 58.6k | f << MWAWColor(col[0], col[1], col[2]) << ","; |
648 | 58.6k | input->seek(pos+6, librevenge::RVNG_SEEK_SET); |
649 | 58.6k | ascFile.addPos(pos); |
650 | 58.6k | ascFile.addNote(f.str().c_str()); |
651 | 58.6k | } |
652 | | |
653 | 229 | return true; |
654 | 483 | } |
655 | | |
656 | | //////////////////////////////////////////////////////////// |
657 | | // graphic zone ( main header ) |
658 | | //////////////////////////////////////////////////////////// |
659 | | bool GreatWksGraph::isGraphicZone() |
660 | 1.05M | { |
661 | 1.05M | int const vers=version(); |
662 | 1.05M | bool isDraw=m_parserState->m_kind==MWAWDocument::MWAW_K_DRAW; |
663 | 1.05M | if (vers == 1 && !isDraw) |
664 | 0 | return false; |
665 | 1.05M | int headerSize; |
666 | 1.05M | if (vers==1) |
667 | 648k | headerSize= 0x1c+0x38+0x1e +0x1a; |
668 | 408k | else |
669 | 408k | headerSize= 0x1c+0xaa+0x30; |
670 | 1.05M | MWAWInputStreamPtr input = m_parserState->m_input; |
671 | 1.05M | long pos = input->tell(); |
672 | 1.05M | if (!input->checkPosition(pos+headerSize)) |
673 | 4.63k | return false; |
674 | | |
675 | 1.05M | int dim[4]; |
676 | 1.34M | for (int st=0; st<2; ++st) { |
677 | 5.04M | for (auto &d : dim) d=static_cast<int>(input->readLong(2)); |
678 | 1.26M | if (dim[0]>=dim[2] || dim[1]>=dim[3] || dim[2]<=0 || dim[3]<=0) { |
679 | 969k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
680 | 969k | return false; |
681 | 969k | } |
682 | 1.26M | } |
683 | | |
684 | 83.0k | input->seek(pos+headerSize, librevenge::RVNG_SEEK_SET); |
685 | 83.0k | int pageHeaderSize=vers==1 ? 16 : isDraw ? 12 : 22; |
686 | 83.0k | if (!input->checkPosition(pos+headerSize+pageHeaderSize)) { |
687 | 99 | bool ok=input->isEnd(); |
688 | 99 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
689 | 99 | return ok; |
690 | 99 | } |
691 | 82.9k | bool ok=isPageFrames(); |
692 | 82.9k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
693 | 82.9k | return ok; |
694 | 83.0k | } |
695 | | |
696 | | bool GreatWksGraph::readGraphicZone() |
697 | 26.6k | { |
698 | 26.6k | int const vers=version(); |
699 | 26.6k | bool isDraw=m_parserState->m_kind==MWAWDocument::MWAW_K_DRAW; |
700 | 26.6k | if (vers == 1 && !isDraw) |
701 | 461 | return false; |
702 | | |
703 | 26.1k | MWAWInputStreamPtr input = m_parserState->m_input; |
704 | 26.1k | long beginPos = input->tell(); |
705 | 26.1k | if (!isGraphicZone() && !findGraphicZone()) { |
706 | 18.2k | input->seek(beginPos, librevenge::RVNG_SEEK_SET); |
707 | 18.2k | return false; |
708 | 18.2k | } |
709 | 7.97k | long pos = input->tell(); |
710 | 7.97k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
711 | 7.97k | if (pos!=beginPos) { |
712 | 2.78k | ascFile.addPos(beginPos); |
713 | 2.78k | ascFile.addNote("Entries(Unknown):"); |
714 | 2.78k | } |
715 | 7.97k | libmwaw::DebugStream f; |
716 | 7.97k | f << "Entries(GZoneHeader):"; |
717 | 23.9k | for (int st=0; st<2; ++st) { |
718 | 15.9k | int dim[4]; |
719 | 63.7k | for (auto &d : dim) d=static_cast<int>(input->readLong(2)); |
720 | 15.9k | f << "dim" << st << "=" << dim[1] << "x" << dim[0] |
721 | 15.9k | << "<->"<< dim[3] << "x" << dim[2] << ","; |
722 | 15.9k | } |
723 | 7.97k | ascFile.addDelimiter(input->tell(),'|'); |
724 | 7.97k | ascFile.addPos(pos); |
725 | 7.97k | ascFile.addNote(f.str().c_str()); |
726 | 7.97k | pos += 0x1c; |
727 | 7.97k | if (vers==1) { |
728 | 2.60k | ascFile.addPos(pos); |
729 | 2.60k | ascFile.addNote("GZoneHeader-II"); |
730 | 2.60k | pos += 0x38; |
731 | | |
732 | 2.60k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
733 | 2.60k | f.str(""); |
734 | 2.60k | f << "Entries(GLineFormat):"; |
735 | 2.60k | std::string extra; |
736 | 2.60k | if (!readLineFormat(extra)) |
737 | 0 | f << "###"; |
738 | 2.60k | else |
739 | 2.60k | f << extra; |
740 | 2.60k | ascFile.addPos(pos); |
741 | 2.60k | ascFile.addNote(f.str().c_str()); |
742 | 2.60k | pos += 0x1e; |
743 | 2.60k | } |
744 | 5.37k | else { |
745 | 5.37k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
746 | 5.37k | MWAWGraphicStyle style; |
747 | 5.37k | f.str(""); |
748 | 5.37k | f << "Entries(GStyle):"; |
749 | 5.37k | if (!readStyle(style)) |
750 | 0 | f << "###"; |
751 | 5.37k | else |
752 | 5.37k | f << style; |
753 | 5.37k | ascFile.addPos(pos); |
754 | 5.37k | ascFile.addNote(f.str().c_str()); |
755 | | |
756 | 5.37k | pos += 0xaa; |
757 | | |
758 | 5.37k | ascFile.addPos(pos); |
759 | 5.37k | ascFile.addNote("Entries(GDatC)[_]:"); |
760 | 5.37k | pos += 0x16; |
761 | 5.37k | } |
762 | 7.97k | ascFile.addPos(pos); |
763 | 7.97k | ascFile.addNote("Entries(GDatD)[_]:"); |
764 | 7.97k | pos += 0x1a; |
765 | | |
766 | 7.97k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
767 | 17.1k | while (!input->isEnd() && readPageFrames()) |
768 | 9.22k | pos=input->tell(); |
769 | 7.97k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
770 | 7.97k | return true; |
771 | 26.1k | } |
772 | | |
773 | | bool GreatWksGraph::findGraphicZone() |
774 | 21.0k | { |
775 | 21.0k | int const vers=version(); |
776 | 21.0k | bool isDraw=m_parserState->m_kind==MWAWDocument::MWAW_K_DRAW; |
777 | 21.0k | if (vers == 1 && !isDraw) |
778 | 0 | return false; |
779 | 21.0k | int headerSize; |
780 | 21.0k | if (vers==1) |
781 | 4.00k | headerSize= 0x1c+0x38+0x1e +0x1a; |
782 | 17.0k | else |
783 | 17.0k | headerSize= 0x1c+0xaa+0x30; |
784 | 21.0k | int pageHeaderSize=vers==1 ? 16 : isDraw ? 12 : 22; |
785 | | |
786 | 21.0k | MWAWInputStreamPtr input = m_parserState->m_input; |
787 | 21.0k | long pos = input->tell(); |
788 | 21.0k | input->seek(pos+headerSize+pageHeaderSize, librevenge::RVNG_SEEK_SET); |
789 | 23.6M | while (!input->isEnd()) { |
790 | 23.6M | long actPos = input->tell(); |
791 | 23.6M | unsigned long value= input->readULong(4); |
792 | 23.6M | int decal=-1; |
793 | | // if we find some tabs, we have a problem |
794 | 23.6M | if (value==0x20FFFF) |
795 | 20.0k | decal = 0; |
796 | 23.6M | else if (value==0x20FFFFFF) |
797 | 24.5k | decal = 1; |
798 | 23.6M | else if (value==0xFFFFFFFF) |
799 | 600k | decal = 2; |
800 | 23.0M | else if (value==0xFFFFFF2E) |
801 | 7.37k | decal = 3; |
802 | 23.6M | if (decal>=0) { |
803 | 652k | input->seek(actPos-decal, librevenge::RVNG_SEEK_SET); |
804 | 652k | if (input->readULong(4)==0x20FFFF && input->readULong(4)==0xFFFF2E00) |
805 | 2.70k | break; |
806 | 649k | input->seek(actPos+4, librevenge::RVNG_SEEK_SET); |
807 | 649k | continue; |
808 | 652k | } |
809 | | |
810 | | // graphic size |
811 | 23.0M | if ((value>>24)==0x36) |
812 | 425k | decal = 3; |
813 | 22.5M | else if ((value>>16)==0x36) |
814 | 303k | decal = 2; |
815 | 22.2M | else if (((value>>8)&0xFFFF)==0x36) |
816 | 280k | decal = 1; |
817 | 21.9M | else if ((value&0xFFFF)==0x36) |
818 | 275k | decal = 0; |
819 | 23.0M | if (decal==-1) |
820 | 21.7M | continue; |
821 | | |
822 | 1.28M | input->seek(actPos-decal, librevenge::RVNG_SEEK_SET); |
823 | 1.28M | auto N=static_cast<int>(input->readULong(2)); |
824 | 1.28M | if (input->readLong(2)!=0x36 || !input->checkPosition(actPos-decal+4+0x36*N)) { |
825 | 253k | input->seek(actPos+4, librevenge::RVNG_SEEK_SET); |
826 | 253k | continue; |
827 | 253k | } |
828 | 1.03M | input->seek(actPos-decal-pageHeaderSize-headerSize, librevenge::RVNG_SEEK_SET); |
829 | 1.03M | if (!isGraphicZone()) { |
830 | 1.02M | input->seek(actPos+4, librevenge::RVNG_SEEK_SET); |
831 | 1.02M | continue; |
832 | 1.02M | } |
833 | 2.78k | input->seek(actPos-decal-pageHeaderSize-headerSize, librevenge::RVNG_SEEK_SET); |
834 | 2.78k | return true; |
835 | 1.03M | } |
836 | 18.2k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
837 | 18.2k | return false; |
838 | 21.0k | } |
839 | | |
840 | | //////////////////////////////////////////////////////////// |
841 | | // graphic zone ( page frames) |
842 | | //////////////////////////////////////////////////////////// |
843 | | bool GreatWksGraph::isPageFrames() |
844 | 96.4k | { |
845 | 96.4k | int const vers=version(); |
846 | 96.4k | bool isDatabase=m_parserState->m_kind==MWAWDocument::MWAW_K_DATABASE; |
847 | 96.4k | bool hasPageUnknown=vers==2 && m_parserState->m_kind!=MWAWDocument::MWAW_K_DRAW && |
848 | 28.3k | !isDatabase; |
849 | 96.4k | int const headerSize=hasPageUnknown ? 22 : (vers==2&&!isDatabase) ? 12 : 16; |
850 | 96.4k | int const nZones= (vers==2||isDatabase) ? 3 : 4; |
851 | 96.4k | MWAWInputStreamPtr &input= m_parserState->m_input; |
852 | 96.4k | long pos=input->tell(); |
853 | 96.4k | long endPos=pos+headerSize+4*nZones; |
854 | 96.4k | if (!input->checkPosition(endPos)) |
855 | 1.19k | return false; |
856 | 95.2k | long sz=-1; |
857 | 95.2k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
858 | 95.2k | if (hasPageUnknown) { |
859 | 27.4k | input->seek(2, librevenge::RVNG_SEEK_CUR); // page or 1c for spreadsheet |
860 | 27.4k | sz=long(input->readULong(4)); |
861 | 27.4k | endPos=input->tell()+sz; |
862 | 27.4k | } |
863 | 95.2k | long zoneSz[4]= {0,0,0,0}; |
864 | 427k | for (int i=0; i<nZones; ++i) |
865 | 332k | zoneSz[i]=long(input->readULong(4)); |
866 | 95.2k | if (hasPageUnknown && |
867 | 27.4k | (6+sz<headerSize+4*nZones || zoneSz[0]+zoneSz[1]+zoneSz[2]>sz || |
868 | 15.8k | !input->checkPosition(endPos))) { |
869 | 14.2k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
870 | 14.2k | return false; |
871 | 14.2k | } |
872 | 80.9k | pos+=headerSize; |
873 | 80.9k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
874 | 80.9k | int expectedSz[]= {0x36, 0xaa, 0x2, 0}; |
875 | 80.9k | if (vers==1) { |
876 | 46.9k | expectedSz[1]=0x34; |
877 | 46.9k | expectedSz[2]=0x1e; |
878 | 46.9k | expectedSz[3]=2; |
879 | 46.9k | } |
880 | 202k | for (int i=0; i < nZones; ++i) { |
881 | 184k | pos=input->tell(); |
882 | 184k | if (pos==endPos) |
883 | 0 | return true; |
884 | 184k | auto nData=static_cast<int>(input->readLong(2)); |
885 | 184k | auto fSz=static_cast<int>(input->readLong(2)); |
886 | 184k | if (nData<0 || (nData!=0 && fSz!=expectedSz[i]) || nData*fSz+4 > zoneSz[i]) { |
887 | 37.8k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
888 | 37.8k | return false; |
889 | 37.8k | } |
890 | 146k | if (i!=nZones-1 && nData *fSz+4!=zoneSz[i]) { |
891 | 116k | MWAW_DEBUG_MSG(("GreatWksGraph::isPageFrames: find a diff of %ld for data %d\n", zoneSz[i]-nData *fSz-4, i)); |
892 | 116k | if ((2*nData+4)*fSz+4 < zoneSz[i]) { |
893 | 24.8k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
894 | 24.8k | return false; |
895 | 24.8k | } |
896 | 116k | } |
897 | 121k | input->seek(expectedSz[i]*nData, librevenge::RVNG_SEEK_CUR); |
898 | 121k | } |
899 | 18.2k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
900 | 18.2k | return true; |
901 | 80.9k | } |
902 | | |
903 | | bool GreatWksGraph::readStyle(MWAWGraphicStyle &style) |
904 | 13.0M | { |
905 | 13.0M | style=MWAWGraphicStyle(); |
906 | 13.0M | MWAWInputStreamPtr &input= m_parserState->m_input; |
907 | 13.0M | libmwaw::DebugStream f; |
908 | 13.0M | int const vers=version(); |
909 | 13.0M | int const gDataSize=vers==1 ? 0x34 : 0xaa; |
910 | | |
911 | 13.0M | long pos=input->tell(); |
912 | 13.0M | long endPos=pos+gDataSize; |
913 | 13.0M | if (!input->checkPosition(endPos)) |
914 | 12.7M | return false; |
915 | | |
916 | 276k | auto val=static_cast<int>(input->readLong(2)); |
917 | 276k | if (val) f << "used=" << val << ","; |
918 | 276k | float dim[2]; |
919 | 552k | for (auto &d : dim) d=float(input->readLong(4))/65536.f; |
920 | 276k | if (dim[0]<dim[1] || dim[0]>dim[1]) f << "lineWidth[real]=" << MWAWVec2f(dim[1],dim[0]) << ","; |
921 | 276k | style.m_lineWidth=(dim[1]+dim[0])/2.f; |
922 | 276k | if (vers==1) { |
923 | 346k | for (int i=0; i < 2; ++i) { // two flags 0|1 |
924 | 231k | val=static_cast<int>(input->readULong(1)); |
925 | 231k | if (val==0 || val==1) { |
926 | 114k | if (i==0) |
927 | 57.3k | style.m_lineOpacity=float(val); |
928 | 56.9k | else |
929 | 56.9k | style.m_surfaceOpacity=float(val); |
930 | 114k | } |
931 | 117k | else |
932 | 117k | f << "#hasPat" << i << "=" << val << ","; |
933 | 231k | } |
934 | 115k | MWAWGraphicStyle::Pattern patterns[2]; |
935 | 231k | for (auto &pattern : patterns) { |
936 | 231k | pattern.m_dim=MWAWVec2i(8,8); |
937 | 231k | pattern.m_data.resize(8); |
938 | 1.85M | for (auto &data : pattern.m_data) data=static_cast<unsigned char>(input->readULong(1)); |
939 | 231k | } |
940 | 578k | for (int i=0; i < 4; ++i) { |
941 | 462k | unsigned char col[3]; |
942 | 1.38M | for (auto &c : col) c=static_cast<unsigned char>(input->readULong(2)>>8); |
943 | 462k | patterns[i/2].m_colors[1-i%2]=MWAWColor(col[0], col[1], col[2]); |
944 | 462k | } |
945 | 115k | if (!patterns[0].getUniqueColor(style.m_lineColor)) { |
946 | 78.3k | f << "linePattern=[" << patterns[0] << "],"; |
947 | 78.3k | patterns[0].getAverageColor(style.m_lineColor); |
948 | 78.3k | } |
949 | 115k | if (!patterns[1].getUniqueColor(style.m_surfaceColor)) { |
950 | 79.3k | if (style.m_surfaceOpacity<=0) |
951 | 73.8k | f << "surfPattern=[" << patterns[1] << "],"; |
952 | 5.52k | else |
953 | 5.52k | style.setPattern(patterns[1]); |
954 | 79.3k | } |
955 | | |
956 | 115k | style.m_extra=f.str(); |
957 | 115k | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
958 | 115k | return true; |
959 | 115k | } |
960 | 160k | MWAWGraphicStyle::Pattern patterns[2]; |
961 | 802k | for (int i=0; i < 4; ++i) { |
962 | 641k | val=static_cast<int>(input->readULong(2)); |
963 | 641k | if (val) f << "col" << i << "=" << std::hex << val << std::dec << ","; |
964 | 641k | unsigned char col[3]; |
965 | 1.92M | for (auto &c : col) c=static_cast<unsigned char>(input->readULong(2)>>8); |
966 | 641k | patterns[i/2].m_colors[1-i%2]=MWAWColor(col[0], col[1], col[2]); |
967 | 641k | } |
968 | 160k | val=static_cast<int>(input->readULong(2)); |
969 | 160k | if (val) f << "col4=" << std::hex << val << std::dec << ","; |
970 | 481k | for (int i=0; i < 2; ++i) { |
971 | 320k | val=static_cast<int>(input->readULong(2)); // small number |
972 | 320k | if (i==0) |
973 | 160k | style.m_lineOpacity=val ? 1.0 : 0.0; |
974 | 160k | else |
975 | 160k | style.m_surfaceOpacity=val ? 1.0 : 0.0; |
976 | 320k | if (val>1) |
977 | 217k | f << "pat" << i << "=" << val << ","; |
978 | 320k | patterns[i].m_dim=MWAWVec2i(8,8); |
979 | 320k | patterns[i].m_data.resize(8); |
980 | 2.56M | for (auto &data : patterns[i].m_data) data=static_cast<unsigned char>(input->readULong(1)); |
981 | 320k | } |
982 | 160k | if (!patterns[0].getUniqueColor(style.m_lineColor)) { |
983 | 116k | f << "linePattern=[" << patterns[0] << "],"; |
984 | 116k | patterns[0].getAverageColor(style.m_lineColor); |
985 | 116k | } |
986 | 160k | if (!patterns[1].getUniqueColor(style.m_surfaceColor)) { |
987 | 117k | if (style.m_surfaceOpacity<=0) |
988 | 23.2k | f << "surfPattern=[" << patterns[1] << "],"; |
989 | 94.1k | else |
990 | 94.1k | style.setPattern(patterns[1]); |
991 | 117k | } |
992 | | |
993 | 160k | val=static_cast<int>(input->readULong(2)); |
994 | 160k | if (val!=1) f << "patId=" << val << ","; |
995 | | |
996 | 160k | int nDash=val==1 ? 1 : static_cast<int>(input->readULong(2)); |
997 | 160k | if (nDash<0||nDash>6) { |
998 | 90.3k | MWAW_DEBUG_MSG(("GreatWksGraph::readStyle: can not read number of line dash\n")); |
999 | 90.3k | f << "#nDash=" << nDash << ","; |
1000 | 90.3k | } |
1001 | 70.0k | else { |
1002 | 109k | for (int i=0; i < nDash; ++i) { |
1003 | 49.2k | float w=float(input->readLong(4))/65536.f; |
1004 | 49.2k | if (w<=0) { |
1005 | 10.1k | if (i==0 && nDash==1) |
1006 | 4.56k | break; |
1007 | 5.59k | MWAW_DEBUG_MSG(("GreatWksGraph::readStyle: the line dash seems bad\n")); |
1008 | 5.59k | f << "###dash" << i << ":w=" << w << ","; |
1009 | 5.59k | style.m_lineDashWidth.resize(0); |
1010 | 5.59k | break; |
1011 | 10.1k | } |
1012 | 39.0k | style.m_lineDashWidth.push_back(w); |
1013 | 39.0k | } |
1014 | 70.0k | } |
1015 | 160k | input->seek(pos+116, librevenge::RVNG_SEEK_SET); |
1016 | 160k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
1017 | 160k | ascFile.addDelimiter(pos+92,'|'); // some data? |
1018 | 160k | ascFile.addDelimiter(input->tell(),'|'); |
1019 | 160k | auto gradId=static_cast<int>(input->readLong(2)); |
1020 | 160k | if (gradId) f << "gradientId=" << gradId << ","; |
1021 | 160k | auto gradType=static_cast<int>(input->readLong(2)); |
1022 | 160k | if (gradId>=1 && gradId<=16 && (gradType>=1&&gradType<=3)) { |
1023 | 9.38k | auto &finalGrad=style.m_gradient; |
1024 | 9.38k | finalGrad.m_stopList.resize(2); |
1025 | 9.38k | finalGrad.m_stopList[0]=MWAWGraphicStyle::Gradient::Stop(0.0, MWAWColor::white()); |
1026 | 9.38k | finalGrad.m_stopList[1]=MWAWGraphicStyle::Gradient::Stop(1.0, MWAWColor::black()); |
1027 | 9.38k | finalGrad.m_type = MWAWGraphicStyle::Gradient::G_Linear; |
1028 | 9.38k | switch (gradId) { |
1029 | 3.07k | case 1: |
1030 | 3.07k | if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None; |
1031 | 3.07k | finalGrad.m_angle = -90; |
1032 | 3.07k | break; |
1033 | 388 | case 2: |
1034 | 388 | if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None; |
1035 | 388 | finalGrad.m_angle = -45; |
1036 | 388 | break; |
1037 | 538 | case 3: |
1038 | 538 | if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None; |
1039 | 538 | break; |
1040 | 1.07k | case 4: |
1041 | 1.07k | if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None; |
1042 | 1.07k | finalGrad.m_stopList[0]=MWAWGraphicStyle::Gradient::Stop(0.0, MWAWColor::black()); |
1043 | 1.07k | finalGrad.m_stopList[1]=MWAWGraphicStyle::Gradient::Stop(1.0, MWAWColor::white()); |
1044 | 1.07k | finalGrad.m_type=MWAWGraphicStyle::Gradient::G_Axial; |
1045 | 1.07k | finalGrad.m_angle = -45; |
1046 | 1.07k | break; |
1047 | 438 | case 5: |
1048 | 438 | if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None; |
1049 | 438 | finalGrad.m_angle = 90; |
1050 | 438 | break; |
1051 | 254 | case 6: |
1052 | 254 | if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None; |
1053 | 254 | finalGrad.m_stopList[0]=MWAWGraphicStyle::Gradient::Stop(0.0, MWAWColor::black()); |
1054 | 254 | finalGrad.m_stopList[1]=MWAWGraphicStyle::Gradient::Stop(1.0, MWAWColor::white()); |
1055 | 254 | finalGrad.m_type=MWAWGraphicStyle::Gradient::G_Axial; |
1056 | 254 | finalGrad.m_angle = 45; |
1057 | 254 | break; |
1058 | 602 | case 7: |
1059 | 602 | if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None; |
1060 | 602 | finalGrad.m_angle = 180; |
1061 | 602 | break; |
1062 | 393 | case 8: |
1063 | 393 | if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None; |
1064 | 393 | finalGrad.m_angle = -135; |
1065 | 393 | break; |
1066 | 707 | case 9: |
1067 | 707 | if (gradType!=3) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None; |
1068 | 707 | finalGrad.m_percentCenter=MWAWVec2f(.5f,.5f); |
1069 | 707 | finalGrad.m_stopList[0]=MWAWGraphicStyle::Gradient::Stop(0.0, MWAWColor::black()); |
1070 | 707 | finalGrad.m_stopList[1]=MWAWGraphicStyle::Gradient::Stop(1.0, MWAWColor::white()); |
1071 | 707 | finalGrad.m_type=MWAWGraphicStyle::Gradient::G_Square; |
1072 | 707 | break; |
1073 | 158 | case 10: |
1074 | 158 | if (gradType!=3) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None; |
1075 | 158 | finalGrad.m_percentCenter=MWAWVec2f(.5f,.5f); |
1076 | 158 | finalGrad.m_type=MWAWGraphicStyle::Gradient::G_Square; |
1077 | 158 | break; |
1078 | 543 | case 11: |
1079 | 761 | case 12: |
1080 | 761 | if (gradType!=2) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None; |
1081 | 761 | finalGrad.m_stopList[0]=MWAWGraphicStyle::Gradient::Stop(0.0, MWAWColor::black()); |
1082 | 761 | finalGrad.m_stopList[1]=MWAWGraphicStyle::Gradient::Stop(1.0, MWAWColor::white()); |
1083 | 761 | finalGrad.m_type=MWAWGraphicStyle::Gradient::G_Radial; |
1084 | 761 | break; |
1085 | 165 | case 13: |
1086 | 165 | if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None; |
1087 | 165 | finalGrad.m_stopList[0]=MWAWGraphicStyle::Gradient::Stop(0.0, MWAWColor(0x88,0,0)); |
1088 | 165 | finalGrad.m_stopList[1]=MWAWGraphicStyle::Gradient::Stop(1.0, MWAWColor(0xee,0,0)); |
1089 | 165 | finalGrad.m_angle = 90; |
1090 | 165 | break; |
1091 | 558 | case 14: |
1092 | 558 | if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None; |
1093 | 558 | finalGrad.m_stopList[0]=MWAWGraphicStyle::Gradient::Stop(0.0, MWAWColor(0,0x55,0)); |
1094 | 558 | finalGrad.m_stopList[1]=MWAWGraphicStyle::Gradient::Stop(1.0, MWAWColor(0,0xee,0)); |
1095 | 558 | finalGrad.m_angle = 90; |
1096 | 558 | break; |
1097 | 85 | case 15: |
1098 | 85 | if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None; |
1099 | 85 | finalGrad.m_stopList[0]=MWAWGraphicStyle::Gradient::Stop(0.0, MWAWColor(0,0,0x88)); |
1100 | 85 | finalGrad.m_stopList[1]=MWAWGraphicStyle::Gradient::Stop(1.0, MWAWColor(0,0,0xff)); |
1101 | 85 | finalGrad.m_angle = 90; |
1102 | 85 | break; |
1103 | 190 | case 16: |
1104 | 190 | if (gradType!=1) finalGrad.m_type = MWAWGraphicStyle::Gradient::G_None; |
1105 | 190 | finalGrad.m_stopList[0]=MWAWGraphicStyle::Gradient::Stop(0.0, MWAWColor(0xff,0xff,0)); |
1106 | 190 | finalGrad.m_stopList[1]=MWAWGraphicStyle::Gradient::Stop(1.0, MWAWColor(0xff,0xff,0xcc)); |
1107 | 190 | finalGrad.m_angle = 90; |
1108 | 190 | break; |
1109 | 0 | default: |
1110 | 0 | break; |
1111 | 9.38k | } |
1112 | 9.38k | if (finalGrad.m_type==MWAWGraphicStyle::Gradient::G_None) { |
1113 | 2.10k | MWAW_DEBUG_MSG(("GreatWksGraph::readStyle: find odd gradient\n")); |
1114 | 2.10k | f << "grad[##type]=" << gradType << ","; |
1115 | 2.10k | } |
1116 | 9.38k | } |
1117 | 481k | for (size_t i=0; i < 2; ++i) { |
1118 | 320k | unsigned char col[3]; |
1119 | 962k | for (auto &c : col) c=static_cast<unsigned char>(input->readULong(2)>>8); |
1120 | 320k | f << "grad[col" << i << "]=" << MWAWColor(col[0], col[1], col[2]) << ","; |
1121 | 320k | } |
1122 | 160k | input->seek(2, librevenge::RVNG_SEEK_CUR); // junk ? |
1123 | 160k | val=static_cast<int>(input->readLong(2)); |
1124 | 160k | switch (val) { |
1125 | 13.6k | case 1: // none |
1126 | 13.6k | break; |
1127 | 3.04k | case 2: |
1128 | 3.04k | style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain(); |
1129 | 3.04k | break; |
1130 | 3.62k | case 3: |
1131 | 3.62k | style.m_arrows[0]=MWAWGraphicStyle::Arrow::plain(); |
1132 | 3.62k | break; |
1133 | 1.68k | case 4: |
1134 | 1.68k | style.m_arrows[0]=style.m_arrows[1]=MWAWGraphicStyle::Arrow::plain(); |
1135 | 1.68k | break; |
1136 | 138k | default: |
1137 | 138k | f << "#lineArrows=" << val << ","; |
1138 | 160k | } |
1139 | 160k | val=static_cast<int>(input->readLong(2)); |
1140 | 160k | if (val!=1) |
1141 | 146k | f << "#lineArrow[unset],"; |
1142 | 160k | style.m_extra=f.str(); |
1143 | | |
1144 | 160k | pos = input->tell(); |
1145 | 160k | std::string extra(""); |
1146 | 160k | f.str(""); |
1147 | 160k | f << "Entries(GLineFormat):"; |
1148 | 160k | if (readLineFormat(extra)) |
1149 | 160k | f << extra; |
1150 | 0 | else |
1151 | 0 | f << "###"; |
1152 | 160k | ascFile.addPos(pos); |
1153 | 160k | ascFile.addNote(f.str().c_str()); |
1154 | 160k | ascFile.addDelimiter(input->tell(),'|'); |
1155 | 160k | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
1156 | 160k | return true; |
1157 | 160k | } |
1158 | | |
1159 | | bool GreatWksGraph::readLineFormat(std::string &extra) |
1160 | 6.94M | { |
1161 | 6.94M | MWAWInputStreamPtr &input= m_parserState->m_input; |
1162 | 6.94M | libmwaw::DebugStream f; |
1163 | 6.94M | int const gDataSize=0x1e; |
1164 | 6.94M | long pos=input->tell(); |
1165 | 6.94M | if (!input->checkPosition(pos+gDataSize)) |
1166 | 6.46M | return false; |
1167 | | |
1168 | | // find: f0=1, f1=0, f2=9|c f3=3|5, f5=c|f, f0+a dim? |
1169 | 2.87M | for (int i=0; i<5; ++i) { |
1170 | 2.39M | auto val=static_cast<int>(input->readLong(2)); |
1171 | 2.39M | if (val) f << "f" << i << "=" << val << ","; |
1172 | 2.39M | } |
1173 | | |
1174 | 479k | extra=f.str(); |
1175 | | // then 3ffda4bc7d1934f709244002fcfb724c879139b4 |
1176 | 479k | m_parserState->m_asciiFile.addDelimiter(input->tell(),'|'); |
1177 | 479k | input->seek(pos+gDataSize, librevenge::RVNG_SEEK_SET); |
1178 | 479k | return true; |
1179 | 6.94M | } |
1180 | | |
1181 | | bool GreatWksGraph::readPageFrames() |
1182 | 13.4k | { |
1183 | 13.4k | MWAWInputStreamPtr &input= m_parserState->m_input; |
1184 | 13.4k | int const vers=version(); |
1185 | 13.4k | bool isDraw = m_parserState->m_kind==MWAWDocument::MWAW_K_DRAW; |
1186 | 13.4k | bool isSpreadsheet = m_parserState->m_kind==MWAWDocument::MWAW_K_SPREADSHEET; |
1187 | 13.4k | bool isDatabase = m_parserState->m_kind==MWAWDocument::MWAW_K_DATABASE; |
1188 | 13.4k | bool hasPageUnknown=vers==2 && !isDraw && !isDatabase; |
1189 | 13.4k | int const nZones=hasPageUnknown ? 4 : (vers==2&&!isDatabase) ? 3 : 4; |
1190 | 13.4k | long pos=input->tell(); |
1191 | 13.4k | if (!isPageFrames()) { |
1192 | 3.10k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
1193 | 3.10k | return false; |
1194 | 3.10k | } |
1195 | 10.3k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
1196 | 10.3k | libmwaw::DebugStream f; |
1197 | 10.3k | f << "Entries(GFrame):"; |
1198 | 10.3k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
1199 | 10.3k | long endPos=-1; |
1200 | 10.3k | GreatWksGraphInternal::Zone pageZone; |
1201 | 10.3k | if (isSpreadsheet) { |
1202 | 63 | auto val=static_cast<int>(input->readLong(2)); |
1203 | 63 | if (val != 0x1c) { |
1204 | 0 | MWAW_DEBUG_MSG(("GreatWksGraph::readPageFrames: oops unexpected key word\n")); |
1205 | 0 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
1206 | 0 | return false; |
1207 | 0 | } |
1208 | 63 | endPos=pos+6+long(input->readULong(4)); |
1209 | 63 | } |
1210 | 10.3k | else if (hasPageUnknown) { |
1211 | 3.45k | pageZone.m_page = static_cast<int>(input->readLong(2)); |
1212 | 3.45k | f << "page=" << pageZone.m_page << ","; |
1213 | 3.45k | endPos=pos+6+long(input->readULong(4)); |
1214 | 3.45k | } |
1215 | 10.3k | static char const* const wh[]= {"head", "gstyle", "root", "unknown"}; |
1216 | 10.3k | long zoneSz[4]= {0,0,0,0}; |
1217 | 48.1k | for (int i=0; i < nZones; ++i) { |
1218 | 37.7k | zoneSz[i] = long(input->readULong(4)); |
1219 | 37.7k | if (zoneSz[i]) |
1220 | 36.0k | f << wh[i] << "[sz]=" << std::hex << zoneSz[i] << std::dec << ","; |
1221 | 37.7k | } |
1222 | | |
1223 | 10.3k | int z=0; |
1224 | 10.3k | long zoneEnd=input->tell()+zoneSz[z++]; |
1225 | 10.3k | auto nFrames=static_cast<int>(input->readLong(2)); |
1226 | 10.3k | input->seek(2, librevenge::RVNG_SEEK_CUR); |
1227 | 10.3k | f << "nFrames=" << nFrames << ","; |
1228 | 10.3k | ascFile.addPos(pos); |
1229 | 10.3k | ascFile.addNote(f.str().c_str()); |
1230 | 10.3k | auto &frames=pageZone.m_frameList; |
1231 | 208k | for (int i=0; i < nFrames; ++i) { |
1232 | 198k | pos = input->tell(); |
1233 | 198k | f.str(""); |
1234 | 198k | f << "GFrame[head]-F" << i+1 << ":"; |
1235 | 198k | std::shared_ptr<GreatWksGraphInternal::Frame> zone; |
1236 | 198k | if (pos+0x36<=zoneEnd) zone=readFrameHeader(); |
1237 | 198k | if (!zone) { |
1238 | 151k | MWAW_DEBUG_MSG(("GreatWksGraph::readPageFrames: oops graphic detection is probably bad\n")); |
1239 | 151k | f << "###"; |
1240 | 151k | input->seek(pos+0x36, librevenge::RVNG_SEEK_SET); |
1241 | 151k | zone.reset(new GreatWksGraphInternal::FrameBad()); |
1242 | 151k | } |
1243 | 47.1k | else |
1244 | 47.1k | f << *zone; |
1245 | 198k | zone->m_page=pageZone.m_page; |
1246 | 198k | frames.push_back(zone); |
1247 | 198k | ascFile.addPos(pos); |
1248 | 198k | ascFile.addNote(f.str().c_str()); |
1249 | 198k | } |
1250 | 10.3k | pos=input->tell(); |
1251 | 10.3k | if (pos!=zoneEnd) { |
1252 | 8.24k | ascFile.addPos(pos); |
1253 | 8.24k | ascFile.addNote("GFrame[head]-end:###"); |
1254 | 8.24k | input->seek(zoneEnd, librevenge::RVNG_SEEK_SET); |
1255 | 8.24k | } |
1256 | | |
1257 | 10.3k | pos=input->tell(); |
1258 | 10.3k | zoneEnd=pos+zoneSz[z++]; |
1259 | 10.3k | auto nData=static_cast<int>(input->readLong(2)); |
1260 | 10.3k | input->seek(2, librevenge::RVNG_SEEK_CUR); |
1261 | 10.3k | f.str(""); |
1262 | 10.3k | f << "Entries(GStyle): N=" << nData << ","; |
1263 | 10.3k | ascFile.addPos(pos); |
1264 | 10.3k | ascFile.addNote(f.str().c_str()); |
1265 | 10.3k | int const gDataSize=vers==1 ? 0x34 : 0xaa; |
1266 | 48.6M | for (int i=0; i < nData; ++i) { |
1267 | 48.5M | pos = input->tell(); |
1268 | 48.5M | f.str(""); |
1269 | 48.5M | f << "GStyle-S" << i+1 << ":"; |
1270 | 48.5M | MWAWGraphicStyle style; |
1271 | 48.5M | if (pos+gDataSize>zoneEnd || !readStyle(style)) |
1272 | 48.3M | f << "###"; |
1273 | 270k | else |
1274 | 270k | f << style; |
1275 | 48.5M | pageZone.m_styleList.push_back(style); |
1276 | 48.5M | ascFile.addPos(pos); |
1277 | 48.5M | ascFile.addNote(f.str().c_str()); |
1278 | 48.5M | input->seek(pos+gDataSize, librevenge::RVNG_SEEK_SET); |
1279 | 48.5M | } |
1280 | 10.3k | pos=input->tell(); |
1281 | 10.3k | if (pos!=zoneEnd) { |
1282 | 8.26k | ascFile.addPos(pos); |
1283 | 8.26k | ascFile.addNote("GStyle-end:###"); |
1284 | 8.26k | input->seek(zoneEnd, librevenge::RVNG_SEEK_SET); |
1285 | 8.26k | } |
1286 | | |
1287 | 10.3k | if (vers==1) { |
1288 | 3.04k | pos=input->tell(); |
1289 | 3.04k | zoneEnd=pos+zoneSz[z++]; |
1290 | 3.04k | nData=static_cast<int>(input->readLong(2)); |
1291 | 3.04k | input->seek(2, librevenge::RVNG_SEEK_CUR); |
1292 | 3.04k | f.str(""); |
1293 | 3.04k | f << "Entries(GLineFormat): N=" << nData << ","; |
1294 | 3.04k | ascFile.addPos(pos); |
1295 | 3.04k | ascFile.addNote(f.str().c_str()); |
1296 | 3.04k | int const gLineFSize= 0x1e; |
1297 | 6.78M | for (int i=0; i < nData; ++i) { |
1298 | 6.77M | pos = input->tell(); |
1299 | 6.77M | f.str(""); |
1300 | 6.77M | f << "GLineFormat-L" << i << ","; |
1301 | 6.77M | std::string extra(""); |
1302 | 6.77M | if (!readLineFormat(extra)) |
1303 | 6.46M | f << "###"; |
1304 | 316k | else |
1305 | 316k | f << extra; |
1306 | 6.77M | ascFile.addPos(pos); |
1307 | 6.77M | ascFile.addNote(f.str().c_str()); |
1308 | 6.77M | input->seek(pos+gLineFSize, librevenge::RVNG_SEEK_SET); |
1309 | 6.77M | } |
1310 | 3.04k | pos=input->tell(); |
1311 | 3.04k | if (pos!=zoneEnd) { |
1312 | 2.24k | ascFile.addPos(pos); |
1313 | 2.24k | ascFile.addNote("GLineFormat-end:###"); |
1314 | 2.24k | input->seek(zoneEnd, librevenge::RVNG_SEEK_SET); |
1315 | 2.24k | } |
1316 | 3.04k | } |
1317 | | |
1318 | 10.3k | pos = input->tell(); |
1319 | 10.3k | zoneEnd=pos+zoneSz[z++]; |
1320 | 10.3k | auto nRoots=static_cast<int>(input->readLong(2)); |
1321 | 10.3k | input->seek(2, librevenge::RVNG_SEEK_CUR); |
1322 | 10.3k | f.str(""); |
1323 | 10.3k | f << "GFrame[roots]: N=" << nRoots << ",roots=["; |
1324 | 7.03M | for (int i=0; i < nRoots; ++i) { |
1325 | 7.02M | if (input->tell()+2>zoneEnd) { |
1326 | 3.06k | MWAW_DEBUG_MSG(("GreatWksGraph::readPageFrames: can not read some roots\n")); |
1327 | 3.06k | f << "###"; |
1328 | 3.06k | break; |
1329 | 3.06k | } |
1330 | 7.01M | auto val = static_cast<int>(input->readLong(2)); |
1331 | 7.01M | if (val==0) { |
1332 | 6.00M | f << "_,"; |
1333 | 6.00M | continue; |
1334 | 6.00M | } |
1335 | 1.01M | pageZone.m_rootList.push_back(val); |
1336 | 1.01M | f << "F" << val << ","; |
1337 | 1.01M | } |
1338 | 10.3k | f << "],"; |
1339 | 10.3k | if (input->tell()!=zoneEnd) { // ok |
1340 | 6.73k | ascFile.addDelimiter(input->tell(),'|'); |
1341 | 6.73k | input->seek(zoneEnd, librevenge::RVNG_SEEK_SET); |
1342 | 6.73k | } |
1343 | 10.3k | ascFile.addPos(pos); |
1344 | 10.3k | ascFile.addNote(f.str().c_str()); |
1345 | | |
1346 | 10.3k | if (isDraw) { |
1347 | | // in draw document, we must sequence the frames recursively ... |
1348 | | // sort rootList using m_order |
1349 | 6.54k | std::map<int, int> orderMap; |
1350 | 951k | for (auto id : pageZone.m_rootList) { |
1351 | 951k | if (id<=0 || id>nFrames) { |
1352 | 807k | MWAW_DEBUG_MSG(("GreatWksGraph::readPageFrames: can not find order for frame %d\n",id)); |
1353 | 807k | continue; |
1354 | 807k | } |
1355 | 143k | int ord=frames[size_t(id-1)]->m_order; |
1356 | 143k | if (orderMap.find(ord)!=orderMap.end()) { |
1357 | 137k | MWAW_DEBUG_MSG(("GreatWksGraph::readPageFrames: oops order %d already exist\n",ord)); |
1358 | 137k | continue; |
1359 | 137k | } |
1360 | 6.47k | orderMap[ord]=id; |
1361 | 6.47k | } |
1362 | 6.54k | pageZone.m_rootList.resize(0); |
1363 | 6.54k | for (auto const &it : orderMap) |
1364 | 6.47k | pageZone.m_rootList.push_back(it.second); |
1365 | | |
1366 | 6.54k | std::set<int> seens; |
1367 | 6.54k | bool ok=true; |
1368 | 9.14k | for (size_t c=pageZone.m_rootList.size(); c > 0;) { |
1369 | 3.34k | if (!readFrameExtraDataRec(pageZone, pageZone.m_rootList[--c]-1, seens, endPos)) { |
1370 | 748 | ok = false; |
1371 | 748 | break; |
1372 | 748 | } |
1373 | 3.34k | } |
1374 | 6.54k | m_state->m_zoneList.push_back(pageZone); |
1375 | 6.54k | if (endPos>0) |
1376 | 0 | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
1377 | 6.54k | return ok; |
1378 | 6.54k | } |
1379 | | |
1380 | | // in text document, we must go through the last frame to the first frame to retrieve data |
1381 | 3.83k | bool ok=true; |
1382 | 12.3k | for (int id=nFrames-1; id >= 0; --id) { |
1383 | 9.72k | if (id>=nFrames) { |
1384 | 0 | MWAW_DEBUG_MSG(("GreatWksGraph::readPageFrames: can not find frame with id=%d\n",id)); |
1385 | 0 | continue; |
1386 | 0 | } |
1387 | 9.72k | auto zone=frames[size_t(id)]; |
1388 | 9.72k | if (!zone) continue; |
1389 | 9.72k | pos=input->tell(); |
1390 | 9.72k | ok = readFrameExtraData(*zone, id, endPos); |
1391 | 9.72k | f.str(""); |
1392 | 9.72k | f << "GFrame-data:F" << id+1 << "[" << *zone << "]:"; |
1393 | 9.72k | if (zone->m_dataSize>0 && input->tell()!=pos+zone->m_dataSize) { |
1394 | 1.36k | if (input->tell()>pos+zone->m_dataSize || !input->checkPosition(pos+zone->m_dataSize)) { |
1395 | 268 | MWAW_DEBUG_MSG(("GreatWksGraph::readPageFrames: must stop, file position seems bad\n")); |
1396 | 268 | f << "###"; |
1397 | 268 | ascFile.addPos(pos); |
1398 | 268 | ascFile.addNote(f.str().c_str()); |
1399 | 268 | ok = false; |
1400 | 268 | break; |
1401 | 268 | } |
1402 | 1.09k | if (!ok) { |
1403 | 1.09k | f << "[##unparsed]"; |
1404 | 1.09k | ascFile.addPos(pos); |
1405 | 1.09k | ascFile.addNote(f.str().c_str()); |
1406 | 1.09k | } |
1407 | 1.09k | input->seek(pos+zone->m_dataSize, librevenge::RVNG_SEEK_SET); |
1408 | 1.09k | ok = true; |
1409 | 1.09k | } |
1410 | 9.45k | if (ok) |
1411 | 8.50k | continue; |
1412 | 952 | MWAW_DEBUG_MSG(("GreatWksGraph::readPageFrames: must stop parsing graphic data\n")); |
1413 | 952 | f << "###"; |
1414 | 952 | ascFile.addPos(pos); |
1415 | 952 | ascFile.addNote(f.str().c_str()); |
1416 | 952 | break; |
1417 | 9.45k | } |
1418 | | // check the roots |
1419 | 3.83k | std::set<int> seens; |
1420 | 61.7k | for (auto &id : pageZone.m_rootList) { |
1421 | 61.7k | if (!checkGraph(pageZone, id-1, seens)) |
1422 | 52.7k | id=0; // set the root has invalid |
1423 | 61.7k | } |
1424 | 3.83k | pos=input->tell(); |
1425 | 3.83k | if (endPos>0 && pos!=endPos) { |
1426 | 2.99k | MWAW_DEBUG_MSG(("GreatWksGraph::readPageFrames: find some end data\n")); |
1427 | 2.99k | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
1428 | 2.99k | ascFile.addPos(pos); |
1429 | 2.99k | ascFile.addNote("GFrame-end:###"); |
1430 | 2.99k | ok=true; |
1431 | 2.99k | } |
1432 | 3.83k | m_state->m_zoneList.push_back(pageZone); |
1433 | 3.83k | return ok; |
1434 | 10.3k | } |
1435 | | |
1436 | | bool GreatWksGraph::checkGraph(GreatWksGraphInternal::Zone &zone, int id, std::set<int> &seens) |
1437 | 61.7k | { |
1438 | 61.7k | if (seens.find(id)!=seens.end()) { |
1439 | 1.26k | MWAW_DEBUG_MSG(("GreatWksGraph::checkGraph: index %d is already read\n", id)); |
1440 | 1.26k | return false; |
1441 | 1.26k | } |
1442 | 60.4k | if (id < 0 || id >= int(zone.m_frameList.size())) { |
1443 | 51.4k | MWAW_DEBUG_MSG(("GreatWksGraph::readPageFrames: can not find zone %d\n", id)); |
1444 | 51.4k | return false; |
1445 | 51.4k | } |
1446 | 8.98k | seens.insert(id); |
1447 | 8.98k | auto frame=zone.m_frameList[size_t(id)]; |
1448 | 8.98k | if (!frame) return true; |
1449 | 8.98k | if (frame->getType()!=GreatWksGraphInternal::Frame::T_GROUP) |
1450 | 8.93k | return true; |
1451 | 48 | auto &group=static_cast<GreatWksGraphInternal::FrameGroup &>(*frame); |
1452 | 48 | for (size_t c=0; c < group.m_childList.size(); ++c) { |
1453 | 8 | if (!checkGraph(zone, group.m_childList[c]-1, seens)) { |
1454 | 8 | group.m_childList.resize(c); |
1455 | 8 | break; |
1456 | 8 | } |
1457 | 8 | } |
1458 | 48 | return true; |
1459 | 8.98k | } |
1460 | | |
1461 | | bool GreatWksGraph::readFrameExtraDataRec(GreatWksGraphInternal::Zone &zone, int id, std::set<int> &seens, long endPos) |
1462 | 3.36k | { |
1463 | 3.36k | if (seens.find(id)!=seens.end()) { |
1464 | 1 | MWAW_DEBUG_MSG(("GreatWksGraph::readPageFrames: index %d is already read\n", id)); |
1465 | 1 | return false; |
1466 | 1 | } |
1467 | 3.36k | if (id < 0 || id >= int(zone.m_frameList.size())) { |
1468 | 20 | MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraDataRec: can not find zone %d\n", id)); |
1469 | 20 | return false; |
1470 | 20 | } |
1471 | 3.34k | seens.insert(id); |
1472 | 3.34k | auto frame=zone.m_frameList[size_t(id)]; |
1473 | 3.34k | if (!frame) return true; |
1474 | 3.34k | MWAWInputStreamPtr &input= m_parserState->m_input; |
1475 | 3.34k | long pos=input->tell(); |
1476 | 3.34k | if (!readFrameExtraData(*frame, id, endPos)) return false; |
1477 | 2.66k | if (frame->m_dataSize>0 && input->tell()!=pos+frame->m_dataSize) { |
1478 | 47 | if (input->tell()>pos+frame->m_dataSize || !input->checkPosition(pos+frame->m_dataSize)) { |
1479 | 47 | MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraDataRec: must stop, file position seems bad\n")); |
1480 | 47 | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
1481 | 47 | ascFile.addPos(pos); |
1482 | 47 | ascFile.addNote("GFrame-Data###"); |
1483 | 47 | if (endPos>0) |
1484 | 0 | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
1485 | 47 | return false; |
1486 | 47 | } |
1487 | 0 | input->seek(pos+frame->m_dataSize, librevenge::RVNG_SEEK_SET); |
1488 | 0 | } |
1489 | 2.62k | if (frame->getType()!=GreatWksGraphInternal::Frame::T_GROUP) |
1490 | 2.59k | return true; |
1491 | 26 | auto &group=static_cast<GreatWksGraphInternal::FrameGroup &>(*frame); |
1492 | 28 | for (size_t c=0; c < group.m_childList.size(); ++c) { |
1493 | 24 | if (!readFrameExtraDataRec(zone, group.m_childList[c]-1, seens, endPos)) { |
1494 | 22 | group.m_childList.resize(c); |
1495 | 22 | return false; |
1496 | 22 | } |
1497 | 24 | } |
1498 | 4 | return true; |
1499 | 26 | } |
1500 | | |
1501 | | std::shared_ptr<GreatWksGraphInternal::Frame> GreatWksGraph::readFrameHeader() |
1502 | 198k | { |
1503 | 198k | int const vers=version(); |
1504 | 198k | GreatWksGraphInternal::Frame zone; |
1505 | 198k | std::shared_ptr<GreatWksGraphInternal::Frame> res; |
1506 | 198k | MWAWInputStreamPtr &input= m_parserState->m_input; |
1507 | 198k | long pos=input->tell(); |
1508 | 198k | long endPos=pos+54; |
1509 | 198k | if (!input->checkPosition(endPos)) |
1510 | 0 | return res; |
1511 | | |
1512 | 198k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
1513 | 198k | libmwaw::DebugStream f; |
1514 | 198k | zone.m_type=static_cast<int>(input->readLong(1)); |
1515 | 198k | auto locked=static_cast<int>(input->readLong(1)); |
1516 | 198k | if (zone.m_type<0||zone.m_type>16||locked<0||locked>1) { |
1517 | 115k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
1518 | 115k | return res; |
1519 | 115k | } |
1520 | 82.9k | if (locked) f << "lock,"; |
1521 | 82.9k | float dim[4]; |
1522 | 331k | for (auto &d : dim) d=float(input->readLong(4))/65536.f; |
1523 | 82.9k | if (dim[2]<dim[0] || dim[3]<dim[1]) { |
1524 | 35.7k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
1525 | 35.7k | return res; |
1526 | 35.7k | } |
1527 | 47.1k | zone.m_box=MWAWBox2f(MWAWVec2f(dim[1],dim[0]),MWAWVec2f(dim[3],dim[2])); |
1528 | 47.1k | zone.m_styleId=static_cast<int>(input->readULong(2)); |
1529 | 47.1k | zone.m_parent=static_cast<int>(input->readULong(2)); |
1530 | 47.1k | zone.m_order=static_cast<int>(input->readULong(2)); |
1531 | 47.1k | switch (zone.m_type) { |
1532 | 5.82k | case 1: { |
1533 | 5.82k | auto textBox = std::make_shared<GreatWksGraphInternal::FrameText>(zone); |
1534 | 5.82k | res = textBox; |
1535 | 5.82k | res->m_dataSize=long(input->readULong(4)); |
1536 | 5.82k | auto val=long(input->readULong(2)); |
1537 | 5.82k | if (val&1) textBox->m_flip[0]=true; |
1538 | 5.82k | if (val&2) textBox->m_flip[1]=true; |
1539 | 5.82k | val &= 0xFFFC; |
1540 | 5.82k | if (val) f << "#flip=" << val << ","; |
1541 | 5.82k | textBox->m_rotate=static_cast<int>(input->readLong(2)); |
1542 | 5.82k | if (vers==2) // checkme odd |
1543 | 2.00k | textBox->m_rotate = -textBox->m_rotate; |
1544 | 5.82k | val=input->readLong(2); // 0 or 100 |
1545 | 5.82k | if (val) f << "f1=" << std::hex << val << std::dec << ","; |
1546 | 5.82k | break; |
1547 | 0 | } |
1548 | 121 | case 11: |
1549 | 121 | res.reset(new GreatWksGraphInternal::FramePicture(zone)); |
1550 | 121 | res->m_dataSize=long(input->readULong(4)); |
1551 | 121 | break; |
1552 | 203 | case 15: { |
1553 | 203 | auto grp = std::make_shared<GreatWksGraphInternal::FrameGroup>(zone); |
1554 | 203 | res = grp; |
1555 | 203 | grp->m_numChild=static_cast<int>(input->readULong(2)); |
1556 | 203 | break; |
1557 | 0 | } |
1558 | 4.42k | case 2: { |
1559 | 4.42k | auto graph = std::make_shared<GreatWksGraphInternal::FrameShape>(zone); |
1560 | 4.42k | res = graph; |
1561 | 4.42k | if (vers==1) { |
1562 | 1.42k | graph->m_lineArrow=static_cast<int>(input->readLong(2)); |
1563 | 1.42k | graph->m_lineFormat=static_cast<int>(input->readLong(2)); |
1564 | 1.42k | } |
1565 | 4.42k | float points[4]; |
1566 | 17.6k | for (auto &pt : points) pt=float(input->readLong(4))/65536; |
1567 | 4.42k | graph->m_shape=MWAWGraphicShape::line(MWAWVec2f(points[1],points[0]), MWAWVec2f(points[3],points[2])); |
1568 | 4.42k | break; |
1569 | 0 | } |
1570 | 1.43k | case 4: { |
1571 | 1.43k | auto graph = std::make_shared<GreatWksGraphInternal::FrameShape>(zone); |
1572 | 1.43k | res = graph; |
1573 | 1.43k | auto roundType = static_cast<int>(input->readLong(2)); |
1574 | 1.43k | auto cornerDim = float(input->readLong(2)); |
1575 | 1.43k | graph->m_shape = MWAWGraphicShape::rectangle(zone.m_box); |
1576 | 1.43k | switch (roundType) { |
1577 | 910 | case 1: // normal |
1578 | 910 | graph->m_shape.m_cornerWidth[0]=cornerDim > zone.m_box.size()[0] ? zone.m_box.size()[0]/2.f : cornerDim/2.f; |
1579 | 910 | graph->m_shape.m_cornerWidth[1]=cornerDim > zone.m_box.size()[1] ? zone.m_box.size()[1]/2.f : cornerDim/2.f; |
1580 | 910 | break; |
1581 | 10 | case 2: |
1582 | 10 | f << "cornerDim[minWidth/2],"; |
1583 | 10 | cornerDim = zone.m_box.size()[0] < zone.m_box.size()[1] ? zone.m_box.size()[0] : zone.m_box.size()[1]; |
1584 | 10 | graph->m_shape.m_cornerWidth[0]=graph->m_shape.m_cornerWidth[1]=0.5f*cornerDim; |
1585 | 10 | break; |
1586 | 511 | default: |
1587 | 511 | f << "#type[corner]=" << roundType << "[" << cornerDim << "],"; |
1588 | 511 | break; |
1589 | 1.43k | } |
1590 | 1.43k | break; |
1591 | 1.43k | } |
1592 | 1.43k | case 6: { |
1593 | 939 | auto graph = std::make_shared<GreatWksGraphInternal::FrameShape>(zone); |
1594 | 939 | res = graph; |
1595 | 939 | int fileAngle[2]; |
1596 | 1.87k | for (auto &angle : fileAngle) angle=static_cast<int>(input->readLong(2)); |
1597 | 939 | auto type=static_cast<int>(input->readLong(1)); // 0:open, 1: close |
1598 | 939 | if (type==1) f << "closed,"; |
1599 | 920 | else if (type) f << "#type=" << type << ","; |
1600 | | |
1601 | 939 | int angle[2] = { int(90-fileAngle[0]-fileAngle[1]), int(90-fileAngle[0]) }; |
1602 | 939 | if (fileAngle[1]<0) { |
1603 | 89 | angle[0]=int(90-fileAngle[0]); |
1604 | 89 | angle[1]=int(90-fileAngle[0]-fileAngle[1]); |
1605 | 89 | } |
1606 | 850 | else if (fileAngle[1]==360) |
1607 | 0 | angle[0]=int(90-fileAngle[0]-359); |
1608 | 939 | if (angle[1]>360) { |
1609 | 73 | int numLoop=int(angle[1]/360)-1; |
1610 | 73 | angle[0]-=numLoop*360; |
1611 | 73 | angle[1]-=numLoop*360; |
1612 | 146 | while (angle[1] > 360) { |
1613 | 73 | angle[0]-=360; |
1614 | 73 | angle[1]-=360; |
1615 | 73 | } |
1616 | 73 | } |
1617 | 939 | if (angle[0] < -360) { |
1618 | 563 | int numLoop=int(angle[0]/360)+1; |
1619 | 563 | angle[0]-=numLoop*360; |
1620 | 563 | angle[1]-=numLoop*360; |
1621 | 1.12k | while (angle[0] < -360) { |
1622 | 558 | angle[0]+=360; |
1623 | 558 | angle[1]+=360; |
1624 | 558 | } |
1625 | 563 | } |
1626 | | // we must compute the real bd box |
1627 | 939 | float minVal[2] = { 0, 0 }, maxVal[2] = { 0, 0 }; |
1628 | 939 | int limitAngle[2]; |
1629 | 2.81k | for (int i = 0; i < 2; ++i) |
1630 | 1.87k | limitAngle[i] = (angle[i] < 0) ? int(angle[i]/90)-1 : int(angle[i]/90); |
1631 | 40.0k | for (int bord = limitAngle[0]; bord <= limitAngle[1]+1; ++bord) { |
1632 | 39.0k | float ang = (bord == limitAngle[0]) ? float(angle[0]) : |
1633 | 39.0k | (bord == limitAngle[1]+1) ? float(angle[1]) : float(90 * bord); |
1634 | 39.0k | ang *= float(M_PI/180.); |
1635 | 39.0k | float const actVal[2] = { std::cos(ang), -std::sin(ang)}; |
1636 | 39.0k | if (actVal[0] < minVal[0]) minVal[0] = actVal[0]; |
1637 | 37.7k | else if (actVal[0] > maxVal[0]) maxVal[0] = actVal[0]; |
1638 | 39.0k | if (actVal[1] < minVal[1]) minVal[1] = actVal[1]; |
1639 | 37.7k | else if (actVal[1] > maxVal[1]) maxVal[1] = actVal[1]; |
1640 | 39.0k | } |
1641 | 939 | MWAWBox2f circleBox=zone.m_box; |
1642 | | // we have the shape box, we need to reconstruct the circle box |
1643 | 939 | if (maxVal[0]>minVal[0] && maxVal[1]>minVal[1]) { |
1644 | 939 | float const scaling[2]= { (zone.m_box[1][0]-zone.m_box[0][0])/(maxVal[0]-minVal[0]), |
1645 | 939 | (zone.m_box[1][1]-zone.m_box[0][1])/(maxVal[1]-minVal[1]) |
1646 | 939 | }; |
1647 | 939 | float const constant[2]= { zone.m_box[0][0]-minVal[0] *scaling[0], zone.m_box[0][1]-minVal[1] *scaling[1]}; |
1648 | 939 | circleBox=MWAWBox2f(MWAWVec2f(constant[0]-scaling[0], constant[1]-scaling[1]), |
1649 | 939 | MWAWVec2f(constant[0]+scaling[0], constant[1]+scaling[1])); |
1650 | 939 | } |
1651 | 939 | if (type==1) |
1652 | 19 | graph->m_shape = MWAWGraphicShape::pie(zone.m_box, circleBox, MWAWVec2f(float(angle[0]), float(angle[1]))); |
1653 | 920 | else |
1654 | 920 | graph->m_shape = MWAWGraphicShape::arc(zone.m_box, circleBox, MWAWVec2f(float(angle[0]), float(angle[1]))); |
1655 | 939 | break; |
1656 | 1.43k | } |
1657 | 1.83k | case 3: // rect: no data |
1658 | 4.05k | case 5: { // oval no data |
1659 | 4.05k | auto graph = std::make_shared<GreatWksGraphInternal::FrameShape>(zone); |
1660 | 4.05k | MWAWGraphicShape &shape = graph->m_shape; |
1661 | 4.05k | res = graph; |
1662 | 4.05k | shape.m_bdBox = shape.m_formBox = zone.m_box; |
1663 | 4.05k | shape.m_type = zone.m_type==3 ? MWAWGraphicShape::Rectangle : MWAWGraphicShape::Circle; |
1664 | 4.05k | break; |
1665 | 1.83k | } |
1666 | 1.22k | case 10: { |
1667 | 1.22k | auto field = std::make_shared<GreatWksGraphInternal::FrameDBField>(zone); |
1668 | 1.22k | res = field; |
1669 | 1.22k | field->m_dataSize=long(input->readULong(4)); |
1670 | 1.22k | break; |
1671 | 1.83k | } |
1672 | 363 | case 7: |
1673 | 2.04k | case 8: |
1674 | 3.09k | case 12: { |
1675 | 3.09k | auto graph = std::make_shared<GreatWksGraphInternal::FrameShape>(zone); |
1676 | 3.09k | res = graph; |
1677 | 3.09k | graph->m_shape = zone.m_type==12 ? MWAWGraphicShape::path(zone.m_box) : MWAWGraphicShape::polygon(zone.m_box); |
1678 | 3.09k | graph->m_dataSize=long(input->readULong(4)); |
1679 | 3.09k | break; |
1680 | 2.04k | } |
1681 | 25.8k | default: |
1682 | 25.8k | break; |
1683 | 47.1k | } |
1684 | 47.1k | if (!res) |
1685 | 25.8k | res.reset(new GreatWksGraphInternal::Frame(zone)); |
1686 | 47.1k | res->m_extra=f.str(); |
1687 | 47.1k | ascFile.addDelimiter(input->tell(),'|'); |
1688 | 47.1k | input->seek(endPos, librevenge::RVNG_SEEK_SET); |
1689 | 47.1k | return res; |
1690 | 47.1k | } |
1691 | | |
1692 | | bool GreatWksGraph::readFrameExtraData(GreatWksGraphInternal::Frame &frame, int id, long endPos) |
1693 | 13.0k | { |
1694 | 13.0k | MWAWInputStreamPtr &input= m_parserState->m_input; |
1695 | 13.0k | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
1696 | 13.0k | libmwaw::DebugStream f; |
1697 | 13.0k | f << "GFrame[data]-F" << id+1 << ":"; |
1698 | 13.0k | long pos=input->tell(); |
1699 | 13.0k | switch (frame.m_type) { |
1700 | 410 | case 0: |
1701 | 410 | MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: find group with type=0\n")); |
1702 | 410 | return false; |
1703 | 2.84k | case 1: { |
1704 | 2.84k | if (frame.getType()!=GreatWksGraphInternal::Frame::T_TEXT) { |
1705 | 0 | MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: unexpected type for text\n")); |
1706 | 0 | return false; |
1707 | 0 | } |
1708 | 2.84k | auto &text=static_cast<GreatWksGraphInternal::FrameText &>(frame); |
1709 | 2.84k | if (!input->checkPosition(pos+text.m_dataSize)) { |
1710 | 157 | MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: text size seems bad\n")); |
1711 | 157 | return false; |
1712 | 157 | } |
1713 | 2.69k | text.m_entry.setBegin(pos); |
1714 | 2.69k | text.m_entry.setLength(text.m_dataSize); |
1715 | 2.69k | input->seek(pos+text.m_dataSize, librevenge::RVNG_SEEK_SET); |
1716 | 2.69k | ascFile.addPos(pos); |
1717 | 2.69k | ascFile.addNote(f.str().c_str()); |
1718 | 2.69k | return true; |
1719 | 2.84k | } |
1720 | 504 | case 10: |
1721 | 504 | input->seek(pos+frame.m_dataSize, librevenge::RVNG_SEEK_SET); |
1722 | 504 | ascFile.addPos(pos); |
1723 | 504 | ascFile.addNote(f.str().c_str()); |
1724 | 504 | return true; |
1725 | 2.98k | case 2: |
1726 | 4.17k | case 3: |
1727 | 4.99k | case 4: |
1728 | 5.51k | case 5: |
1729 | 5.69k | case 6: |
1730 | 5.69k | return true; |
1731 | 1.30k | case 8: // poly normal |
1732 | 1.53k | case 7: // regular poly |
1733 | 2.46k | case 12: { // spline |
1734 | 2.46k | if (frame.getType()!=GreatWksGraphInternal::Frame::T_BASIC) { |
1735 | 0 | MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: unexpected type for basic graph\n")); |
1736 | 0 | return false; |
1737 | 0 | } |
1738 | 2.46k | auto nPt=static_cast<int>(input->readLong(2)); |
1739 | 2.46k | long endData=pos+10+8*nPt; |
1740 | 2.46k | if (pos+frame.m_dataSize > endData) |
1741 | 1.79k | endData=pos+frame.m_dataSize; |
1742 | 2.46k | if (nPt<0 || (endPos>0 && endData>endPos) || |
1743 | 1.13k | (endPos<0 && !input->checkPosition(endData))) |
1744 | 1.36k | return false; |
1745 | 1.10k | float dim[4]; |
1746 | 4.40k | for (auto &d : dim) d=float(input->readLong(4))/65536.f; |
1747 | 1.10k | f << "dim=" << dim[1] << "x" << dim[0] << "<->" |
1748 | 1.10k | << dim[3] << "x" << dim[2] << ","; |
1749 | 1.10k | f << "pt=["; |
1750 | 1.10k | auto &graph=static_cast<GreatWksGraphInternal::FrameShape &>(frame); |
1751 | 1.10k | float pt[2]; |
1752 | 1.10k | std::vector<MWAWVec2f> vertices; |
1753 | 10.0k | for (int p=0; p<nPt; ++p) { |
1754 | 17.9k | for (auto &i: pt) i=float(input->readLong(4))/65536.f; |
1755 | 8.97k | vertices.push_back(MWAWVec2f(pt[1],pt[0])); |
1756 | 8.97k | f << pt[1] << "x" << pt[0] << ","; |
1757 | 8.97k | } |
1758 | 1.10k | f << "],"; |
1759 | 1.10k | if (graph.m_shape.m_type == MWAWGraphicShape::Polygon) |
1760 | 688 | graph.m_shape.m_vertices = vertices; |
1761 | 412 | else if (graph.m_shape.m_type == MWAWGraphicShape::Path) { |
1762 | 412 | if (nPt<4 || (nPt%3)!=1) { |
1763 | 184 | MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: the spline number of points seems bad\n")); |
1764 | 184 | f << "###"; |
1765 | 184 | } |
1766 | 228 | else { |
1767 | 228 | std::vector<MWAWGraphicShape::PathData> &path=graph.m_shape.m_path; |
1768 | 228 | path.push_back(MWAWGraphicShape::PathData('M', vertices[0])); |
1769 | | |
1770 | 1.69k | for (size_t p=1; p < size_t(nPt); p+=3) { |
1771 | 1.47k | bool hasFirstC=vertices[p-1]!=vertices[p]; |
1772 | 1.47k | bool hasSecondC=vertices[p+1]!=vertices[p+2]; |
1773 | 1.47k | if (!hasFirstC && !hasSecondC) |
1774 | 354 | path.push_back(MWAWGraphicShape::PathData('L', vertices[p+2])); |
1775 | 1.11k | else if (hasFirstC) |
1776 | 900 | path.push_back(MWAWGraphicShape::PathData('C', vertices[p+2], vertices[p+1], vertices[p+1])); |
1777 | 216 | else |
1778 | 216 | path.push_back(MWAWGraphicShape::PathData('S', vertices[p+2], vertices[p+1])); |
1779 | 1.47k | } |
1780 | 228 | path.push_back(MWAWGraphicShape::PathData('Z')); |
1781 | 228 | } |
1782 | 412 | } |
1783 | 0 | else { |
1784 | 0 | MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: find unexpected vertices\n")); |
1785 | 0 | f << "###"; |
1786 | 0 | } |
1787 | 1.10k | if (input->tell()!=endData) { |
1788 | 634 | ascFile.addDelimiter(input->tell(),'|'); |
1789 | 634 | input->seek(endData,librevenge::RVNG_SEEK_SET); |
1790 | 634 | } |
1791 | 1.10k | ascFile.addPos(pos); |
1792 | 1.10k | ascFile.addNote(f.str().c_str()); |
1793 | 1.10k | return true; |
1794 | 2.46k | } |
1795 | 53 | case 11: { |
1796 | 53 | if (frame.getType()!=GreatWksGraphInternal::Frame::T_PICTURE) { |
1797 | 0 | MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: unexpected type for picture\n")); |
1798 | 0 | return false; |
1799 | 0 | } |
1800 | 53 | auto &pict=static_cast<GreatWksGraphInternal::FramePicture &>(frame); |
1801 | 53 | if (!input->checkPosition(pos+pict.m_dataSize)) { |
1802 | 16 | MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: picture size seems bad\n")); |
1803 | 16 | return false; |
1804 | 16 | } |
1805 | 37 | pict.m_entry.setBegin(pos); |
1806 | 37 | pict.m_entry.setLength(pict.m_dataSize); |
1807 | 37 | input->seek(pos+pict.m_dataSize, librevenge::RVNG_SEEK_SET); |
1808 | 37 | return true; |
1809 | 53 | } |
1810 | 172 | case 15: { |
1811 | 172 | auto nGrp=static_cast<int>(input->readLong(2)); |
1812 | 172 | if (nGrp<0 || (endPos>0 && pos+4+2*nGrp>endPos) || |
1813 | 118 | (endPos<0 && !input->checkPosition(pos+4+2*nGrp))) { |
1814 | 65 | MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: unexpected number of group\n")); |
1815 | 65 | return false; |
1816 | 65 | } |
1817 | | |
1818 | 107 | if (frame.getType()!=GreatWksGraphInternal::Frame::T_GROUP) { |
1819 | 0 | MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: unexpected type for group\n")); |
1820 | 0 | input->seek(pos+4+2*nGrp, librevenge::RVNG_SEEK_SET); |
1821 | 0 | f << "###[internal]"; |
1822 | 0 | return false; |
1823 | 0 | } |
1824 | 107 | auto &group=static_cast<GreatWksGraphInternal::FrameGroup &>(frame); |
1825 | 107 | if (nGrp != group.m_numChild) { |
1826 | 83 | f << "###[N=" << group.m_numChild << "]"; |
1827 | 83 | MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: unexpected number of group child\n")); |
1828 | 83 | } |
1829 | 107 | auto val=static_cast<int>(input->readLong(2)); // always 2 |
1830 | 107 | if (val!=2) f << "f0=" << val << ","; |
1831 | 107 | f << "grpId=["; |
1832 | 3.27k | for (int j=0; j < nGrp; ++j) { |
1833 | 3.17k | val = static_cast<int>(input->readLong(2)); |
1834 | 3.17k | group.m_childList.push_back(val); |
1835 | 3.17k | f << val << ","; |
1836 | 3.17k | } |
1837 | 107 | f << "],"; |
1838 | 107 | ascFile.addPos(pos); |
1839 | 107 | ascFile.addNote(f.str().c_str()); |
1840 | 107 | return true; |
1841 | 107 | } |
1842 | 925 | default: |
1843 | 925 | break; |
1844 | 13.0k | } |
1845 | 925 | MWAW_DEBUG_MSG(("GreatWksGraph::readFrameExtraData: unexpected type\n")); |
1846 | 925 | return false; |
1847 | 13.0k | } |
1848 | | |
1849 | | //////////////////////////////////////////////////////////// |
1850 | | // textbox |
1851 | | //////////////////////////////////////////////////////////// |
1852 | | bool GreatWksGraph::sendTextbox(GreatWksGraphInternal::FrameText const &text, GreatWksGraphInternal::Zone const &zone, MWAWPosition const &pos) |
1853 | 2.25k | { |
1854 | 2.25k | MWAWListenerPtr listener=m_parserState->getMainListener(); |
1855 | 2.25k | if (!listener) { |
1856 | 0 | MWAW_DEBUG_MSG(("GreatWksGraph::sendTextbox: can not find the listener\n")); |
1857 | 0 | return true; |
1858 | 0 | } |
1859 | 2.25k | MWAWGraphicStyle style; |
1860 | 2.25k | if (text.m_styleId>=1 && text.m_styleId <= int(zone.m_styleList.size())) |
1861 | 1.94k | style = zone.m_styleList[size_t(text.m_styleId-1)]; |
1862 | 2.25k | MWAWVec2f fSz=pos.size(); |
1863 | | // increase slightly x and set y to atleast |
1864 | 2.25k | MWAWVec2f newSz(fSz[0]+3,fSz[1]); |
1865 | 2.25k | if (listener->getType()==MWAWListener::Graphic) |
1866 | 777 | return sendTextboxAsGraphic(MWAWBox2f(pos.origin(),pos.origin()+newSz), text, style, listener); |
1867 | | |
1868 | 1.48k | MWAWPosition finalPos(pos); |
1869 | 1.48k | finalPos.setSize(MWAWVec2f(newSz[0], -newSz[1])); |
1870 | 1.48k | if ((text.hasTransform() || style.hasPattern() || style.hasGradient()) && |
1871 | 485 | m_document.canSendTextboxAsGraphic(text.m_entry)) { |
1872 | 468 | MWAWBox2f box(MWAWVec2f(0,0),newSz); |
1873 | 468 | MWAWGraphicEncoder graphicEncoder; |
1874 | 468 | MWAWGraphicListenerPtr graphicListener(new MWAWGraphicListener(*m_parserState, box, &graphicEncoder)); |
1875 | 468 | graphicListener->startDocument(); |
1876 | 468 | bool ok=sendTextboxAsGraphic(box, text, style, graphicListener); |
1877 | 468 | graphicListener->endDocument(); |
1878 | 468 | MWAWEmbeddedObject picture; |
1879 | 468 | if (!graphicEncoder.getBinaryResult(picture) || !ok) |
1880 | 0 | return false; |
1881 | 468 | listener->insertPicture(finalPos, picture); |
1882 | 468 | return true; |
1883 | 468 | } |
1884 | | |
1885 | 1.01k | std::shared_ptr<MWAWSubDocument> doc(new GreatWksGraphInternal::SubDocument(*this, m_parserState->m_input, text.m_entry)); |
1886 | 1.01k | MWAWGraphicStyle frameStyle; |
1887 | 1.01k | if (style.hasSurfaceColor()) |
1888 | 24 | frameStyle.setBackgroundColor(style.m_surfaceColor); |
1889 | 1.01k | listener->insertTextBox(finalPos, doc, frameStyle); |
1890 | 1.01k | return true; |
1891 | 1.48k | } |
1892 | | |
1893 | | bool GreatWksGraph::sendTextboxAsGraphic(MWAWBox2f const &box, GreatWksGraphInternal::FrameText const &text, |
1894 | | MWAWGraphicStyle const &style, MWAWListenerPtr listener) |
1895 | 1.24k | { |
1896 | 1.24k | libmwaw::SubDocumentType subdocType; |
1897 | 1.24k | if (!listener || !listener->isDocumentStarted() || listener->isSubDocumentOpened(subdocType)) { |
1898 | 0 | MWAW_DEBUG_MSG(("GreatWksGraph::sendTextboxAsGraphic: unexpected graphic state\n")); |
1899 | 0 | return false; |
1900 | 0 | } |
1901 | 1.24k | std::shared_ptr<MWAWSubDocument> doc(new GreatWksGraphInternal::SubDocument(*this, m_parserState->m_input, text.m_entry)); |
1902 | | |
1903 | 1.24k | MWAWVec2f fSz=box.size(); |
1904 | 1.24k | MWAWBox2f textBox=MWAWBox2f(box[0],box[0]+MWAWVec2f(fSz[0], -fSz[1])); |
1905 | | /* rotation are multiple of 90, so we can use the inverse rotation to find |
1906 | | the original box */ |
1907 | 1.24k | if (text.m_rotate) |
1908 | 754 | textBox=libmwaw::rotateBoxFromCenter(box, -float(text.m_rotate)); |
1909 | 1.24k | MWAWPosition textPos(textBox[0], textBox.size(), librevenge::RVNG_POINT); |
1910 | 1.24k | textPos.m_anchorTo=MWAWPosition::Page; |
1911 | 1.24k | textPos.m_wrapping = MWAWPosition::WBackground; |
1912 | 1.24k | listener->insertTextBox(textPos, doc, text.getStyle(style)); |
1913 | 1.24k | return true; |
1914 | 1.24k | } |
1915 | | |
1916 | | //////////////////////////////////////////////////////////// |
1917 | | // picture |
1918 | | //////////////////////////////////////////////////////////// |
1919 | | bool GreatWksGraph::sendPicture(MWAWEntry const &entry, MWAWPosition const &pos) |
1920 | 77 | { |
1921 | 77 | MWAWListenerPtr listener=m_parserState->getMainListener(); |
1922 | 77 | if (!listener) { |
1923 | 0 | MWAW_DEBUG_MSG(("GreatWksGraph::sendPicture: can not find the listener\n")); |
1924 | 0 | return true; |
1925 | 0 | } |
1926 | 77 | if (!entry.valid()) { |
1927 | 57 | MWAW_DEBUG_MSG(("GreatWksGraph::sendPicture: can not find the entry\n")); |
1928 | 57 | return false; |
1929 | 57 | } |
1930 | 20 | entry.setParsed(true); |
1931 | 20 | MWAWInputStreamPtr &input= m_parserState->m_input; |
1932 | 20 | long actPos = input->tell(); |
1933 | | |
1934 | 20 | input->seek(entry.begin(), librevenge::RVNG_SEEK_SET); |
1935 | 20 | std::shared_ptr<MWAWPict> thePict(MWAWPictData::get(input, static_cast<int>(entry.length()))); |
1936 | 20 | MWAWEmbeddedObject picture; |
1937 | 20 | if (thePict && thePict->getBinary(picture)) |
1938 | 10 | listener->insertPicture(pos, picture); |
1939 | | |
1940 | | #ifdef DEBUG_WITH_FILES |
1941 | | libmwaw::DebugFile &ascFile = m_parserState->m_asciiFile; |
1942 | | ascFile.skipZone(entry.begin(), entry.end()-1); |
1943 | | librevenge::RVNGBinaryData file; |
1944 | | input->seek(entry.begin(),librevenge::RVNG_SEEK_SET); |
1945 | | input->readDataBlock(entry.length(), file); |
1946 | | |
1947 | | static int volatile pictName = 0; |
1948 | | libmwaw::DebugStream f; |
1949 | | f << "DATA-" << ++pictName << ".pct"; |
1950 | | libmwaw::Debug::dumpFile(file, f.str().c_str()); |
1951 | | #endif |
1952 | | |
1953 | 20 | input->seek(actPos, librevenge::RVNG_SEEK_SET); |
1954 | 20 | return true; |
1955 | 77 | } |
1956 | | |
1957 | | //////////////////////////////////////////////////////////// |
1958 | | // group |
1959 | | //////////////////////////////////////////////////////////// |
1960 | | bool GreatWksGraph::sendGroup(GreatWksGraphInternal::FrameGroup const &group, GreatWksGraphInternal::Zone const &zone, MWAWPosition const &pos) |
1961 | 81 | { |
1962 | 81 | sendGroupChild(group,zone,pos); |
1963 | 81 | return true; |
1964 | 81 | } |
1965 | | |
1966 | | bool GreatWksGraph::canCreateGraphic(GreatWksGraphInternal::FrameGroup const &group, GreatWksGraphInternal::Zone const &zone) |
1967 | 0 | { |
1968 | 0 | if (group.m_childList.empty()) |
1969 | 0 | return true; |
1970 | 0 | auto numFrames=static_cast<int>(zone.m_frameList.size()); |
1971 | 0 | int page=group.m_page; |
1972 | 0 | for (auto childId : group.m_childList) { |
1973 | 0 | if (childId<=0 || childId>int(numFrames)) continue; |
1974 | 0 | std::shared_ptr<GreatWksGraphInternal::Frame> frame=zone.m_frameList[size_t(childId-1)]; |
1975 | 0 | if (!frame) continue; |
1976 | 0 | if (frame->m_page!=page) return false; |
1977 | 0 | switch (frame->getType()) { |
1978 | 0 | case GreatWksGraphInternal::Frame::T_BASIC: |
1979 | 0 | break; |
1980 | 0 | case GreatWksGraphInternal::Frame::T_DBFIELD: |
1981 | 0 | case GreatWksGraphInternal::Frame::T_PICTURE: |
1982 | 0 | return false; |
1983 | 0 | case GreatWksGraphInternal::Frame::T_GROUP: |
1984 | 0 | if (!canCreateGraphic(static_cast<GreatWksGraphInternal::FrameGroup const &>(*frame), zone)) |
1985 | 0 | return false; |
1986 | 0 | break; |
1987 | 0 | case GreatWksGraphInternal::Frame::T_TEXT: { |
1988 | 0 | auto const &text=static_cast<GreatWksGraphInternal::FrameText const &>(*frame); |
1989 | 0 | if (!m_document.canSendTextboxAsGraphic(text.m_entry)) |
1990 | 0 | return false; |
1991 | 0 | break; |
1992 | 0 | } |
1993 | 0 | case GreatWksGraphInternal::Frame::T_BAD: |
1994 | 0 | case GreatWksGraphInternal::Frame::T_UNSET: |
1995 | | #if !defined(__clang__) |
1996 | | default: |
1997 | | #endif |
1998 | 0 | break; |
1999 | 0 | } |
2000 | 0 | } |
2001 | 0 | return true; |
2002 | 0 | } |
2003 | | |
2004 | | void GreatWksGraph::sendGroup(GreatWksGraphInternal::FrameGroup const &group, GreatWksGraphInternal::Zone const &zone, MWAWGraphicListenerPtr &listener) |
2005 | 0 | { |
2006 | 0 | if (!listener || group.m_childList.empty()) return; |
2007 | 0 | auto numFrames=static_cast<int>(zone.m_frameList.size()); |
2008 | 0 | for (auto childId : group.m_childList) { |
2009 | 0 | if (childId<=0 || childId>int(numFrames)) continue; |
2010 | 0 | auto frame=zone.m_frameList[size_t(childId-1)]; |
2011 | 0 | if (!frame) continue; |
2012 | | |
2013 | 0 | MWAWBox2f const &box=frame->m_box; |
2014 | 0 | MWAWGraphicStyle style; |
2015 | 0 | if (frame->m_styleId>=1 && frame->m_styleId <= int(zone.m_styleList.size())) |
2016 | 0 | style = zone.m_styleList[size_t(frame->m_styleId-1)]; |
2017 | 0 | switch (frame->getType()) { |
2018 | 0 | case GreatWksGraphInternal::Frame::T_BASIC: { |
2019 | 0 | auto const &shape=static_cast<GreatWksGraphInternal::FrameShape const &>(*frame); |
2020 | 0 | shape.updateStyle(style); |
2021 | 0 | MWAWPosition shapePos(box[0], box.size(), librevenge::RVNG_POINT); |
2022 | 0 | shapePos.m_anchorTo=MWAWPosition::Page; |
2023 | 0 | listener->insertShape(shapePos, shape.m_shape, style); |
2024 | 0 | break; |
2025 | 0 | } |
2026 | 0 | case GreatWksGraphInternal::Frame::T_GROUP: |
2027 | 0 | sendGroup(static_cast<GreatWksGraphInternal::FrameGroup const &>(*frame), zone,listener); |
2028 | 0 | break; |
2029 | 0 | case GreatWksGraphInternal::Frame::T_TEXT: |
2030 | 0 | sendTextboxAsGraphic(MWAWBox2f(box[0],box[1]+MWAWVec2f(3,0)), |
2031 | 0 | static_cast<GreatWksGraphInternal::FrameText const &>(*frame), style, listener); |
2032 | 0 | break; |
2033 | 0 | case GreatWksGraphInternal::Frame::T_DBFIELD: |
2034 | 0 | case GreatWksGraphInternal::Frame::T_PICTURE: |
2035 | 0 | case GreatWksGraphInternal::Frame::T_BAD: |
2036 | 0 | case GreatWksGraphInternal::Frame::T_UNSET: |
2037 | | #if !defined(__clang__) |
2038 | | default: |
2039 | | #endif |
2040 | 0 | break; |
2041 | 0 | } |
2042 | 0 | } |
2043 | 0 | } |
2044 | | |
2045 | | void GreatWksGraph::sendGroupChild(GreatWksGraphInternal::FrameGroup const &group, GreatWksGraphInternal::Zone const &zone, MWAWPosition const &pos) |
2046 | 81 | { |
2047 | 81 | MWAWListenerPtr listener=m_parserState->getMainListener(); |
2048 | 81 | if (!listener) { |
2049 | 0 | MWAW_DEBUG_MSG(("GreatWksGraph::sendGroupChild: can not find the listeners\n")); |
2050 | 0 | return; |
2051 | 0 | } |
2052 | 81 | size_t numChilds=group.m_childList.size(), childNotSent=0; |
2053 | 81 | if (!numChilds) return; |
2054 | | |
2055 | 2 | bool isDraw=listener->getType()==MWAWListener::Graphic; |
2056 | 2 | int numDataToMerge=0; |
2057 | 2 | auto numFrames=static_cast<int>(zone.m_frameList.size()); |
2058 | 2 | MWAWBox2f partialBdBox; |
2059 | 2 | MWAWPosition partialPos(pos); |
2060 | | |
2061 | 4 | for (size_t c=0; c<numChilds; ++c) { |
2062 | 2 | int childId=group.m_childList[c]; |
2063 | 2 | if (childId<=0 || childId>int(numFrames)) continue; |
2064 | 2 | std::shared_ptr<GreatWksGraphInternal::Frame> frame=zone.m_frameList[size_t(childId-1)]; |
2065 | 2 | if (!frame) continue; |
2066 | | |
2067 | 2 | bool canMerge=false; |
2068 | 2 | if (!isDraw && frame->m_page==group.m_page) { |
2069 | 0 | switch (frame->getType()) { |
2070 | 0 | case GreatWksGraphInternal::Frame::T_BASIC: |
2071 | 0 | canMerge=true; |
2072 | 0 | break; |
2073 | 0 | case GreatWksGraphInternal::Frame::T_GROUP: |
2074 | 0 | canMerge=canCreateGraphic(static_cast<GreatWksGraphInternal::FrameGroup const &>(*frame), zone); |
2075 | 0 | break; |
2076 | 0 | case GreatWksGraphInternal::Frame::T_TEXT: { |
2077 | 0 | auto const &text=static_cast<GreatWksGraphInternal::FrameText const &>(*frame); |
2078 | 0 | canMerge=m_document.canSendTextboxAsGraphic(text.m_entry); |
2079 | 0 | break; |
2080 | 0 | } |
2081 | 0 | case GreatWksGraphInternal::Frame::T_DBFIELD: |
2082 | 0 | case GreatWksGraphInternal::Frame::T_PICTURE: |
2083 | 0 | case GreatWksGraphInternal::Frame::T_BAD: |
2084 | 0 | case GreatWksGraphInternal::Frame::T_UNSET: |
2085 | | #if !defined(__clang__) |
2086 | | default: |
2087 | | #endif |
2088 | 0 | break; |
2089 | 0 | } |
2090 | 0 | } |
2091 | 2 | MWAWBox2f box=frame->m_box; |
2092 | 2 | bool isLast=false; |
2093 | 2 | if (canMerge) { |
2094 | 0 | if (numDataToMerge == 0) |
2095 | 0 | partialBdBox=box; |
2096 | 0 | else |
2097 | 0 | partialBdBox=partialBdBox.getUnion(box); |
2098 | 0 | ++numDataToMerge; |
2099 | 0 | if (c+1 < numChilds) |
2100 | 0 | continue; |
2101 | 0 | isLast=true; |
2102 | 0 | } |
2103 | | |
2104 | 2 | if (numDataToMerge>1) { |
2105 | 0 | MWAWGraphicEncoder graphicEncoder; |
2106 | 0 | MWAWGraphicListenerPtr graphicListener(new MWAWGraphicListener(*m_parserState, partialBdBox, &graphicEncoder)); |
2107 | 0 | graphicListener->startDocument(); |
2108 | 0 | size_t lastChild = isLast ? c : c-1; |
2109 | 0 | for (size_t ch=childNotSent; ch <= lastChild; ++ch) { |
2110 | 0 | int localCId = group.m_childList[ch]; |
2111 | 0 | if (localCId<=0 || localCId>int(numFrames)) continue; |
2112 | 0 | auto child=zone.m_frameList[size_t(localCId-1)]; |
2113 | 0 | if (!child) continue; |
2114 | | |
2115 | 0 | box=child->m_box; |
2116 | 0 | MWAWGraphicStyle style; |
2117 | 0 | if (child->m_styleId>=1 && child->m_styleId <= int(zone.m_styleList.size())) |
2118 | 0 | style = zone.m_styleList[size_t(child->m_styleId-1)]; |
2119 | 0 | switch (child->getType()) { |
2120 | 0 | case GreatWksGraphInternal::Frame::T_BASIC: { |
2121 | 0 | auto const &shape=static_cast<GreatWksGraphInternal::FrameShape const &>(*child); |
2122 | 0 | shape.updateStyle(style); |
2123 | 0 | MWAWPosition shapePos(box[0], box.size(), librevenge::RVNG_POINT); |
2124 | 0 | shapePos.m_anchorTo=MWAWPosition::Page; |
2125 | 0 | graphicListener->insertShape(shapePos, shape.m_shape, style); |
2126 | 0 | break; |
2127 | 0 | } |
2128 | 0 | case GreatWksGraphInternal::Frame::T_GROUP: |
2129 | 0 | sendGroup(static_cast<GreatWksGraphInternal::FrameGroup const &>(*child), zone,graphicListener); |
2130 | 0 | break; |
2131 | 0 | case GreatWksGraphInternal::Frame::T_TEXT: |
2132 | 0 | sendTextboxAsGraphic(MWAWBox2f(box[0],box[1]+MWAWVec2f(3,0)), |
2133 | 0 | static_cast<GreatWksGraphInternal::FrameText const &>(*child), style, graphicListener); |
2134 | 0 | break; |
2135 | 0 | case GreatWksGraphInternal::Frame::T_DBFIELD: |
2136 | 0 | case GreatWksGraphInternal::Frame::T_PICTURE: |
2137 | 0 | case GreatWksGraphInternal::Frame::T_BAD: |
2138 | 0 | case GreatWksGraphInternal::Frame::T_UNSET: |
2139 | | #if !defined(__clang__) |
2140 | | default: |
2141 | | #endif |
2142 | 0 | break; |
2143 | 0 | } |
2144 | 0 | } |
2145 | 0 | graphicListener->endDocument(); |
2146 | 0 | MWAWEmbeddedObject picture; |
2147 | 0 | if (graphicEncoder.getBinaryResult(picture)) { |
2148 | 0 | partialPos.setOrigin(pos.origin()+partialBdBox[0]-group.m_box[0]); |
2149 | 0 | partialPos.setSize(partialBdBox.size()); |
2150 | 0 | listener->insertPicture(partialPos, picture); |
2151 | 0 | if (isLast) |
2152 | 0 | break; |
2153 | 0 | childNotSent=c; |
2154 | 0 | } |
2155 | 0 | } |
2156 | | |
2157 | | // time to send back the data |
2158 | 4 | for (; childNotSent <= c; ++childNotSent) { |
2159 | 2 | int localCId=group.m_childList[childNotSent]; |
2160 | 2 | if (localCId<=0 || localCId>int(numFrames)) continue; |
2161 | 2 | auto child=zone.m_frameList[size_t(localCId-1)]; |
2162 | 2 | if (!child) continue; |
2163 | 2 | sendFrame(child, zone); |
2164 | 2 | } |
2165 | 2 | numDataToMerge=0; |
2166 | 2 | } |
2167 | 2 | } |
2168 | | |
2169 | | |
2170 | | //////////////////////////////////////////////////////////// |
2171 | | // send data to a listener |
2172 | | //////////////////////////////////////////////////////////// |
2173 | | |
2174 | | //////////////////////////////////////////////////////////// |
2175 | | // send data |
2176 | | //////////////////////////////////////////////////////////// |
2177 | | bool GreatWksGraph::sendShape(GreatWksGraphInternal::FrameShape const &graph, GreatWksGraphInternal::Zone const &zone, MWAWPosition const &pos) |
2178 | 8.08k | { |
2179 | 8.08k | MWAWListenerPtr listener=m_parserState->getMainListener(); |
2180 | 8.08k | if (!listener) { |
2181 | 0 | MWAW_DEBUG_MSG(("GreatWksGraph::sendShape: can not find a listener\n")); |
2182 | 0 | return false; |
2183 | 0 | } |
2184 | 8.08k | MWAWGraphicStyle style; |
2185 | 8.08k | if (graph.m_styleId>=1 && graph.m_styleId <= int(zone.m_styleList.size())) |
2186 | 7.49k | style = zone.m_styleList[size_t(graph.m_styleId-1)]; |
2187 | 8.08k | graph.updateStyle(style); |
2188 | 8.08k | MWAWPosition finalPos(pos); |
2189 | 8.08k | finalPos.setOrigin(pos.origin()-MWAWVec2f(2,2)); |
2190 | 8.08k | finalPos.setSize(pos.size()+MWAWVec2f(4,4)); |
2191 | 8.08k | listener->insertShape(finalPos,graph.m_shape, style); |
2192 | 8.08k | return true; |
2193 | 8.08k | } |
2194 | | |
2195 | | bool GreatWksGraph::sendFrame(std::shared_ptr<GreatWksGraphInternal::Frame> frame, GreatWksGraphInternal::Zone const &zone) |
2196 | 13.5k | { |
2197 | 13.5k | MWAWListenerPtr listener=m_parserState->getMainListener(); |
2198 | 13.5k | if (!listener || !frame) { |
2199 | 0 | MWAW_DEBUG_MSG(("GreatWksGraph::sendFrame: can not find a listener\n")); |
2200 | 0 | return false; |
2201 | 0 | } |
2202 | 13.5k | frame->m_parsed=true; |
2203 | 13.5k | MWAWInputStreamPtr &input= m_parserState->m_input; |
2204 | 13.5k | long pos=input->tell(); |
2205 | 13.5k | MWAWVec2f LTPos(0,0); |
2206 | 13.5k | if (m_parserState->m_kind==MWAWDocument::MWAW_K_DRAW) |
2207 | 6.47k | LTPos=72.0f*MWAWVec2f(float(m_mainParser->getPageSpan().getMarginLeft()), float(m_mainParser->getPageSpan().getMarginTop())); |
2208 | 13.5k | MWAWPosition fPos(frame->m_box[0]+LTPos,frame->m_box.size(),librevenge::RVNG_POINT); |
2209 | 13.5k | fPos.setRelativePosition(MWAWPosition::Page); |
2210 | 13.5k | fPos.setPage(frame->m_page<0 ? 1: frame->m_page); |
2211 | 13.5k | fPos.m_wrapping = MWAWPosition::WBackground; |
2212 | 13.5k | bool ok=true; |
2213 | 13.5k | switch (frame->getType()) { |
2214 | 8.08k | case GreatWksGraphInternal::Frame::T_BASIC: |
2215 | 8.08k | ok = sendShape(static_cast<GreatWksGraphInternal::FrameShape const &>(*frame), zone, fPos); |
2216 | 8.08k | break; |
2217 | 66 | case GreatWksGraphInternal::Frame::T_PICTURE: |
2218 | 66 | ok = sendPicture(static_cast<GreatWksGraphInternal::FramePicture const &>(*frame).m_entry, fPos); |
2219 | 66 | break; |
2220 | 81 | case GreatWksGraphInternal::Frame::T_GROUP: |
2221 | 81 | ok = sendGroup(static_cast<GreatWksGraphInternal::FrameGroup const &>(*frame), zone, fPos); |
2222 | 81 | break; |
2223 | 2.25k | case GreatWksGraphInternal::Frame::T_TEXT: |
2224 | 2.25k | ok = sendTextbox(static_cast<GreatWksGraphInternal::FrameText const &>(*frame), zone, fPos); |
2225 | 2.25k | break; |
2226 | 88 | case GreatWksGraphInternal::Frame::T_DBFIELD: |
2227 | | // do me |
2228 | 917 | case GreatWksGraphInternal::Frame::T_BAD: |
2229 | 3.02k | case GreatWksGraphInternal::Frame::T_UNSET: |
2230 | | #if !defined(__clang__) |
2231 | | default: |
2232 | | #endif |
2233 | 3.02k | ok=false; |
2234 | 13.5k | } |
2235 | 13.5k | input->seek(pos, librevenge::RVNG_SEEK_SET); |
2236 | 13.5k | return ok; |
2237 | 13.5k | } |
2238 | | |
2239 | | bool GreatWksGraph::sendPageFrames(GreatWksGraphInternal::Zone const &zone) |
2240 | 7.56k | { |
2241 | 7.56k | MWAWListenerPtr listener=m_parserState->getMainListener(); |
2242 | 7.56k | if (!listener) { |
2243 | 0 | MWAW_DEBUG_MSG(("GreatWksGraph::sendPageFrames: can not find a listener\n")); |
2244 | 0 | return false; |
2245 | 0 | } |
2246 | 7.56k | zone.m_parsed=true; |
2247 | 14.0k | for (auto id : zone.m_rootList) { |
2248 | 14.0k | --id; |
2249 | 14.0k | if (id<0 || !zone.m_frameList[size_t(id)]) |
2250 | 511 | continue; |
2251 | 13.5k | auto frame=zone.m_frameList[size_t(id)]; |
2252 | 13.5k | if (frame->m_parsed) |
2253 | 0 | continue; |
2254 | 13.5k | sendFrame(frame,zone); |
2255 | 13.5k | } |
2256 | 7.56k | return true; |
2257 | 7.56k | } |
2258 | | |
2259 | | bool GreatWksGraph::sendPageGraphics() |
2260 | 12.6k | { |
2261 | 12.6k | MWAWListenerPtr listener=m_parserState->getMainListener(); |
2262 | 12.6k | if (!listener) { |
2263 | 0 | MWAW_DEBUG_MSG(("GreatWksGraph::sendPageGraphics: can not find a listener\n")); |
2264 | 0 | return false; |
2265 | 0 | } |
2266 | 12.6k | for (auto const &zone : m_state->m_zoneList) { |
2267 | 7.56k | if (zone.m_parsed) |
2268 | 0 | continue; |
2269 | 7.56k | sendPageFrames(zone); |
2270 | 7.56k | } |
2271 | 12.6k | return true; |
2272 | 12.6k | } |
2273 | | |
2274 | | void GreatWksGraph::flushExtra() |
2275 | 0 | { |
2276 | 0 | sendPageGraphics(); |
2277 | 0 | } |
2278 | | // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: |