/src/libwps/src/lib/WPS8.cpp
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ |
2 | | /* libwps |
3 | | * Version: MPL 2.0 / LGPLv2.1+ |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * Major Contributor(s): |
10 | | * Copyright (C) 2006, 2007 Andrew Ziem |
11 | | * Copyright (C) 2004 Marc Maurer (uwog@uwog.net) |
12 | | * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch) |
13 | | * |
14 | | * For minor contributions see the git repository. |
15 | | * |
16 | | * Alternatively, the contents of this file may be used under the terms |
17 | | * of the GNU Lesser General Public License Version 2.1 or later |
18 | | * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are |
19 | | * applicable instead of those above. |
20 | | */ |
21 | | |
22 | | #include <algorithm> |
23 | | #include <stdlib.h> |
24 | | #include <stdio.h> |
25 | | #include <string.h> |
26 | | |
27 | | #include <librevenge-stream/librevenge-stream.h> |
28 | | |
29 | | #include "libwps_internal.h" |
30 | | #include "libwps_tools_win.h" |
31 | | |
32 | | #include "WPSContentListener.h" |
33 | | #include "WPSEntry.h" |
34 | | #include "WPSHeader.h" |
35 | | #include "WPSOLEParser.h" |
36 | | #include "WPSPageSpan.h" |
37 | | #include "WPSPosition.h" |
38 | | #include "WPSTextSubDocument.h" |
39 | | |
40 | | #include "WPS8Graph.h" |
41 | | #include "WPS8Struct.h" |
42 | | #include "WPS8Table.h" |
43 | | #include "WPS8Text.h" |
44 | | |
45 | | #include "WPS8.h" |
46 | | |
47 | | namespace WPS8ParserInternal |
48 | | { |
49 | | //! Internal: the subdocument of a WPS8Parser |
50 | | class SubDocument final : public WPSTextSubDocument |
51 | | { |
52 | | public: |
53 | | //! type of an entry |
54 | | enum Type { Unknown, TEXT }; |
55 | | //! constructor for a text entry |
56 | | SubDocument(RVNGInputStreamPtr const &input, WPS8Parser &pars, WPSEntry const &entry) |
57 | 12.6k | : WPSTextSubDocument(input, &pars) |
58 | 12.6k | , m_entry(entry) {} |
59 | | //! destructor |
60 | 12.6k | ~SubDocument() final {} |
61 | | |
62 | | //! operator== |
63 | | bool operator==(std::shared_ptr<WPSSubDocument> const &doc) const final |
64 | 0 | { |
65 | 0 | if (!doc || !WPSTextSubDocument::operator==(doc)) |
66 | 0 | return false; |
67 | 0 | auto const *sDoc = dynamic_cast<SubDocument const *>(doc.get()); |
68 | 0 | if (!sDoc) return false; |
69 | 0 | return m_entry == sDoc->m_entry; |
70 | 0 | } |
71 | | |
72 | | //! the parser function |
73 | | void parse(std::shared_ptr<WPSContentListener> &listener, libwps::SubDocumentType subDocumentType) final; |
74 | | //! the entry |
75 | | WPSEntry m_entry; |
76 | | }; |
77 | | |
78 | | void SubDocument::parse(std::shared_ptr<WPSContentListener> &listener, libwps::SubDocumentType subDocumentType) |
79 | 16.5k | { |
80 | 16.5k | if (!listener.get()) |
81 | 0 | { |
82 | 0 | WPS_DEBUG_MSG(("WPS8ParserInternal::SubDocument::parse: no listener\n")); |
83 | 0 | return; |
84 | 0 | } |
85 | 16.5k | if (!dynamic_cast<WPSContentListener *>(listener.get())) |
86 | 0 | { |
87 | 0 | WPS_DEBUG_MSG(("WPS8ParserInternal::SubDocument::parse: bad listener\n")); |
88 | 0 | return; |
89 | 0 | } |
90 | | |
91 | 16.5k | auto &listen = static_cast<WPSContentListenerPtr &>(listener); |
92 | 16.5k | if (!m_parser) |
93 | 0 | { |
94 | 0 | listen->insertCharacter(' '); |
95 | 0 | WPS_DEBUG_MSG(("WPS8ParserInternal::SubDocument::parse: bad parser\n")); |
96 | 0 | return; |
97 | 0 | } |
98 | | |
99 | 16.5k | if (m_entry.isParsed() && subDocumentType != libwps::DOC_HEADER_FOOTER) |
100 | 20 | { |
101 | 20 | listen->insertCharacter(' '); |
102 | 20 | WPS_DEBUG_MSG(("WPS8ParserInternal::SubDocument::parse: this zone is already parsed\n")); |
103 | 20 | return; |
104 | 20 | } |
105 | 16.5k | m_entry.setParsed(true); |
106 | 16.5k | if (m_entry.type() != "Text") |
107 | 11.8k | { |
108 | 11.8k | listen->insertCharacter(' '); |
109 | 11.8k | WPS_DEBUG_MSG(("WPS8ParserInternal::SubDocument::parse: send not Text entry is not implemented\n")); |
110 | 11.8k | return; |
111 | 11.8k | } |
112 | | |
113 | 4.72k | if (!m_entry.valid()) |
114 | 7 | { |
115 | 7 | WPS_DEBUG_MSG(("WPS8ParserInternal::SubDocument::parse: empty document found...\n")); |
116 | 7 | listen->insertCharacter(' '); |
117 | 7 | return; |
118 | 7 | } |
119 | | |
120 | | |
121 | 4.71k | auto *mnParser = dynamic_cast<WPS8Parser *>(m_parser); |
122 | 4.71k | if (!mnParser) |
123 | 0 | { |
124 | 0 | WPS_DEBUG_MSG(("WPS8ParserInternal::SubDocument::parse: can not find a WPS8Parser...\n")); |
125 | 0 | listen->insertCharacter(' '); |
126 | 0 | return; |
127 | 0 | } |
128 | 4.71k | mnParser->send(m_entry); |
129 | 4.71k | } |
130 | | |
131 | | /** Internal: a frame, a zone which can contain text, picture, ... and have some borders */ |
132 | | struct Frame |
133 | | { |
134 | | //! constructor |
135 | 290k | Frame() : m_parsed(false), m_type(UNKNOWN), m_pos(), |
136 | 290k | m_idStrs(-1), m_idObject(-1), m_idTable(-1), m_idOle(-1), m_columns(1), m_idBorder(), |
137 | 290k | m_backgroundColor(WPSColor::white()), m_error("") |
138 | 290k | { |
139 | 290k | m_pos.setRelativePosition(WPSPosition::Page); |
140 | 290k | m_pos.setPage(1); |
141 | 290k | } |
142 | | |
143 | | //! operator << |
144 | | friend std::ostream &operator<<(std::ostream &o, Frame const &ft); |
145 | | |
146 | | /** The frame type |
147 | | * |
148 | | * - Header/Footer: the header and footer frame |
149 | | * - Table : a table |
150 | | * - Object : a picture, ... |
151 | | * - Text : a text zone */ |
152 | | enum { UNKNOWN = 0, DbField, Header, Footer, Table, Object, Text }; |
153 | | |
154 | | //! a flag to know if the frame is already sent to the listener |
155 | | mutable bool m_parsed; |
156 | | //! the frame type |
157 | | int m_type; |
158 | | //! the frame position |
159 | | WPSPosition m_pos; |
160 | | int m_idStrs /** identifier corresponding to a text zone (STRS)*/, |
161 | | m_idObject /** identifier corresponding to an object zone (EOBJ)*/, |
162 | | m_idTable /** identifier corresponding to a table (MCLD)*/, |
163 | | m_idOle /** identifier corresponding to an ole*/; |
164 | | //! the number of columns for a textbox, ... |
165 | | int m_columns; |
166 | | //! the border: an entry to some complex border (if sets) |
167 | | WPSEntry m_idBorder; |
168 | | //! the border's color |
169 | | WPSColor m_backgroundColor; |
170 | | //! a string used to store the parsing errors |
171 | | std::string m_error; |
172 | | }; |
173 | | |
174 | | //! operator<< for a Frame |
175 | | std::ostream &operator<<(std::ostream &o, Frame const &ft) |
176 | 0 | { |
177 | 0 | switch (ft.m_type) |
178 | 0 | { |
179 | 0 | case Frame::DbField: |
180 | 0 | o<< "db[field]"; |
181 | 0 | break; |
182 | 0 | case Frame::Header: |
183 | 0 | o<< "header"; |
184 | 0 | break; |
185 | 0 | case Frame::Footer: |
186 | 0 | o<< "footer"; |
187 | 0 | break; |
188 | 0 | case Frame::Table: |
189 | 0 | o<< "table"; |
190 | 0 | break; |
191 | 0 | case Frame::Text: |
192 | 0 | o<< "textbox"; |
193 | 0 | break; |
194 | 0 | case Frame::Object: |
195 | 0 | o<< "object"; |
196 | 0 | break; |
197 | 0 | default: |
198 | 0 | o << "###type=unknown"; |
199 | 0 | break; |
200 | 0 | } |
201 | 0 | o << "("; |
202 | 0 | if (ft.m_idStrs >= 0) o << "STRS" << ft.m_idStrs << ","; |
203 | 0 | if (ft.m_idObject >= 0) o << "EOBJ" << ft.m_idObject << ","; |
204 | 0 | if (ft.m_idTable >= 0) o << "MCLD/Table" << ft.m_idTable << ","; |
205 | 0 | if (ft.m_idOle >= 0) o << "oleId=" << ft.m_idOle << ","; |
206 | 0 | o << "),"; |
207 | |
|
208 | 0 | o << ft.m_pos << ","; |
209 | 0 | switch (ft.m_pos.page()) |
210 | 0 | { |
211 | 0 | case -1: |
212 | 0 | o << "allpages,"; |
213 | 0 | break; |
214 | 0 | case -2: |
215 | 0 | break; // undef |
216 | 0 | default: |
217 | 0 | if (ft.m_pos.page() < 0) o << "###page=" << ft.m_pos.page() << ","; |
218 | 0 | } |
219 | | |
220 | 0 | if (ft.m_columns != 1) o << ft.m_columns << "columns,"; |
221 | 0 | if (ft.m_idBorder.valid()) |
222 | 0 | o << "border='" << ft.m_idBorder.name() << "':" << ft.m_idBorder.id() << ","; |
223 | 0 | if (!ft.m_backgroundColor.isWhite()) |
224 | 0 | o << "backColor=" << ft.m_backgroundColor << ","; |
225 | |
|
226 | 0 | if (!ft.m_error.empty()) o << "errors=(" << ft.m_error << ")"; |
227 | 0 | return o; |
228 | 0 | } |
229 | | |
230 | | //! the state of WPS8 |
231 | | struct State |
232 | | { |
233 | | State() |
234 | 7.96k | : m_eof(-1) |
235 | 7.96k | , m_pageSpan() |
236 | 7.96k | , m_localeLanguage("") |
237 | 7.96k | , m_background() |
238 | 7.96k | , m_frameList() |
239 | 7.96k | , m_object2FrameMap() |
240 | 7.96k | , m_table2FrameMap() |
241 | 7.96k | , m_docPropertyTypes() |
242 | 7.96k | , m_frameTypes() |
243 | 7.96k | , m_numColumns(1) |
244 | 7.96k | , m_actPage(0) |
245 | 7.96k | , m_numPages(0) |
246 | 7.96k | { |
247 | 7.96k | initTypeMaps(); |
248 | 7.96k | } |
249 | | //! initializes the type map |
250 | | void initTypeMaps(); |
251 | | //! the end of file |
252 | | long m_eof; |
253 | | //! the actual document size |
254 | | WPSPageSpan m_pageSpan; |
255 | | //! the language |
256 | | std::string m_localeLanguage; |
257 | | //! an identificator to design a background picture |
258 | | WPSEntry m_background; |
259 | | |
260 | | //! the frame's list |
261 | | std::vector<Frame> m_frameList; |
262 | | //! a map m_idObject -> frame |
263 | | std::map<int, int> m_object2FrameMap; |
264 | | //! a map m_idTable -> frame |
265 | | std::map<int, int> m_table2FrameMap; |
266 | | |
267 | | //! the document property type |
268 | | std::map<int, int> m_docPropertyTypes; |
269 | | //! the frame type |
270 | | std::map<int, int> m_frameTypes; |
271 | | int m_numColumns /** the number of columns */; |
272 | | int m_actPage /** the actual page*/, m_numPages /* the number of pages */; |
273 | | }; |
274 | | |
275 | | void State::initTypeMaps() |
276 | 7.96k | { |
277 | 7.96k | static int const docTypes[] = |
278 | 7.96k | { |
279 | 7.96k | 0, 0x22, 1, 0x22, 2, 0x22, 3, 0x22, 4, 0x22, 5, 0x22, 6, 0x22, 7, 0x22, |
280 | 7.96k | 8, 0x1a, 0xa, 0x2, |
281 | 7.96k | 0x13, 0x2a, 0x15, 0x2a, |
282 | 7.96k | 0x18, 0x12, 0x19, 0x2, 0x1b, 0x12, 0x1c, 0x22, 0x1e, 0x22, |
283 | 7.96k | 0x26, 0x22, 0x27, 0x22, |
284 | 7.96k | 0x28, 0x22, 0x29, 0x22, 0x2a, 0x22, 0x2b, 0x22, 0x2c, 0x82, 0x2d, 0x82, 0x2e, 0x82 |
285 | 7.96k | }; |
286 | 215k | for (int i = 0; i+1 < int(WPS_N_ELEMENTS(docTypes)); i+=2) |
287 | 207k | m_docPropertyTypes[docTypes[i]] = docTypes[i+1]; |
288 | 7.96k | static int const frameTypes[] = |
289 | 7.96k | { |
290 | 7.96k | 0, 0x1a, 1, 0x12, 2, 0x12, 3, 0x2, 4, 0x22, 5, 0x22, 6, 0x22, 7, 0x22, |
291 | 7.96k | 8, 0x22, 9, 0x22, 0xa, 0x22, |
292 | 7.96k | 0x10, 0x2a, 0x11, 0x82, 0x13, 0x12, 0x14, 0x12, 0x16, 0x2a, 0x17, 0x2, |
293 | 7.96k | 0x18, 0x22, 0x19, 0x22, 0x1a, 0x12, 0x1b, 0x22, 0x1d, 0x22, 0x1e, 0x22, 0x1f, 0x22, |
294 | 7.96k | 0x20, 0x22, 0x26, 0x22, |
295 | 7.96k | 0x2a, 0x22, 0x2c, 0x1a, 0x2d, 0x1a, 0x2e, 0x22, 0x2f, 0x2, |
296 | 7.96k | 0x30, 0x22 |
297 | 7.96k | }; |
298 | 262k | for (int i = 0; i+1 < int(WPS_N_ELEMENTS(frameTypes)); i+=2) |
299 | 255k | m_frameTypes[frameTypes[i]] = frameTypes[i+1]; |
300 | | |
301 | 7.96k | } |
302 | | |
303 | | class TableRecursionGuard |
304 | | { |
305 | | // disable copying |
306 | | TableRecursionGuard(const TableRecursionGuard &) = delete; |
307 | | TableRecursionGuard &operator=(const TableRecursionGuard &) = delete; |
308 | | |
309 | | public: |
310 | | TableRecursionGuard(std::deque<int> &stack, const int id) |
311 | 350 | : m_stack(stack) |
312 | 350 | { |
313 | 350 | m_stack.push_front(id); |
314 | 350 | } |
315 | | |
316 | | ~TableRecursionGuard() |
317 | 350 | { |
318 | 350 | m_stack.pop_front(); |
319 | 350 | } |
320 | | |
321 | | private: |
322 | | std::deque<int> &m_stack; |
323 | | }; |
324 | | |
325 | | |
326 | | } |
327 | | |
328 | | // constructor, destructor |
329 | | WPS8Parser::WPS8Parser(RVNGInputStreamPtr &input, WPSHeaderPtr &header) |
330 | 7.96k | : WPSParser(input, header) |
331 | 7.96k | , m_listener() |
332 | 7.96k | , m_graphParser() |
333 | 7.96k | , m_tableParser() |
334 | 7.96k | , m_textParser() |
335 | 7.96k | , m_state() |
336 | 7.96k | , m_sendingTables() |
337 | 7.96k | { |
338 | 7.96k | if (version()<5) setVersion(5); |
339 | 7.96k | m_state.reset(new WPS8ParserInternal::State); |
340 | 7.96k | m_graphParser.reset(new WPS8Graph(*this)); |
341 | 7.96k | m_tableParser.reset(new WPS8Table(*this)); |
342 | 7.96k | m_textParser.reset(new WPS8Text(*this)); |
343 | 7.96k | } |
344 | | |
345 | | WPS8Parser::~WPS8Parser() |
346 | 7.96k | { |
347 | 7.96k | } |
348 | | |
349 | | // small funtion ( dimension, ...) |
350 | | float WPS8Parser::pageHeight() const |
351 | 0 | { |
352 | 0 | return float(m_state->m_pageSpan.getFormLength()-m_state->m_pageSpan.getMarginTop()-m_state->m_pageSpan.getMarginBottom()); |
353 | 0 | } |
354 | | |
355 | | float WPS8Parser::pageWidth() const |
356 | 10 | { |
357 | 10 | return float(m_state->m_pageSpan.getFormWidth()-m_state->m_pageSpan.getMarginLeft()-m_state->m_pageSpan.getMarginRight()); |
358 | 10 | } |
359 | | |
360 | | int WPS8Parser::numColumns() const |
361 | 6.45k | { |
362 | 6.45k | return m_state->m_numColumns; |
363 | 6.45k | } |
364 | | |
365 | | bool WPS8Parser::checkInFile(long pos) |
366 | 0 | { |
367 | 0 | if (pos <= m_state->m_eof) |
368 | 0 | return true; |
369 | 0 | RVNGInputStreamPtr input = getInput(); |
370 | 0 | long actPos = input->tell(); |
371 | 0 | input->seek(pos, librevenge::RVNG_SEEK_SET); |
372 | 0 | bool ok = input->tell() == pos; |
373 | 0 | if (ok) m_state->m_eof = pos; |
374 | 0 | input->seek(actPos, librevenge::RVNG_SEEK_SET); |
375 | 0 | return ok; |
376 | 0 | } |
377 | | |
378 | | // listener, new page |
379 | | void WPS8Parser::setListener(std::shared_ptr<WPSContentListener> const &listener) |
380 | 7.01k | { |
381 | 7.01k | m_listener = listener; |
382 | 7.01k | m_graphParser->setListener(m_listener); |
383 | 7.01k | m_tableParser->setListener(m_listener); |
384 | 7.01k | m_textParser->setListener(m_listener); |
385 | 7.01k | } |
386 | | |
387 | | std::shared_ptr<WPSContentListener> WPS8Parser::createListener(librevenge::RVNGTextInterface *interface) |
388 | 7.01k | { |
389 | 7.01k | std::vector<WPSPageSpan> pageList; |
390 | 7.01k | WPSPageSpan ps(m_state->m_pageSpan); |
391 | | |
392 | 7.01k | int numPages = 1; |
393 | 7.01k | for (auto const &frame : m_state->m_frameList) |
394 | 290k | { |
395 | 290k | if (frame.m_pos.page() > numPages) |
396 | 57 | numPages = frame.m_pos.page(); |
397 | 290k | } |
398 | | |
399 | 7.01k | int textPages = m_textParser->numPages(); |
400 | 7.01k | if (textPages > numPages) numPages = textPages; |
401 | 7.01k | int tablePages = m_tableParser->numPages(); |
402 | 7.01k | if (tablePages > numPages) numPages = tablePages; |
403 | 7.01k | int graphPages = m_graphParser->numPages(); |
404 | 7.01k | if (graphPages>=numPages) numPages = graphPages; |
405 | | |
406 | 7.01k | WPSEntry entry = m_textParser->getHeaderEntry(); |
407 | 7.01k | if (entry.valid()) |
408 | 326 | { |
409 | 326 | WPSSubDocumentPtr subdoc(new WPS8ParserInternal::SubDocument |
410 | 326 | (getInput(), *this, entry)); |
411 | 326 | ps.setHeaderFooter(WPSPageSpan::HEADER, WPSPageSpan::ALL, subdoc); |
412 | 326 | } |
413 | | |
414 | 7.01k | entry = m_textParser->getFooterEntry(); |
415 | 7.01k | if (entry.valid()) |
416 | 400 | { |
417 | 400 | WPSSubDocumentPtr subdoc(new WPS8ParserInternal::SubDocument |
418 | 400 | (getInput(), *this, entry)); |
419 | 400 | ps.setHeaderFooter(WPSPageSpan::FOOTER, WPSPageSpan::ALL, subdoc); |
420 | 400 | } |
421 | | #ifdef DEBUG |
422 | | // create all the pages + an empty page, if we have some remaining data... |
423 | | numPages++; |
424 | | #endif |
425 | | |
426 | 7.01k | pageList.push_back(ps); |
427 | 34.6k | for (int i = 1; i < numPages; i++) pageList.push_back(ps); |
428 | 7.01k | m_state->m_numPages=numPages; |
429 | 7.01k | return std::shared_ptr<WPSContentListener> |
430 | 7.01k | (new WPSContentListener(pageList, interface)); |
431 | 7.01k | } |
432 | | |
433 | | void WPS8Parser::newPage(int number) |
434 | 24.9k | { |
435 | 24.9k | if (number <= m_state->m_actPage || number > m_state->m_numPages) |
436 | 75 | return; |
437 | | |
438 | 50.6k | while (m_state->m_actPage < number) |
439 | 25.7k | { |
440 | 25.7k | m_state->m_actPage++; |
441 | | |
442 | 25.7k | if (m_listener.get() == nullptr || m_state->m_actPage == 1) |
443 | 891 | continue; |
444 | 24.9k | m_listener->insertBreak(WPS_PAGE_BREAK); |
445 | 24.9k | m_graphParser->sendObjects(m_state->m_actPage); |
446 | 24.9k | } |
447 | 24.9k | } |
448 | | |
449 | | //////////////////////////////////////////////////////////// |
450 | | // interface with the graph/text parser |
451 | | void WPS8Parser::send(WPSEntry const &entry) |
452 | 4.71k | { |
453 | 4.71k | RVNGInputStreamPtr input = getInput(); |
454 | 4.71k | long actPos = input->tell(); |
455 | 4.71k | m_textParser->readText(entry); |
456 | 4.71k | input->seek(actPos, librevenge::RVNG_SEEK_SET); |
457 | 4.71k | } |
458 | | |
459 | | void WPS8Parser::send(int strsId) |
460 | 0 | { |
461 | 0 | send(m_textParser->getEntry(strsId)); |
462 | 0 | } |
463 | | |
464 | | void WPS8Parser::sendTextInCell(int strsId, int cellId) |
465 | 835 | { |
466 | 835 | RVNGInputStreamPtr input = getInput(); |
467 | 835 | long actPos = input->tell(); |
468 | 835 | m_textParser->readTextInCell(strsId,cellId); |
469 | 835 | input->seek(actPos, librevenge::RVNG_SEEK_SET); |
470 | 835 | } |
471 | | |
472 | | void WPS8Parser::sendTextBox(WPSPosition const &pos, int strsid, librevenge::RVNGPropertyList frameExtras) |
473 | 11.9k | { |
474 | 11.9k | if (!m_listener) |
475 | 0 | { |
476 | 0 | WPS_DEBUG_MSG(("WPS8Parser::sendTextBox can not find the listener\n")); |
477 | 0 | return; |
478 | 0 | } |
479 | 11.9k | WPSEntry entry = m_textParser->getEntry(strsid); |
480 | 11.9k | WPSSubDocumentPtr subdoc(new WPS8ParserInternal::SubDocument |
481 | 11.9k | (getInput(), *this, entry)); |
482 | 11.9k | m_listener->insertTextBox(pos, subdoc, frameExtras); |
483 | 11.9k | } |
484 | | |
485 | | bool WPS8Parser::sendObject(Vec2f const &size, int objectId, bool ole) |
486 | 211 | { |
487 | 211 | WPSPosition posi(Vec2f(),size); |
488 | 211 | posi.setRelativePosition(WPSPosition::CharBaseLine); |
489 | 211 | posi.m_wrapping = WPSPosition::WDynamic; |
490 | 211 | m_graphParser->sendObject(posi,objectId,ole); |
491 | 211 | return true; |
492 | 211 | } |
493 | | |
494 | | bool WPS8Parser::sendTable(Vec2f const &size, int objectId) |
495 | 780 | { |
496 | 780 | if (find(m_sendingTables.begin(), m_sendingTables.end(), objectId) != m_sendingTables.end()) |
497 | 250 | { |
498 | 250 | WPS_DEBUG_MSG(("WPS8Parser::sendTable table %d is contained in itself\n", objectId)); |
499 | 250 | return false; |
500 | 250 | } |
501 | | |
502 | 530 | auto pos = m_state->m_object2FrameMap.find(objectId); |
503 | 530 | if (pos == m_state->m_object2FrameMap.end()) |
504 | 121 | { |
505 | 121 | WPS_DEBUG_MSG(("WPS8Parser::sendTable can not find the table %d \n", objectId)); |
506 | 121 | return false; |
507 | 121 | } |
508 | | |
509 | 409 | auto const &frame = m_state->m_frameList[size_t(pos->second)]; |
510 | 409 | if (frame.m_idStrs < 0) |
511 | 43 | { |
512 | 43 | WPS_DEBUG_MSG(("WPS8Parser:sendTable can not find the text zone \n")); |
513 | 43 | return false; |
514 | 43 | } |
515 | | |
516 | 366 | if (frame.m_idTable < 0) |
517 | 16 | { |
518 | 16 | WPSPosition position(Vec2f(), size); |
519 | 16 | position.m_anchorTo = WPSPosition::CharBaseLine; // CHECKME |
520 | 16 | position.m_wrapping = WPSPosition::WDynamic; |
521 | | |
522 | 16 | WPS_DEBUG_MSG(("WPS8Parser:sendTable can not find the table zone \n")); |
523 | 16 | sendTextBox(position, frame.m_idStrs); |
524 | 16 | return true; |
525 | 16 | } |
526 | 350 | frame.m_parsed = true; |
527 | 350 | WPS8ParserInternal::TableRecursionGuard guard(m_sendingTables, objectId); |
528 | 350 | return m_tableParser->sendTable(size, frame.m_idTable, frame.m_idStrs); |
529 | 366 | } |
530 | | |
531 | | int WPS8Parser::getTableSTRSId(int tableId) const |
532 | 0 | { |
533 | 0 | auto pos = m_state->m_table2FrameMap.find(tableId); |
534 | | // probably ok: checkme |
535 | 0 | if (pos == m_state->m_table2FrameMap.end()) |
536 | 0 | return -1; |
537 | 0 | auto const &frame = m_state->m_frameList[size_t(pos->second)]; |
538 | 0 | if (frame.m_idStrs < 0) |
539 | 0 | { |
540 | 0 | WPS_DEBUG_MSG(("WPS8Parser:getTableSTRSId can not find the text zone \n")); |
541 | 0 | } |
542 | 0 | return frame.m_idStrs; |
543 | 0 | } |
544 | | |
545 | | //////////////////////////////////////////////////////////// |
546 | | // main function to parse the document |
547 | | void WPS8Parser::parse(librevenge::RVNGTextInterface *documentInterface) |
548 | 7.96k | { |
549 | 7.96k | RVNGInputStreamPtr input=getInput(); |
550 | 7.96k | if (!input) |
551 | 0 | { |
552 | 0 | WPS_DEBUG_MSG(("WPS8Parser::parse: does not find main ole\n")); |
553 | 0 | throw (libwps::ParseException()); |
554 | 0 | } |
555 | | |
556 | 7.96k | try |
557 | 7.96k | { |
558 | 7.96k | createOLEStructures(); |
559 | 7.96k | } |
560 | 7.96k | catch (...) |
561 | 7.96k | { |
562 | 0 | WPS_DEBUG_MSG(("WPS8Parser::parse: exception catched when parsing secondary OLEs\n")); |
563 | 0 | } |
564 | | |
565 | 7.96k | ascii().setStream(input); |
566 | 7.96k | ascii().open("CONTENTS"); |
567 | 7.96k | try |
568 | 7.96k | { |
569 | 7.96k | if (!createStructures()) throw(libwps::ParseException()); |
570 | 7.96k | } |
571 | 7.96k | catch (...) |
572 | 7.96k | { |
573 | 958 | WPS_DEBUG_MSG(("WPS8Parser::parse: exception catched when parsing MN0\n")); |
574 | 958 | throw (libwps::ParseException()); |
575 | 958 | } |
576 | 7.01k | setListener(createListener(documentInterface)); |
577 | 7.01k | if (!m_listener) |
578 | 0 | { |
579 | 0 | WPS_DEBUG_MSG(("WPS8Parser::parse: can not create the listener\n")); |
580 | 0 | throw (libwps::ParseException()); |
581 | 0 | } |
582 | 7.01k | m_listener->startDocument(); |
583 | 7.01k | sendPageFrames(); |
584 | 7.01k | WPSEntry ent = m_textParser->getTextEntry(); |
585 | 7.01k | if (ent.valid()) |
586 | 6.31k | m_textParser->readText(ent); |
587 | 693 | else |
588 | 693 | { |
589 | 693 | WPS_DEBUG_MSG(("WPS8Parser::parse: can not find main text entry\n")); |
590 | 693 | throw (libwps::ParseException()); |
591 | 693 | } |
592 | | |
593 | | #ifdef DEBUG |
594 | | m_tableParser->flushExtra(); |
595 | | #endif |
596 | 6.31k | m_textParser->flushExtra(); |
597 | | #ifdef DEBUG |
598 | | m_graphParser->sendObjects(-1); |
599 | | #endif |
600 | | |
601 | 6.31k | m_listener->endDocument(); |
602 | 6.31k | m_listener.reset(); |
603 | | |
604 | 6.31k | ascii().reset(); |
605 | 6.31k | } |
606 | | |
607 | | // find and create all the zones ( normal/ole ) |
608 | | bool WPS8Parser::createStructures() |
609 | 7.96k | { |
610 | 7.96k | if (!getInput()) return false; |
611 | | |
612 | 7.96k | RVNGInputStreamPtr input = getInput(); |
613 | 7.96k | parseHeaderIndex(); |
614 | | |
615 | | // initialize the text, table, .. |
616 | 7.96k | if (!m_textParser->readStructures()) |
617 | 810 | return false; |
618 | 7.15k | m_graphParser->readStructures(input); |
619 | 7.15k | m_tableParser->readStructures(input); |
620 | | |
621 | | // read DOP zone (document properties) |
622 | 7.15k | auto pos = getNameEntryMap().lower_bound("DOP "); |
623 | 647k | while (getNameEntryMap().end() != pos) |
624 | 647k | { |
625 | 647k | WPSEntry const &entry = pos++->second; |
626 | 647k | if (!entry.hasName("DOP ")) break; |
627 | 640k | if (!entry.hasType("DOP ")) continue; |
628 | | |
629 | 606k | WPSPageSpan page; |
630 | 606k | if (readDocProperties(entry, page)) m_state->m_pageSpan = page; |
631 | 606k | } |
632 | | |
633 | | // printer data |
634 | 7.15k | pos = getNameEntryMap().lower_bound("PRNT"); |
635 | 418k | while (getNameEntryMap().end() != pos) |
636 | 418k | { |
637 | 418k | WPSEntry const &entry = pos++->second; |
638 | 418k | if (!entry.hasName("PRNT")) break; |
639 | 411k | if (!entry.hasType("WNPR")) continue; |
640 | | |
641 | 329k | readWNPR(entry); |
642 | 329k | } |
643 | | |
644 | | // SYID |
645 | 7.15k | pos = getNameEntryMap().lower_bound("SYID"); |
646 | 174k | while (getNameEntryMap().end() != pos) |
647 | 174k | { |
648 | 174k | WPSEntry const &entry = pos++->second; |
649 | 174k | if (!entry.hasName("SYID")) break; |
650 | 167k | if (!entry.hasType("SYID")) continue; |
651 | | |
652 | 106k | std::vector<int> listId; |
653 | 106k | readSYID(entry, listId); |
654 | 106k | } |
655 | | |
656 | | // document title |
657 | 7.15k | pos = getNameEntryMap().find("TITL"); |
658 | 7.15k | librevenge::RVNGString title; |
659 | 7.15k | if (getNameEntryMap().end() != pos && pos->second.hasType("TITL")) |
660 | 1.30k | { |
661 | 1.30k | pos->second.setParsed(true); |
662 | 1.30k | input->seek(pos->second.begin(), librevenge::RVNG_SEEK_SET); |
663 | 1.30k | m_textParser->readString(input, pos->second.length(), title); |
664 | 1.30k | ascii().addPos(pos->second.begin()); |
665 | 1.30k | ascii().addNote(title.cstr()); |
666 | 1.30k | } |
667 | | |
668 | | // ok, we can now read the frame |
669 | 7.15k | pos = getNameEntryMap().lower_bound("FRAM"); |
670 | 801k | while (getNameEntryMap().end() != pos) |
671 | 801k | { |
672 | 801k | WPSEntry const &entry = pos++->second; |
673 | 801k | if (!entry.hasName("FRAM")) break; |
674 | 794k | if (!entry.hasType("FRAM")) continue; |
675 | | |
676 | 695k | readFRAM(entry); |
677 | 695k | } |
678 | | // FRCD |
679 | 7.15k | pos = getNameEntryMap().lower_bound("FRCD"); |
680 | 448k | while (getNameEntryMap().end() != pos) |
681 | 447k | { |
682 | 447k | WPSEntry const &entry = pos++->second; |
683 | 447k | if (!entry.hasName("FRCD")) break; |
684 | 440k | if (!entry.hasType("FRCD")) continue; |
685 | 263k | readFRCD(entry); |
686 | 263k | } |
687 | | |
688 | | // creates the correspondance between the eobj and the frame |
689 | 7.15k | size_t numFrames = m_state->m_frameList.size(); |
690 | 297k | for (size_t i = 0; i < numFrames; i++) |
691 | 290k | { |
692 | 290k | WPS8ParserInternal::Frame const &frame = m_state->m_frameList[i]; |
693 | 290k | if (frame.m_idObject < 0) continue; |
694 | 367 | m_state->m_object2FrameMap[frame.m_idObject] = int(i); |
695 | 367 | m_state->m_table2FrameMap[frame.m_idTable] = int(i); |
696 | 367 | } |
697 | | |
698 | 7.15k | m_graphParser->computePositions(); |
699 | | |
700 | 7.15k | return true; |
701 | 7.96k | } |
702 | | |
703 | | bool WPS8Parser::createOLEStructures() |
704 | 7.96k | { |
705 | 7.96k | RVNGInputStreamPtr input=getFileInput(); |
706 | 7.96k | if (!input) return false; |
707 | | |
708 | 7.96k | if (!input->isStructured()) return true; |
709 | 7.96k | WPSOLEParser oleParser("CONTENTS", libwps_tools_win::Font::WIN3_WEUROPE); |
710 | 7.96k | if (!oleParser.parse(input)) return false; |
711 | | |
712 | 7.96k | m_graphParser->storeObjects(oleParser.getObjectsMap()); |
713 | | #ifdef DEBUG |
714 | | // there can remain some embedded Works subdocument ( WKS, ... ) |
715 | | // with name MN0 and some unknown picture ole |
716 | | auto unparsed = oleParser.getNotParse(); |
717 | | |
718 | | for (std::string const &name : unparsed) |
719 | | { |
720 | | if (name == "CONTENTS") |
721 | | continue; |
722 | | if (name== "SPELLING") |
723 | | { |
724 | | RVNGInputStreamPtr ole(input->getSubStreamByName(name.c_str())); |
725 | | if (ole && readSPELLING(ole, name)) |
726 | | continue; |
727 | | } |
728 | | WPS_DEBUG_MSG(("WPS8Parser::createOLEStructures:: Find unparsed ole: %s\n", name.c_str())); |
729 | | |
730 | | #ifdef DEBUG_WITH_FILES |
731 | | RVNGInputStreamPtr ole(input->getSubStreamByName(name.c_str())); |
732 | | if (!ole.get()) |
733 | | { |
734 | | WPS_DEBUG_MSG(("WPS8Parser::createOLEStructures: error: can find OLE part: \"%s\"\n", name.c_str())); |
735 | | continue; |
736 | | } |
737 | | |
738 | | librevenge::RVNGBinaryData data; |
739 | | if (libwps::readDataToEnd(ole,data)) |
740 | | libwps::Debug::dumpFile(data, name.c_str()); |
741 | | #endif |
742 | | } |
743 | | #endif |
744 | 7.96k | return true; |
745 | 7.96k | } |
746 | | |
747 | | //////////////////////////////////////////////////////////// |
748 | | // send the frames which correspond to a page |
749 | | //////////////////////////////////////////////////////////// |
750 | | void WPS8Parser::sendPageFrames() |
751 | 7.01k | { |
752 | 7.01k | if (!m_listener) return; |
753 | | |
754 | 7.01k | RVNGInputStreamPtr input = getInput(); |
755 | 7.01k | long actPos = input->tell(); |
756 | | |
757 | 7.01k | for (auto const &frame : m_state->m_frameList) |
758 | 290k | { |
759 | 290k | if (frame.m_parsed) continue; |
760 | 290k | if (frame.m_pos.page() < 0 || frame.m_idObject != -1) continue; |
761 | 268k | if (frame.m_pos.size()[0] <= 0 || frame.m_pos.size()[1] <= 0) continue; |
762 | | |
763 | 62.5k | WPSPosition pos(frame.m_pos); |
764 | 62.5k | if (pos.origin().y() < 0 || pos.origin().x() < 0) |
765 | 39.8k | { |
766 | 39.8k | if (frame.m_type == WPS8ParserInternal::Frame::DbField) continue; |
767 | | // FIXME: the |
768 | 30.9k | WPS_DEBUG_MSG(("WPS8Parser::insertPageFrames: origin is too small\n")); |
769 | 30.9k | Vec2f orig = pos.origin(); |
770 | 30.9k | orig += Vec2f(float(m_state->m_pageSpan.getMarginLeft()), |
771 | 30.9k | float(m_state->m_pageSpan.getMarginTop())); |
772 | 30.9k | pos.setOrigin(orig); |
773 | 30.9k | } |
774 | 53.7k | pos.m_anchorTo = WPSPosition::Page; |
775 | 53.7k | pos.m_wrapping = WPSPosition::WDynamic; |
776 | 53.7k | frame.m_parsed = true; |
777 | 53.7k | if (frame.m_type == WPS8ParserInternal::Frame::Object) |
778 | 6.46k | m_graphParser->sendObject(pos, frame.m_idOle, true); |
779 | 47.2k | else if (frame.m_type == WPS8ParserInternal::Frame::Text) |
780 | 11.8k | { |
781 | 11.8k | librevenge::RVNGPropertyList frameExtras; |
782 | 11.8k | if (!frame.m_backgroundColor.isWhite()) |
783 | 2.80k | frameExtras.insert("fo:background-color", frame.m_backgroundColor.str().c_str()); |
784 | 11.8k | sendTextBox(pos, frame.m_idStrs, frameExtras); |
785 | 11.8k | } |
786 | 35.3k | else if (frame.m_type != WPS8ParserInternal::Frame::Header && frame.m_type != WPS8ParserInternal::Frame::Footer) |
787 | 26.0k | { |
788 | 26.0k | WPS_DEBUG_MSG(("WPS8Parser::insertPageFrames: not implemented type%d\n", int(frame.m_type))); |
789 | 26.0k | } |
790 | 53.7k | } |
791 | | |
792 | 7.01k | input->seek(actPos,librevenge::RVNG_SEEK_SET); |
793 | 7.01k | } |
794 | | |
795 | | //////////////////////////////////////////////////////////// |
796 | | // read the index |
797 | | bool WPS8Parser::parseHeaderIndexEntry() |
798 | 37.1M | { |
799 | 37.1M | RVNGInputStreamPtr input = getInput(); |
800 | 37.1M | long pos = input->tell(); |
801 | 37.1M | ascii().addPos(pos); |
802 | | |
803 | 37.1M | libwps::DebugStream f; |
804 | | |
805 | 37.1M | uint16_t cch = libwps::readU16(input); |
806 | | |
807 | | // check if the entry can be read |
808 | 37.1M | input->seek(pos + cch, librevenge::RVNG_SEEK_SET); |
809 | 37.1M | if (input->tell() != pos+cch) |
810 | 2.10k | { |
811 | 2.10k | WPS_DEBUG_MSG(("WPS8Parser::parseHeaderIndexEntry: error: incomplete entry\n")); |
812 | 2.10k | ascii().addNote("###IndexEntry incomplete (ignored)"); |
813 | 2.10k | return false; |
814 | 2.10k | } |
815 | 37.1M | input->seek(pos + 2, librevenge::RVNG_SEEK_SET); |
816 | | |
817 | 37.1M | if (0x18 != cch) |
818 | 1.05M | { |
819 | 1.05M | if (cch < 0x18) |
820 | 114k | { |
821 | 114k | input->seek(pos + cch, librevenge::RVNG_SEEK_SET); |
822 | 114k | ascii().addNote("###IndexEntry too short(ignored)"); |
823 | 114k | if (cch < 10) throw libwps::ParseException(); |
824 | 114k | return true; |
825 | 114k | } |
826 | 1.05M | } |
827 | | |
828 | 37.0M | std::string name; |
829 | | |
830 | | // sanity check |
831 | 37.0M | int i; |
832 | 175M | for (i =0; i < 4; i++) |
833 | 141M | { |
834 | 141M | uint8_t c = libwps::readU8(input); |
835 | 141M | name.append(1, char(c)); |
836 | | |
837 | 141M | if (c != 0 && c != 0x20 && (41 > c || c > 90)) |
838 | 3.78M | { |
839 | 3.78M | WPS_DEBUG_MSG(("WPS8Parser::parseHeaderIndexEntry: error: bad character=%u (0x%02x) in name in header index\n", unsigned(c), unsigned(c))); |
840 | 3.78M | ascii().addNote("###IndexEntry bad name(ignored)"); |
841 | | |
842 | 3.78M | input->seek(pos + cch, librevenge::RVNG_SEEK_SET); |
843 | 3.78M | return true; |
844 | 3.78M | } |
845 | 141M | } |
846 | | |
847 | 33.2M | f << "Entries("<<name<<")"; |
848 | 33.2M | if (cch != 24) f << ", #size=" << int(cch); |
849 | 33.2M | auto id = int(libwps::readU16(input)); |
850 | 33.2M | f << ", id=" << id << ", ("; |
851 | 99.8M | for (i = 0; i < 2; i ++) |
852 | 66.5M | { |
853 | 66.5M | auto val = int(libwps::read16(input)); |
854 | 66.5M | f << val << ","; |
855 | 66.5M | } |
856 | | |
857 | 33.2M | std::string name2; |
858 | 166M | for (i =0; i < 4; i++) |
859 | 133M | name2.append(1, char(libwps::readU8(input))); |
860 | 33.2M | f << "), " << name2; |
861 | | |
862 | 33.2M | WPSEntry hie; |
863 | 33.2M | hie.setName(name); |
864 | 33.2M | hie.setType(name2); |
865 | 33.2M | hie.setId(id); |
866 | 33.2M | hie.setBegin(long(libwps::readU32(input))); |
867 | 33.2M | hie.setLength(long(libwps::readU32(input))); |
868 | | |
869 | 33.2M | f << ", offset=" << std::hex << hie.begin() << ", length=" << hie.length(); |
870 | | |
871 | 33.2M | std::string mess; |
872 | 33.2M | if (cch != 0x18 && parseHeaderIndexEntryEnd(pos+cch, hie, mess)) |
873 | 599k | f << "," << mess; |
874 | | |
875 | 33.2M | input->seek(hie.end(), librevenge::RVNG_SEEK_SET); |
876 | 33.2M | if (input->tell() != hie.end()) |
877 | 11.7M | { |
878 | 11.7M | f << ", ###ignored"; |
879 | 11.7M | ascii().addNote(f.str().c_str()); |
880 | 11.7M | input->seek(pos + cch, librevenge::RVNG_SEEK_SET); |
881 | 11.7M | return true; |
882 | 11.7M | } |
883 | | |
884 | 21.5M | getNameEntryMap().insert(NameMultiMap::value_type(name, hie)); |
885 | | |
886 | 21.5M | ascii().addPos(pos); |
887 | 21.5M | ascii().addNote(f.str().c_str()); |
888 | | |
889 | 21.5M | ascii().addPos(hie.begin()); |
890 | 21.5M | f.str(""); |
891 | 21.5M | f << name; |
892 | 21.5M | if (name != name2) f << "/" << name2; |
893 | 21.5M | f << ":" << std::dec << id; |
894 | 21.5M | ascii().addNote(f.str().c_str()); |
895 | | |
896 | 21.5M | ascii().addPos(hie.end()); |
897 | 21.5M | ascii().addNote("_"); |
898 | | |
899 | 21.5M | input->seek(pos + cch, librevenge::RVNG_SEEK_SET); |
900 | 21.5M | return true; |
901 | 33.2M | } |
902 | | |
903 | | // |
904 | | // read the end the entry index: normally a string name |
905 | | // |
906 | | bool WPS8Parser::parseHeaderIndexEntryEnd(long endPos, WPSEntry &hie, std::string &mess) |
907 | 599k | { |
908 | 599k | RVNGInputStreamPtr input = getInput(); |
909 | | |
910 | 599k | long pos = input->tell(); |
911 | 599k | long len = endPos-pos; |
912 | 599k | libwps::DebugStream f; |
913 | | |
914 | 599k | auto size = int(libwps::read16(input)); |
915 | 599k | librevenge::RVNGString str; |
916 | 599k | if (2*(size+1) != len || !m_textParser->readString(input, 2*size, str)) |
917 | 557k | { |
918 | 557k | WPS_DEBUG_MSG(("WPS8Parser::parseHeaderIndexEntryEnd: unknown data\n")); |
919 | 557k | ascii().addPos(pos); |
920 | 557k | ascii().addNote("Entry(end): ###ignored"); |
921 | 557k | } |
922 | 41.9k | else |
923 | 41.9k | { |
924 | 41.9k | hie.setExtra(str.cstr()); |
925 | 41.9k | f << "'" << str.cstr() << "'"; |
926 | 41.9k | mess = f.str(); |
927 | 41.9k | } |
928 | 599k | return true; |
929 | 599k | } |
930 | | |
931 | | /** |
932 | | * In the header, parse the index to the different sections of |
933 | | * the CONTENTS stream. |
934 | | * |
935 | | */ |
936 | | bool WPS8Parser::parseHeaderIndex() |
937 | 7.96k | { |
938 | 7.96k | RVNGInputStreamPtr input = getInput(); |
939 | 7.96k | getNameEntryMap().clear(); |
940 | 7.96k | input->seek(0x08, librevenge::RVNG_SEEK_SET); |
941 | | |
942 | 7.96k | long pos = input->tell(); |
943 | 7.96k | auto i0 = int(libwps::read16(input)); |
944 | 7.96k | auto i1 = int(libwps::read16(input)); |
945 | 7.96k | uint16_t n_entries = libwps::readU16(input); |
946 | | // fixme: sanity check n_entries |
947 | | |
948 | 7.96k | libwps::DebugStream f; |
949 | 7.96k | f << "Entries(HeaderZ): N=" << n_entries << ", " << i0 << ", " << i1 << "("; |
950 | | |
951 | 39.8k | for (int i = 0; i < 4; i++) |
952 | 31.8k | f << std::hex << libwps::read16(input) << std::dec << ","; |
953 | 7.96k | f << "), "; |
954 | 7.96k | f << "unk=" << std::hex <<libwps::read16(input) << std::dec << ","; |
955 | | |
956 | 7.96k | ascii().addPos(pos); |
957 | 7.96k | ascii().addNote(f.str().c_str()); |
958 | | |
959 | 7.96k | input->seek(0x18, librevenge::RVNG_SEEK_SET); |
960 | 7.96k | bool readSome = false; |
961 | 7.96k | do |
962 | 3.98M | { |
963 | 3.98M | if (input->isEnd()) return readSome; |
964 | | |
965 | 3.98M | pos = input->tell(); |
966 | 3.98M | f.str(""); |
967 | 3.98M | uint16_t unknown1 = libwps::readU16(input); // function of the size of the entries ? |
968 | | |
969 | 3.98M | uint16_t n_entries_local = libwps::readU16(input); |
970 | 3.98M | f << "HeaderZ("<<std::hex << unknown1<<"): N=" << std::dec << n_entries_local; |
971 | | |
972 | 3.98M | if (n_entries_local > 0x20) |
973 | 529 | { |
974 | 529 | WPS_DEBUG_MSG(("WPS8Parser::parseHeaderIndex: error: n_entries_local=%i\n", n_entries_local)); |
975 | 529 | return readSome; |
976 | 529 | } |
977 | | |
978 | 3.98M | uint32_t next_index_table = libwps::readU32(input); |
979 | 3.98M | f << std::hex << ", nextHeader=" << next_index_table; |
980 | 3.98M | if (next_index_table != 0xFFFFFFFF && long(next_index_table) < pos) |
981 | 212 | { |
982 | 212 | WPS_DEBUG_MSG(("WPS8Parser::parseHeaderIndex: error: next_index_table=%x decreasing !!!\n", next_index_table)); |
983 | 212 | return readSome; |
984 | 212 | } |
985 | | |
986 | 3.98M | ascii().addPos(pos); |
987 | 3.98M | ascii().addNote(f.str().c_str()); |
988 | | |
989 | 3.98M | do |
990 | 37.1M | { |
991 | 37.1M | if (!parseHeaderIndexEntry()) return readSome; |
992 | | |
993 | 37.1M | readSome=true; |
994 | 37.1M | n_entries--; |
995 | 37.1M | n_entries_local--; |
996 | 37.1M | } |
997 | 37.1M | while (n_entries > 0 && n_entries_local); |
998 | | |
999 | 3.98M | if (0xFFFFFFFF == next_index_table && n_entries > 0) |
1000 | 134 | { |
1001 | 134 | WPS_DEBUG_MSG(("WPS8Parser::parseHeaderIndex: error: expected more header index entries\n")); |
1002 | 134 | return true; |
1003 | 134 | } |
1004 | | |
1005 | 3.98M | if (0xFFFFFFFF == next_index_table) break; |
1006 | | |
1007 | 3.98M | if (input->seek(long(next_index_table), librevenge::RVNG_SEEK_SET) != 0) return readSome; |
1008 | 3.98M | } |
1009 | 3.98M | while (n_entries > 0); |
1010 | | |
1011 | 4.58k | return true; |
1012 | 7.96k | } |
1013 | | |
1014 | | //////////////////////////////////////////////////////////// |
1015 | | // low level |
1016 | | //////////////////////////////////////////////////////////// |
1017 | | // read DOP zone: the document properties |
1018 | | bool WPS8Parser::readDocProperties(WPSEntry const &entry, WPSPageSpan &page) |
1019 | 606k | { |
1020 | 606k | if (!entry.hasType(entry.name())) |
1021 | 0 | { |
1022 | 0 | WPS_DEBUG_MSG(("WPS8Parser::readDocProperties: warning: DOP name=%s, type=%s\n", |
1023 | 0 | entry.name().c_str(), entry.type().c_str())); |
1024 | 0 | return false; |
1025 | 0 | } |
1026 | | |
1027 | 606k | RVNGInputStreamPtr input = getInput(); |
1028 | 606k | page=WPSPageSpan(); |
1029 | | |
1030 | 606k | long page_offset = entry.begin(); |
1031 | 606k | long length = entry.length(); |
1032 | 606k | long endPage = entry.end(); |
1033 | | |
1034 | 606k | if (length < 2) |
1035 | 74.9k | { |
1036 | 74.9k | WPS_DEBUG_MSG(("WPS8Parser::readDocProperties: warning: DOP length=0x%lx\n", static_cast<unsigned long>(length))); |
1037 | 74.9k | return false; |
1038 | 74.9k | } |
1039 | | |
1040 | 531k | entry.setParsed(); |
1041 | 531k | input->seek(page_offset, librevenge::RVNG_SEEK_SET); |
1042 | | |
1043 | 531k | libwps::DebugStream f, f2; |
1044 | 531k | if (libwps::read16(input) != length) |
1045 | 124k | { |
1046 | 124k | WPS_DEBUG_MSG(("WPS8Parser::readDocProperties: invalid length=%ld\n", length)); |
1047 | 124k | return false; |
1048 | 124k | } |
1049 | | |
1050 | 406k | WPS8Struct::FileData mainData; |
1051 | 406k | std::string error; |
1052 | 406k | bool readOk = readBlockData(input, endPage,mainData, error); |
1053 | | |
1054 | 406k | double dim[8] = {0, 0, 0, 0, 0, 0, 0, 0}; |
1055 | 406k | bool setVal[8] = { false, false, false, false, false, false, false, false}; |
1056 | 406k | for (auto const &dt : mainData.m_recursData) |
1057 | 2.25M | { |
1058 | 2.25M | if (dt.isBad()) continue; |
1059 | 2.25M | if (m_state->m_docPropertyTypes.find(dt.id())==m_state->m_docPropertyTypes.end()) |
1060 | 168k | { |
1061 | 168k | f << "##" << dt << ","; |
1062 | 168k | continue; |
1063 | 168k | } |
1064 | 2.08M | if (m_state->m_docPropertyTypes.find(dt.id())->second != dt.type()) |
1065 | 196k | { |
1066 | 196k | WPS_DEBUG_MSG(("WPS8Parser::readDocProperties: unexpected type for %d=%d\n", dt.id(), dt.type())); |
1067 | 196k | f << "###" << dt << ","; |
1068 | 196k | continue; |
1069 | 196k | } |
1070 | | // is dt.id()==6 another dimension ? |
1071 | 1.88M | if (dt.id() >= 0 && (dt.id() < 6 || dt.id()==7)) |
1072 | 401k | { |
1073 | 401k | dim[dt.id()] = double(dt.m_value)/914400; |
1074 | 401k | setVal[dt.id()] = true; |
1075 | 401k | continue; |
1076 | 401k | } |
1077 | 1.48M | bool ok = true; |
1078 | 1.48M | switch (dt.id()) |
1079 | 1.48M | { |
1080 | 7 | case 0x8: |
1081 | 7 | if (!dt.m_value) break; |
1082 | 6 | if (dt.m_value >= 1 && dt.m_value <= 13) |
1083 | 5 | m_state->m_numColumns = int(1+dt.m_value); |
1084 | 1 | else |
1085 | 1 | f2 << "#"; |
1086 | 6 | f2 << "numCols=" << dt.m_value+1 << ","; |
1087 | 6 | break; |
1088 | 338k | case 0x18: |
1089 | 338k | switch (dt.m_value) |
1090 | 338k | { |
1091 | 6.24k | case 1: |
1092 | 6.24k | break; // portrait |
1093 | 187k | case 2: |
1094 | 187k | page.setFormOrientation(WPSPageSpan::LANDSCAPE); |
1095 | 187k | f2 << "landscape,"; |
1096 | 187k | break; |
1097 | 144k | default: |
1098 | 144k | f2 << "#pageOrientation=" << dt.m_value << ","; |
1099 | 144k | break; |
1100 | 338k | } |
1101 | 338k | break; |
1102 | 338k | case 0x1b: // [-1,0,1,3,4] |
1103 | 0 | f2 << "f" << dt.id() << "=" << int(int8_t(dt.m_value)) << ","; |
1104 | 0 | break; |
1105 | 0 | case 0x13: // an entries index, always an IBGF ? |
1106 | 0 | m_state->m_background.setName(dt.m_text); |
1107 | 0 | m_state->m_background.setId(int(dt.m_value)); |
1108 | 0 | f2 << "background(entries)='" << dt.m_text << "':" << dt.m_value << ","; |
1109 | 0 | break; |
1110 | 0 | case 0x15: // another entries index, always an 'BDR '? |
1111 | 0 | WPS_DEBUG_MSG(("WPS8Parser::readDocProperties: find a BDR entry, not implemented\n")); |
1112 | 0 | f2 << "pageBorder(entries)='" << dt.m_text << "':" << dt.m_value << ","; |
1113 | 0 | break; |
1114 | 341k | case 0xa: |
1115 | 341k | if (dt.isTrue()) f2 << "colSep(line),"; |
1116 | 341k | break; |
1117 | 326k | case 0x19: // almost always set |
1118 | 326k | if (dt.isFalse()) |
1119 | 0 | f2 << "f" << dt.id() << "=false,"; |
1120 | 326k | else |
1121 | 326k | f2 << "f" << dt.id() << ","; |
1122 | 326k | break; |
1123 | 7 | case 0x1c: // 0.1 |
1124 | 7 | f2 << "colSep=" << float(dt.m_value)/914400.f << "(inch),"; |
1125 | 7 | break; |
1126 | 339k | case 0x28: // main language ? |
1127 | 339k | f2 << "lang?=" << libwps_tools_win::Language::name(dt.m_value) << ","; |
1128 | 339k | m_state->m_localeLanguage = libwps_tools_win::Language::localeName(dt.m_value); |
1129 | 339k | break; |
1130 | 0 | case 0x1e: // -3, 47 ou 85 |
1131 | 168 | case 0x29: // 1 ou 2 |
1132 | 168 | f2 << "f" << dt.id() << "=" << dt.m_value << ","; |
1133 | 168 | break; |
1134 | | // 0x2a: an integer = 4|6|b |
1135 | | // 0x2b: an integer = 0|8|c |
1136 | 0 | case 0x2c: |
1137 | 0 | { |
1138 | 0 | if (dt.isRead() || !dt.isArray()) |
1139 | 0 | { |
1140 | 0 | ok = false; |
1141 | 0 | break; |
1142 | 0 | } |
1143 | 0 | auto size = int(dt.end()-dt.begin()); |
1144 | 0 | if (size < 2 || size%2 != 0) |
1145 | 0 | { |
1146 | 0 | ok = false; |
1147 | 0 | break; |
1148 | 0 | } |
1149 | 0 | long actPos = input->tell(); |
1150 | 0 | int numElt = (size-2)/2; |
1151 | |
|
1152 | 0 | input->seek(dt.begin()+2, librevenge::RVNG_SEEK_SET); |
1153 | 0 | std::string str; |
1154 | 0 | int elt=0; |
1155 | 0 | while (elt < numElt) |
1156 | 0 | { |
1157 | 0 | long val = libwps::read16(input); |
1158 | 0 | if (val < 30 && val != '\t' && val != '\n') |
1159 | 0 | { |
1160 | 0 | input->seek(-2, librevenge::RVNG_SEEK_CUR); |
1161 | 0 | break; |
1162 | 0 | } |
1163 | 0 | elt++; |
1164 | 0 | str += char(val); |
1165 | 0 | } |
1166 | 0 | if (!str.length()) |
1167 | 0 | { |
1168 | 0 | ok = false; |
1169 | 0 | input->seek(actPos, librevenge::RVNG_SEEK_SET); |
1170 | 0 | break; |
1171 | 0 | } |
1172 | 0 | f2 << "filename?=["; // wkthmLET.fmt and wkthmSCH.fmt |
1173 | 0 | if (str.length()) f2 << "\"" << str << "\","; |
1174 | 0 | numElt -= elt; |
1175 | 0 | elt=0; |
1176 | 0 | while (elt++ < numElt) |
1177 | 0 | { |
1178 | 0 | auto val = long(libwps::readU16(input)); |
1179 | 0 | if (val) f2 << "f" << elt << "=" << std::hex << val << std::dec << ","; |
1180 | 0 | } |
1181 | 0 | f2 << "],"; |
1182 | 0 | input->seek(actPos, librevenge::RVNG_SEEK_SET); |
1183 | 0 | break; |
1184 | 0 | } |
1185 | 0 | case 0x2d: |
1186 | 0 | case 0x2e: |
1187 | 0 | { |
1188 | | // In one file with unk2d=[f1=20,], unk2e=[f2=20,] |
1189 | 0 | if (dt.isRead() || !dt.isArray()) |
1190 | 0 | { |
1191 | 0 | ok = false; |
1192 | 0 | break; |
1193 | 0 | } |
1194 | 0 | auto size = int(dt.end()-dt.begin()); |
1195 | 0 | if (size != 0x100) |
1196 | 0 | { |
1197 | 0 | ok = false; |
1198 | 0 | break; |
1199 | 0 | } |
1200 | 0 | long actPos = input->tell(); |
1201 | 0 | input->seek(dt.begin(), librevenge::RVNG_SEEK_SET); |
1202 | 0 | f2 << "unk" << std::hex << dt.id() << "=" << "["; |
1203 | 0 | for (int i = 0; i < 128; i++) |
1204 | 0 | { |
1205 | 0 | auto val = long(libwps::readU16(input)); |
1206 | 0 | if (val) f2 << "f" << i << "=" << std::hex << val << std::dec << ","; |
1207 | 0 | } |
1208 | 0 | f2 << "]" << std::dec << ","; |
1209 | 0 | input->seek(actPos, librevenge::RVNG_SEEK_SET); |
1210 | 0 | break; |
1211 | 0 | } |
1212 | | |
1213 | 141k | default: |
1214 | 141k | ok = false; |
1215 | 141k | break; |
1216 | 1.48M | } |
1217 | 1.48M | if (ok) continue; |
1218 | 141k | f2 << dt << ","; |
1219 | 141k | } |
1220 | 406k | if (setVal[0]) |
1221 | 10.2k | { |
1222 | 10.2k | if (dim[0] < 0.5 || dim[0] > 40) f << "###"; |
1223 | 3.15k | else page.setFormWidth(dim[0]); |
1224 | 10.2k | f << "width=" << dim[0] << ","; |
1225 | 10.2k | } |
1226 | 406k | if (setVal[1]) |
1227 | 16.9k | { |
1228 | 16.9k | if (dim[1] < 0.5 || dim[1] > 40) f << "###"; |
1229 | 4.16k | else page.setFormLength(dim[1]); |
1230 | 16.9k | f << "height=" << dim[1] << ","; |
1231 | 16.9k | } |
1232 | 406k | f << "margin=["; |
1233 | 2.03M | for (int i = 2; i < 6; i++) |
1234 | 1.62M | { |
1235 | 1.62M | if (!setVal[i]) |
1236 | 1.41M | { |
1237 | 1.41M | f << "_,"; |
1238 | 1.41M | continue; |
1239 | 1.41M | } |
1240 | 214k | int w = i%2; |
1241 | 214k | double dd = w ? page.getFormWidth() : page.getFormLength(); |
1242 | 214k | bool ok = (dim[i] >= 0) && (2*dim[i] < dd); |
1243 | 214k | switch (i) |
1244 | 214k | { |
1245 | 17.3k | case 2: |
1246 | 17.3k | if (ok) page.setMarginTop(dim[i]); |
1247 | 17.3k | break; |
1248 | 13.8k | case 3: |
1249 | 13.8k | if (ok) page.setMarginLeft(dim[i]); |
1250 | 13.8k | break; |
1251 | 17.3k | case 4: |
1252 | 17.3k | if (ok) page.setMarginBottom(dim[i]); |
1253 | 17.3k | break; |
1254 | 166k | case 5: |
1255 | 166k | if (ok) page.setMarginRight(dim[i]); |
1256 | 166k | break; |
1257 | 0 | default: |
1258 | 0 | break; |
1259 | 214k | } |
1260 | 214k | if (!ok) f << "###"; |
1261 | 214k | f << dim[i] << ","; |
1262 | 214k | } |
1263 | 406k | f << "],"; |
1264 | 406k | if (setVal[7]) f << "bordDim?=" << dim[7] << ","; |
1265 | 406k | f << f2.str(); |
1266 | | |
1267 | 406k | if (!readOk) f << "###or [" << mainData << "]"; |
1268 | | |
1269 | 406k | ascii().addPos(page_offset); |
1270 | 406k | ascii().addNote(f.str().c_str()); |
1271 | | |
1272 | 406k | return true; |
1273 | 406k | } |
1274 | | |
1275 | | /** Frame zone: ie a zone which can contains text, picture, ... |
1276 | | and have some border */ |
1277 | | bool WPS8Parser::readFRAM(WPSEntry const &entry) |
1278 | 695k | { |
1279 | 695k | typedef WPS8ParserInternal::Frame Frame; |
1280 | 695k | libwps::DebugStream f; |
1281 | 695k | if (!entry.hasType(entry.name())) |
1282 | 0 | { |
1283 | 0 | WPS_DEBUG_MSG(("WPS8Parser::readFRAM warning: name=%s, type=%s\n", |
1284 | 0 | entry.name().c_str(), entry.type().c_str())); |
1285 | 0 | return false; |
1286 | 0 | } |
1287 | 695k | RVNGInputStreamPtr input = getInput(); |
1288 | | |
1289 | 695k | long page_offset = entry.begin(); |
1290 | 695k | long length = entry.length(); |
1291 | 695k | long endPage = entry.end(); |
1292 | | |
1293 | 695k | if (length < 2) |
1294 | 12.8k | { |
1295 | 12.8k | WPS_DEBUG_MSG(("WPS8Parser::readFRAM warning: length=0x%lx\n", static_cast<unsigned long>(length))); |
1296 | 12.8k | return false; |
1297 | 12.8k | } |
1298 | | |
1299 | 682k | entry.setParsed(); |
1300 | 682k | input->seek(page_offset, librevenge::RVNG_SEEK_SET); |
1301 | | |
1302 | 682k | int numFram = libwps::read16(input); |
1303 | 682k | if (numFram < 0 || numFram*2 > length) |
1304 | 205k | { |
1305 | 205k | WPS_DEBUG_MSG(("WPS8Parser::readFRAM warning: length=0x%lx, num=%d\n", static_cast<unsigned long>(length), numFram)); |
1306 | 205k | return false; |
1307 | 205k | } |
1308 | 476k | f << "N=" << numFram; |
1309 | | |
1310 | 476k | ascii().addPos(page_offset); |
1311 | 476k | ascii().addNote(f.str().c_str()); |
1312 | | |
1313 | | |
1314 | 476k | bool parsedAll = true, color = false; |
1315 | 476k | long lastPos=input->tell(); // uneeded initialization but makes clang analyser happier |
1316 | 767k | for (int i = 0; i < numFram; i++) |
1317 | 451k | { |
1318 | 451k | lastPos = input->tell(); |
1319 | 451k | if (lastPos+2 > endPage) |
1320 | 12.7k | { |
1321 | 12.7k | parsedAll = false; |
1322 | 12.7k | break; |
1323 | 12.7k | } |
1324 | 438k | int sz = libwps::read16(input); |
1325 | 438k | if (sz < 2 || lastPos + sz > endPage) |
1326 | 148k | { |
1327 | 148k | parsedAll = false; |
1328 | 148k | break; |
1329 | 148k | } |
1330 | | |
1331 | 290k | WPS8Struct::FileData mainData; |
1332 | 290k | std::string error; |
1333 | 290k | bool readOk = readBlockData(input, lastPos + sz, mainData, error); |
1334 | | |
1335 | 290k | double dim[3] = {0, 0, 0}; |
1336 | 290k | bool setVal[3] = { false, false, false}; |
1337 | | |
1338 | 290k | double bDim[4] = {0, 0, 0, 0}; |
1339 | 290k | bool bset = false, bsetVal[4] = { false, false, false, false}; |
1340 | 290k | libwps::DebugStream f2; |
1341 | | |
1342 | 290k | Frame frame; |
1343 | 290k | int lastPage = 0; |
1344 | 290k | Vec2f minP, sizeP; |
1345 | 290k | for (auto const &dt : mainData.m_recursData) |
1346 | 1.10M | { |
1347 | 1.10M | if (dt.isBad()) continue; |
1348 | 1.10M | if (m_state->m_frameTypes.find(dt.id())==m_state->m_frameTypes.end()) |
1349 | 82.1k | { |
1350 | 82.1k | WPS_DEBUG_MSG(("WPS8Parser::readFRAM: unexpected id for %d\n", dt.id())); |
1351 | 82.1k | f2 << "##" << dt << ","; |
1352 | 82.1k | continue; |
1353 | 82.1k | } |
1354 | 1.02M | if (m_state->m_frameTypes.find(dt.id())->second != dt.type()) |
1355 | 116k | { |
1356 | 116k | WPS_DEBUG_MSG(("WPS8Parser::readFRAM: unexpected type for %d=%d\n", dt.id(), dt.type())); |
1357 | 116k | f2 << "###" << dt << ","; |
1358 | 116k | continue; |
1359 | 116k | } |
1360 | 904k | if (dt.id() >= 4 && dt.id() < 11) |
1361 | 439k | { |
1362 | 439k | switch (dt.id()) |
1363 | 439k | { |
1364 | 94.1k | case 4: |
1365 | 94.1k | minP.setX(float(dt.m_value)/914400.f); |
1366 | 94.1k | break; |
1367 | 71.8k | case 5: |
1368 | 71.8k | minP.setY(float(dt.m_value)/914400.f); |
1369 | 71.8k | break; |
1370 | 115k | case 6: |
1371 | 115k | sizeP.setX(float(dt.m_value)/914400.f); |
1372 | 115k | break; |
1373 | 86.9k | case 7: |
1374 | 86.9k | sizeP.setY(float(dt.m_value)/914400.f); |
1375 | 86.9k | break; |
1376 | 70.9k | default: |
1377 | 70.9k | dim[dt.id()-8] = double(dt.m_value)/914400; |
1378 | 70.9k | setVal[dt.id()-8] = true; |
1379 | 70.9k | break; |
1380 | 439k | } |
1381 | 439k | continue; |
1382 | 439k | } |
1383 | | |
1384 | 465k | bool ok = true; |
1385 | 465k | switch (dt.id()) |
1386 | 465k | { |
1387 | 153k | case 0: |
1388 | 153k | { |
1389 | 153k | int page = int16_t(dt.m_value); |
1390 | | // try to avoid creating to many page |
1391 | 153k | if (page > lastPage+100) |
1392 | 84.9k | { |
1393 | 84.9k | ok = false; |
1394 | 84.9k | break; |
1395 | 84.9k | } |
1396 | 68.2k | frame.m_pos.setPage(page > 0 ? page+1 : page); |
1397 | 68.2k | if (page > lastPage) lastPage = page; |
1398 | 68.2k | break; |
1399 | 153k | } |
1400 | 129k | case 1: |
1401 | 129k | switch (dt.m_value) |
1402 | 129k | { |
1403 | | // associated with mailing database with 0x16 |
1404 | 9.31k | case 4: |
1405 | 9.31k | frame.m_type = Frame::DbField; |
1406 | 9.31k | break; |
1407 | | // associated with 0x13=22:[0|96], 0x18,1b=0x41,0x2e, rarely with 0x1a |
1408 | 9.78k | case 6: |
1409 | 9.78k | frame.m_type = Frame::Header; |
1410 | 9.78k | break; |
1411 | | // associated with 0x13=22:[0|96],0x18,1b=0x41,0x2e, rarely with 0x1a |
1412 | 8.51k | case 7: |
1413 | 8.51k | frame.m_type = Frame::Footer; |
1414 | 8.51k | break; |
1415 | | |
1416 | | // does the following correspond to page, column, char position ? |
1417 | | |
1418 | | // associated with 0x11=(m_idOle,0,1), 0x2e=? |
1419 | 35.4k | case 8: |
1420 | 35.4k | frame.m_type = Frame::Object; |
1421 | 35.4k | break; |
1422 | | // associated with 0x18=?, 0x46=? and often with a BDR entry |
1423 | | // CHECKME: seems also associated to a MCLD, how ? |
1424 | 17.8k | case 9: |
1425 | 17.8k | frame.m_type = Frame::Text; |
1426 | 17.8k | break; |
1427 | | // associated with f3 and 0x11=(table_id,0,0) and 0x2a=? |
1428 | 39.3k | case 12: |
1429 | 39.3k | frame.m_type = Frame::Table; |
1430 | 39.3k | break; |
1431 | | |
1432 | 9.51k | default: |
1433 | 9.51k | f2 << "###type=" << dt.m_value << ","; |
1434 | 9.51k | break; |
1435 | 129k | } |
1436 | 129k | break; |
1437 | 129k | case 0x2: |
1438 | 1 | if (dt.m_value&1) f2 << "noText[right],"; |
1439 | 1 | if (dt.m_value&2) f2 << "noText[left],"; |
1440 | 1 | if (dt.m_value&0xFC) f2 << "#f2=" << std::hex << (dt.m_value&0xFC) << ","; |
1441 | 1 | break; |
1442 | 542 | case 0x3: // seem to exist iff type=12 |
1443 | 542 | if ((frame.m_type == Frame::Table) != dt.isTrue()) |
1444 | 44 | f2 << "isTable?[" |
1445 | 44 | << (dt.isTrue() ? "true" : "false") << "],"; |
1446 | 542 | break; |
1447 | 0 | case 0x10: // an entry index always a BDR ? |
1448 | 0 | frame.m_idBorder.setName(dt.m_text); |
1449 | 0 | frame.m_idBorder.setId(int(dt.m_value)); |
1450 | 0 | break; |
1451 | 535 | case 0x11: // a list of 3 int32 ? Only the first is signifiant ? |
1452 | 535 | { |
1453 | 535 | if (dt.isRead() || !dt.isArray()) |
1454 | 9 | { |
1455 | 9 | ok = false; |
1456 | 9 | break; |
1457 | 9 | } |
1458 | 526 | auto size = int(dt.end()-dt.begin()); |
1459 | 526 | if (size < 2 || (size+2)%4 != 0) |
1460 | 6 | { |
1461 | 6 | ok = false; |
1462 | 6 | break; |
1463 | 6 | } |
1464 | 520 | int numElt = (size-2)/4; |
1465 | 520 | long actPos = input->tell(); |
1466 | | |
1467 | 520 | input->seek(dt.begin()+2, librevenge::RVNG_SEEK_SET); |
1468 | 520 | std::vector<long> values; |
1469 | 2.14k | for (int elt = 0; elt < numElt; elt++) |
1470 | 1.62k | { |
1471 | 1.62k | long val = libwps::read32(input); |
1472 | 1.62k | values.push_back(val); |
1473 | 1.62k | } |
1474 | | |
1475 | 520 | bool canHaveId = frame.m_type==Frame::Table || frame.m_type==Frame::Object; |
1476 | 520 | if (canHaveId && numElt == 3 && values[1] == 0 && values[2] ==0) |
1477 | 367 | frame.m_idObject = int(values[0]); |
1478 | 153 | else if (canHaveId && numElt == 3 && values[1] == 0 && values[2] == 1) |
1479 | 3 | frame.m_idOle = int(values[0]); |
1480 | 150 | else |
1481 | 150 | { |
1482 | 150 | WPS_DEBUG_MSG(("WPS8Parser::readFRAM unknown field 0x11\n")); |
1483 | 150 | f2 << "###f17=("; |
1484 | 660 | for (int j = 0; j < numElt; j++) f2 << values[size_t(j)] << ","; |
1485 | 150 | f2 << "),"; |
1486 | 150 | } |
1487 | | |
1488 | 520 | input->seek(actPos, librevenge::RVNG_SEEK_SET); |
1489 | 520 | break; |
1490 | 526 | } |
1491 | 0 | case 0x16: // associated with field and database |
1492 | 0 | f2 << "database=" << dt.m_text << ":" << dt.m_value << ","; |
1493 | 0 | break; |
1494 | | // associated with a tex box and field 0x19 |
1495 | 0 | case 0x17: |
1496 | 0 | color = dt.isTrue(); |
1497 | 0 | break; |
1498 | 36.9k | case 0x18: |
1499 | 36.9k | { |
1500 | 36.9k | if (dt.m_value < 0 || dt.m_value >= m_textParser->getNumTextZones()) |
1501 | 31.0k | { |
1502 | 31.0k | ok = false; |
1503 | 31.0k | break; |
1504 | 31.0k | } |
1505 | 5.89k | int type = m_textParser->getTextZoneType(int(dt.m_value)); |
1506 | 5.89k | if ((type == 6 && frame.m_type == Frame::Header) || |
1507 | 5.61k | (type == 7 && frame.m_type == Frame::Footer) || |
1508 | 5.34k | (type == 5)) |
1509 | 883 | frame.m_idStrs = int(dt.m_value); |
1510 | 5.01k | else |
1511 | 5.01k | { |
1512 | 5.01k | WPS_DEBUG_MSG(("WPS8Parser::readFRAM odd id for field 0x18\n")); |
1513 | 5.01k | ok = false; |
1514 | 5.01k | } |
1515 | 5.89k | break; |
1516 | 36.9k | } |
1517 | 16.3k | case 0x19: // CHECKME: can we also have a front color and a pattern ? |
1518 | 16.3k | if (!color) |
1519 | 16.3k | f2 << "#f23=false,"; |
1520 | 16.3k | frame.m_backgroundColor = dt.getRGBColor(); |
1521 | 16.3k | break; |
1522 | 3.48k | case 0x1b: // 41 |
1523 | 3.48k | if (frame.m_type!=Frame::Footer || dt.m_value != 0x41) |
1524 | 3.09k | f2 << "##f" << dt.id() << "=" << int16_t(dt.m_value) << ","; |
1525 | 3.48k | break; |
1526 | 13.1k | case 0x26: // rotation in degree from center ( CCW) |
1527 | 13.1k | f2 << "rot=" << double(dt.m_value)/10. << "deg,"; |
1528 | 13.1k | break; |
1529 | | // |
1530 | | // Table specific field ? |
1531 | | // |
1532 | 23.5k | case 0x2a: // link to the m_idTable(ids) number for a table |
1533 | 23.5k | { |
1534 | 23.5k | int id = int16_t(dt.m_value); |
1535 | 23.5k | if (frame.m_type==Frame::Table) |
1536 | 12.9k | frame.m_idTable = id; |
1537 | 10.6k | else |
1538 | 10.6k | f2 << "f" << dt.id() << "=" << id << ","; |
1539 | 23.5k | break; |
1540 | 36.9k | } |
1541 | 3.08k | case 0x2c: // CHEKME |
1542 | 3.08k | if (frame.m_type==Frame::Table) |
1543 | 394 | frame.m_columns = int(dt.m_value); |
1544 | 2.69k | else ok = false; |
1545 | 3.08k | break; |
1546 | 0 | case 0x14: // in relation with 0x30 ? find a small number between 1 and 18 |
1547 | 0 | if (frame.m_type==Frame::Table) |
1548 | 0 | f2 << "grpId=" << int16_t(dt.m_value) << ","; |
1549 | 0 | else ok = false; |
1550 | 0 | break; |
1551 | 4 | case 0x30: // seems to link the table together |
1552 | 4 | if (frame.m_type==Frame::Table) |
1553 | 0 | f2 << "tableGrp=" << int16_t(dt.m_value) << ","; |
1554 | 4 | else ok = false; |
1555 | 4 | break; |
1556 | 228 | case 0x2d: // appear 2 time in a table with value 2 |
1557 | 228 | f2 << "f" << dt.id() << "=" << int16_t(dt.m_value) << ","; |
1558 | 228 | break; |
1559 | | |
1560 | | // UNKNOWN |
1561 | 0 | case 0x1a: // appear 2 time (in a header and in a footer) with value 16 |
1562 | 0 | f2 << "f" << dt.id() << "=" << int(int8_t(dt.m_value)) << ","; |
1563 | 0 | break; |
1564 | | |
1565 | 24.8k | case 0x2e: // in a table: objectId+1, in textbox: m_idTable ?, other = i ? |
1566 | 24.8k | f2 << "id" << dt.id() << "=" << int16_t(dt.m_value-1) << ","; |
1567 | 24.8k | break; |
1568 | 22.5k | case 0x13: |
1569 | | // table 0x6-??, |
1570 | | // header/footer 0x16-??, |
1571 | | // textbox 0x10(means automatic resize) |
1572 | | // object : no set |
1573 | 22.5k | f2 << "f" << dt.id(); |
1574 | 22.5k | if (dt.m_value) |
1575 | 22.5k | f2 << "=" << std::hex << dt.m_value << std::dec; |
1576 | 22.5k | f2 << ","; |
1577 | 22.5k | break; |
1578 | 79 | case 0x2f: |
1579 | 79 | if (dt.isTrue()) |
1580 | 79 | f2 << "f" << dt.id() << ","; |
1581 | 0 | else |
1582 | 0 | f2 << "f" << dt.id() << "=false,"; |
1583 | 79 | break; |
1584 | 12.8k | case 0x1D: |
1585 | 22.7k | case 0x1E: |
1586 | 29.9k | case 0x1F: |
1587 | 37.0k | case 0x20: // in inches small value 0/0.05/0.1 -> a border size ? |
1588 | 37.0k | bset = true; |
1589 | 37.0k | bsetVal[dt.id()-0x1D] = true; |
1590 | 37.0k | bDim[dt.id()-0x1D] = double(dt.m_value)/914400; |
1591 | 37.0k | break; |
1592 | | |
1593 | 0 | default: |
1594 | 0 | ok = false; |
1595 | 465k | } |
1596 | | |
1597 | 465k | if (ok) continue; |
1598 | 123k | f2 << "#" << dt << ","; |
1599 | 123k | } |
1600 | 290k | frame.m_pos.setOrigin(minP); |
1601 | 290k | frame.m_pos.setSize(sizeP); |
1602 | 290k | m_state->m_frameList.push_back(frame); |
1603 | | |
1604 | 290k | f.str(""); |
1605 | 290k | f << entry.name() << "(" << i << "):" << frame << ","; |
1606 | 290k | if (setVal[0] || setVal[1]) |
1607 | 62.6k | { |
1608 | 62.6k | f << "f8/9=["; |
1609 | 187k | for (int j = 0; j < 2; j++) |
1610 | 125k | { |
1611 | 125k | if (!setVal[j]) |
1612 | 61.2k | { |
1613 | 61.2k | f << "_,"; |
1614 | 61.2k | continue; |
1615 | 61.2k | } |
1616 | 63.9k | double diff = 25/18.-dim[j]; |
1617 | 63.9k | if (diff >= -1e-3 && diff <= 1e-3) f << "*,"; |
1618 | 38.7k | else f << dim[j] << ","; |
1619 | 63.9k | } |
1620 | 62.6k | f << "],"; |
1621 | 62.6k | } |
1622 | 290k | if (setVal[2]) f << "border[w]=" << dim[2] << ","; |
1623 | | |
1624 | 290k | if (bset) |
1625 | 35.7k | { |
1626 | 35.7k | f << "borderMod[w]=["; // L, T, R, B |
1627 | 178k | for (int j = 0; j < 4; j++) |
1628 | 142k | { |
1629 | 142k | if (!bsetVal[j]) |
1630 | 105k | { |
1631 | 105k | f << "_,"; |
1632 | 105k | continue; |
1633 | 105k | } |
1634 | 37.0k | f << bDim[j] << ","; |
1635 | 37.0k | } |
1636 | 35.7k | f << "],"; |
1637 | 35.7k | } |
1638 | 290k | f << f2.str(); |
1639 | 290k | if (!readOk) f << ", ###or" << mainData; |
1640 | | |
1641 | 290k | ascii().addPos(lastPos); |
1642 | 290k | ascii().addNote(f.str().c_str()); |
1643 | 290k | } |
1644 | 476k | if (parsedAll) return true; |
1645 | | |
1646 | 161k | ascii().addPos(lastPos); |
1647 | 161k | f.str(""); |
1648 | 161k | f << "###" << entry.name(); |
1649 | 161k | ascii().addNote(f.str().c_str()); |
1650 | 161k | return false; |
1651 | 476k | } |
1652 | | |
1653 | | /** try to read a frame XXX database */ |
1654 | | bool WPS8Parser::readFRCD(WPSEntry const &entry) |
1655 | 263k | { |
1656 | 263k | libwps::DebugStream f; |
1657 | 263k | if (!entry.hasType(entry.name())) |
1658 | 0 | { |
1659 | 0 | WPS_DEBUG_MSG(("WPS8Parser::readFRCD warning: name=%s, type=%s\n", |
1660 | 0 | entry.name().c_str(), entry.type().c_str())); |
1661 | 0 | return false; |
1662 | 0 | } |
1663 | 263k | RVNGInputStreamPtr input = getInput(); |
1664 | | |
1665 | 263k | long page_offset = entry.begin(); |
1666 | 263k | long length = entry.length(); |
1667 | 263k | long endPage = entry.end(); |
1668 | | |
1669 | 263k | if (length < 4+33+5*8) |
1670 | 35.9k | { |
1671 | 35.9k | WPS_DEBUG_MSG(("WPS8Parser::readFRCD warning: length=0x%lx\n", static_cast<unsigned long>(length))); |
1672 | 35.9k | return false; |
1673 | 35.9k | } |
1674 | 227k | entry.setParsed(); |
1675 | 227k | input->seek(page_offset, librevenge::RVNG_SEEK_SET); |
1676 | 227k | auto val=int(libwps::readU16(input)); // 0x30 |
1677 | 227k | if (val!=0x30) f << "f0=" << val << ","; |
1678 | 227k | auto sSz=int(libwps::readU16(input)); |
1679 | 227k | librevenge::RVNGString str; |
1680 | 227k | if (4+2*sSz+33+5*8>length || !m_textParser->readString(input, sSz, str)) |
1681 | 36.4k | { |
1682 | 36.4k | WPS_DEBUG_MSG(("WPS8Parser::readFRCD warning: can not read main string\n")); |
1683 | 36.4k | return false; |
1684 | 36.4k | } |
1685 | 190k | f << str.cstr() << ","; |
1686 | 3.24M | for (int i=0; i<16; ++i) // f1=10,f2=22,f4=4,f7=256,f11=-1,f12=-256,f13=255,f14=-1 |
1687 | 3.05M | { |
1688 | 3.05M | val=int(libwps::read16(input)); |
1689 | 3.05M | if (val) f << "f" << i+1 << "=" << val << ","; |
1690 | 3.05M | } |
1691 | 190k | val=int(libwps::read8(input)); |
1692 | 190k | if (val) f << "g0=" << val << ","; |
1693 | 190k | ascii().addPos(page_offset); |
1694 | 190k | ascii().addNote(f.str().c_str()); |
1695 | 679k | for (int i=0; i<5; ++i) |
1696 | 604k | { |
1697 | 604k | long pos=input->tell(); |
1698 | 604k | f.str(""); |
1699 | 604k | f << "FRCD-A" << i << ":"; |
1700 | 604k | if (pos+8>endPage) |
1701 | 10.9k | { |
1702 | 10.9k | WPS_DEBUG_MSG(("WPS8Parser::readFRCD warning: the zone seems too short\n")); |
1703 | 10.9k | f << "###"; |
1704 | 10.9k | ascii().addPos(pos); |
1705 | 10.9k | ascii().addNote(f.str().c_str()); |
1706 | 10.9k | return true; |
1707 | 10.9k | } |
1708 | 1.59M | for (int s=0; s<2; ++s) |
1709 | 1.10M | { |
1710 | 1.10M | if (pos+4>endPage || libwps::read8(input)!=-1) |
1711 | 66.2k | { |
1712 | 66.2k | WPS_DEBUG_MSG(("WPS8Parser::readFRCD warning: the zone seems bad\n")); |
1713 | 66.2k | f << "###"; |
1714 | 66.2k | ascii().addPos(pos); |
1715 | 66.2k | ascii().addNote(f.str().c_str()); |
1716 | 66.2k | return true; |
1717 | 66.2k | } |
1718 | 1.04M | val=int(libwps::read8(input)); |
1719 | 1.04M | if (val==-1) |
1720 | 936k | { |
1721 | 936k | val=int(libwps::read16(input)); |
1722 | 936k | if (val!=0x204) |
1723 | 936k | f << "f" << s << "=" << val << ","; |
1724 | 936k | } |
1725 | 106k | else if (val==-2) |
1726 | 80.3k | { |
1727 | 80.3k | val=int(libwps::read8(input)); |
1728 | 80.3k | if (val!=-1) f << "g" << s << "=" << val << ","; |
1729 | 80.3k | sSz=int(libwps::readU8(input)); |
1730 | 80.3k | str.clear(); |
1731 | 80.3k | if (pos+2*sSz>endPage || (sSz && !m_textParser->readString(input, 2*sSz, str))) |
1732 | 11.9k | { |
1733 | 11.9k | WPS_DEBUG_MSG(("WPS8Parser::readFRCD warning: the zone seems too short\n")); |
1734 | 11.9k | f << "###"; |
1735 | 11.9k | ascii().addPos(pos); |
1736 | 11.9k | ascii().addNote(f.str().c_str()); |
1737 | 11.9k | return true; |
1738 | 11.9k | } |
1739 | 68.3k | if (!str.empty()) |
1740 | 33.0k | f << str.cstr() << ","; |
1741 | 68.3k | } |
1742 | 26.4k | else |
1743 | 26.4k | { |
1744 | 26.4k | WPS_DEBUG_MSG(("WPS8Parser::readFRCD warning: find unexpected value\n")); |
1745 | 26.4k | f << "###val=" << val << ","; |
1746 | 26.4k | ascii().addPos(pos); |
1747 | 26.4k | ascii().addNote(f.str().c_str()); |
1748 | 26.4k | return true; |
1749 | 26.4k | } |
1750 | 1.04M | } |
1751 | 488k | ascii().addPos(pos); |
1752 | 488k | ascii().addNote(f.str().c_str()); |
1753 | 488k | } |
1754 | 75.1k | long pos=input->tell(); |
1755 | 75.1k | f.str(""); |
1756 | 75.1k | f << "FRCD-B:"; |
1757 | 75.1k | if (pos+4>endPage) |
1758 | 11.8k | { |
1759 | 11.8k | WPS_DEBUG_MSG(("WPS8Parser::readFRCD warning: can not read the second zone\n")); |
1760 | 11.8k | f << "###"; |
1761 | 11.8k | ascii().addPos(pos); |
1762 | 11.8k | ascii().addNote(f.str().c_str()); |
1763 | 11.8k | return true; |
1764 | 11.8k | } |
1765 | 63.3k | auto N=int(libwps::readU16(input)); |
1766 | 63.3k | if (pos+4+10*N>endPage) |
1767 | 13.9k | { |
1768 | 13.9k | WPS_DEBUG_MSG(("WPS8Parser::readFRCD warning: can not read the second zone\n")); |
1769 | 13.9k | f << "###"; |
1770 | 13.9k | ascii().addPos(pos); |
1771 | 13.9k | ascii().addNote(f.str().c_str()); |
1772 | 13.9k | return true; |
1773 | 13.9k | } |
1774 | 49.3k | val=int(libwps::read16(input)); // 0 |
1775 | 49.3k | if (val) f << "f0=" << val << ","; |
1776 | 49.3k | ascii().addPos(pos); |
1777 | 49.3k | ascii().addNote(f.str().c_str()); |
1778 | 64.9k | for (int n=0; n<N; ++n) |
1779 | 51.2k | { |
1780 | 51.2k | pos=input->tell(); |
1781 | 51.2k | f.str(""); |
1782 | 51.2k | f << "FRCD-B" << n << ":"; |
1783 | 51.2k | if (pos+10>endPage) |
1784 | 2.82k | { |
1785 | 2.82k | WPS_DEBUG_MSG(("WPS8Parser::readFRCD warning: the zone seems too short\n")); |
1786 | 2.82k | f << "###"; |
1787 | 2.82k | ascii().addPos(pos); |
1788 | 2.82k | ascii().addNote(f.str().c_str()); |
1789 | 2.82k | return true; |
1790 | 2.82k | } |
1791 | 48.4k | val=int(libwps::read16(input)); // 0 |
1792 | 48.4k | if (val) f << "f0=" << val << ","; |
1793 | 99.3k | for (int s=0; s<2; ++s) |
1794 | 83.7k | { |
1795 | 83.7k | if (pos+4>endPage || libwps::read8(input)!=-1) |
1796 | 14.0k | { |
1797 | 14.0k | WPS_DEBUG_MSG(("WPS8Parser::readFRCD warning: the second zone seems bad\n")); |
1798 | 14.0k | f << "###"; |
1799 | 14.0k | ascii().addPos(pos); |
1800 | 14.0k | ascii().addNote(f.str().c_str()); |
1801 | 14.0k | return true; |
1802 | 14.0k | } |
1803 | 69.7k | val=int(libwps::read8(input)); |
1804 | 69.7k | if (val==-2) |
1805 | 59.0k | { |
1806 | 59.0k | val=int(libwps::read8(input)); |
1807 | 59.0k | if (val!=-1) f << "g" << s << "=" << val << ","; |
1808 | 59.0k | sSz=int(libwps::readU8(input)); |
1809 | 59.0k | str.clear(); |
1810 | 59.0k | if (pos+2*sSz>endPage || (sSz && !m_textParser->readString(input, 2*sSz, str))) |
1811 | 8.09k | { |
1812 | 8.09k | WPS_DEBUG_MSG(("WPS8Parser::readFRCD warning: the second zone seems too short\n")); |
1813 | 8.09k | f << "###"; |
1814 | 8.09k | ascii().addPos(pos); |
1815 | 8.09k | ascii().addNote(f.str().c_str()); |
1816 | 8.09k | return true; |
1817 | 8.09k | } |
1818 | 50.9k | if (!str.empty()) |
1819 | 27.6k | f << str.cstr() << ","; |
1820 | 50.9k | } |
1821 | 10.7k | else |
1822 | 10.7k | { |
1823 | 10.7k | WPS_DEBUG_MSG(("WPS8Parser::readFRCD warning: find unexpected value\n")); |
1824 | 10.7k | f << "###val=" << val << ","; |
1825 | 10.7k | ascii().addPos(pos); |
1826 | 10.7k | ascii().addNote(f.str().c_str()); |
1827 | 10.7k | return true; |
1828 | 10.7k | } |
1829 | 69.7k | } |
1830 | 15.6k | ascii().addPos(pos); |
1831 | 15.6k | ascii().addNote(f.str().c_str()); |
1832 | 15.6k | } |
1833 | 13.6k | return true; |
1834 | 49.3k | } |
1835 | | |
1836 | | // reads SYID zone: an unknown zone which seems to have the |
1837 | | // same number of entries than the text zone |
1838 | | // also related to the MCLD ? |
1839 | | bool WPS8Parser::readSYID(WPSEntry const &entry, std::vector<int> &listId) |
1840 | 106k | { |
1841 | 106k | RVNGInputStreamPtr input = getInput(); |
1842 | 106k | listId.resize(0); |
1843 | 106k | libwps::DebugStream f; |
1844 | 106k | if (!entry.hasType(entry.name())) |
1845 | 0 | { |
1846 | 0 | WPS_DEBUG_MSG(("WPS8Parser::readSYID: warning: SYID name=%s, type=%s\n", |
1847 | 0 | entry.name().c_str(), entry.type().c_str())); |
1848 | 0 | return false; |
1849 | 0 | } |
1850 | | |
1851 | 106k | long page_offset = entry.begin(); |
1852 | 106k | long length = entry.length(); |
1853 | | |
1854 | 106k | if (length < 4) |
1855 | 33.5k | { |
1856 | 33.5k | WPS_DEBUG_MSG(("WPS8Parser::readSYID: warning: SYID length=0x%lx\n", static_cast<unsigned long>(length))); |
1857 | 33.5k | return false; |
1858 | 33.5k | } |
1859 | | |
1860 | 72.8k | input->seek(page_offset, librevenge::RVNG_SEEK_SET); |
1861 | | |
1862 | 72.8k | int unk = libwps::read32(input); |
1863 | 72.8k | int numID = libwps::read32(input); |
1864 | 72.8k | if (numID < 0 || 4*(long(numID)+2) != length) |
1865 | 70.7k | { |
1866 | 70.7k | WPS_DEBUG_MSG(("WPS8Parser::readSYID: invalid length=%ld, num=%d\n", length, numID)); |
1867 | 70.7k | return false; |
1868 | 70.7k | } |
1869 | | |
1870 | 2.11k | f << "N=" << numID << ", unkn=" << unk << ", ("; |
1871 | 5.17k | for (int i = 0; i < numID; i++) |
1872 | 3.05k | { |
1873 | 3.05k | int val = libwps::read32(input); |
1874 | 3.05k | listId.push_back(val); |
1875 | 3.05k | f << val << ","; |
1876 | 3.05k | } |
1877 | 2.11k | f << ")"; |
1878 | | |
1879 | 2.11k | ascii().addPos(page_offset); |
1880 | 2.11k | ascii().addNote(f.str().c_str()); |
1881 | | |
1882 | 2.11k | entry.setParsed(); |
1883 | 2.11k | return true; |
1884 | 72.8k | } |
1885 | | |
1886 | | // reads the WNPR zone : a zone which seems to contain the printer preferences |
1887 | | // Warning: read data are not used |
1888 | | bool WPS8Parser::readWNPR(WPSEntry const &entry) |
1889 | 329k | { |
1890 | 329k | if (!entry.hasType("WNPR")) |
1891 | 0 | { |
1892 | 0 | WPS_DEBUG_MSG(("WPS8Parser::readWNPR: warning: WNPR name=%s, type=%s\n", |
1893 | 0 | entry.name().c_str(), entry.type().c_str())); |
1894 | 0 | return false; |
1895 | 0 | } |
1896 | 329k | RVNGInputStreamPtr input = getInput(); |
1897 | 329k | long page_offset = entry.begin(); |
1898 | 329k | long length = entry.length(); |
1899 | 329k | long endPage = entry.end(); |
1900 | | |
1901 | 329k | if (length < 40) |
1902 | 22.9k | { |
1903 | 22.9k | WPS_DEBUG_MSG(("WPS8Parser::readWNPR: warning: WNPR length=0x%lx\n", static_cast<unsigned long>(length))); |
1904 | 22.9k | return false; |
1905 | 22.9k | } |
1906 | | |
1907 | 306k | entry.setParsed(); |
1908 | 306k | input->seek(page_offset, librevenge::RVNG_SEEK_SET); |
1909 | | |
1910 | 306k | libwps::DebugStream f; |
1911 | | |
1912 | 306k | f << std::hex << libwps::readU32(input) << std::dec << ","; |
1913 | 306k | long dim[4]; |
1914 | 306k | for (long &i : dim) |
1915 | 1.01M | { |
1916 | 1.01M | i = libwps::read32(input); |
1917 | 1.01M | if (i <= 0) return false; |
1918 | 1.01M | } |
1919 | | |
1920 | 188k | if (dim[2] && dim[3]) |
1921 | 188k | { |
1922 | 188k | f << "width=" << float(dim[0])/float(dim[2]) << ","; |
1923 | 188k | f << "height=" << float(dim[1])/float(dim[3]) << ","; |
1924 | 188k | } |
1925 | 0 | else |
1926 | 0 | { |
1927 | 0 | f << "###width=" << dim[0] << ":" << dim[3] << ","; |
1928 | 0 | f << "###height=" << dim[1] << ":" << dim[3] << ","; |
1929 | 0 | } |
1930 | | |
1931 | 188k | f << "printmargins?=("; |
1932 | 944k | for (int i = 0; i < 4; i++) |
1933 | 755k | { |
1934 | 755k | auto val = long(libwps::readU32(input)); |
1935 | 755k | long sz = dim[2+(i%2)]; |
1936 | 755k | if (sz) |
1937 | 755k | f << float(val)/float(sz) << ","; |
1938 | 0 | else |
1939 | 0 | f << "###" << val << ","; |
1940 | 755k | } |
1941 | 188k | f << "),"; |
1942 | | |
1943 | 566k | for (int i = 0; i < 2; i++) |
1944 | 377k | f << std::hex << libwps::readU16(input) << std::dec <<","; |
1945 | | |
1946 | | |
1947 | 188k | ascii().addPos(page_offset); |
1948 | 188k | ascii().addNote(f.str().c_str()); |
1949 | | |
1950 | 188k | long actPos = input->tell(); |
1951 | 188k | if (actPos + 32*2+38+22 > endPage) |
1952 | 26.6k | { |
1953 | 26.6k | WPS_DEBUG_MSG(("WPS8Parser::readWNPR: length=0x%lx seems too short\n", static_cast<unsigned long>(length))); |
1954 | 26.6k | return false; |
1955 | 26.6k | } |
1956 | | |
1957 | | // DEVMODEA |
1958 | 162k | std::string st; |
1959 | 5.35M | for (int i = 0; i < 32; i++) |
1960 | 5.18M | { |
1961 | 5.18M | unsigned char c = libwps::readU8(input); |
1962 | 5.18M | if (!c) continue; // normally end by c, check me |
1963 | 3.04M | st+= char(c); |
1964 | 3.04M | } |
1965 | 162k | f.str(""); |
1966 | 162k | f << "PRNT(DevMode):"; |
1967 | 162k | f << "devName='" << st << "'," << std::hex; |
1968 | 162k | f << "specVersion=" << libwps::readU16(input) << ","; |
1969 | 162k | f << "driverVersion=" << libwps::readU16(input) << ","; |
1970 | 162k | int dmSize = libwps::readU16(input); |
1971 | 162k | if (actPos + dmSize > endPage || dmSize < 124) return false; |
1972 | 26.7k | f << "dmSize=" << dmSize << ","; |
1973 | 26.7k | f << "driverExtras=" << libwps::readU16(input) << ","; |
1974 | 26.7k | f << "dmFields=" << libwps::readU32(input) << ","; |
1975 | 26.7k | f << "orientation=" << libwps::readU16(input) << ","; // 1: portrait, 2: landscape |
1976 | 26.7k | f << "paperSize=" << libwps::readU16(input) << ","; // 1: letter, 2:letter small, .. |
1977 | | |
1978 | 26.7k | long dim2[3]; |
1979 | 26.7k | for (long &i : dim2) |
1980 | 80.3k | i = libwps::read16(input); |
1981 | 26.7k | f << std::dec; |
1982 | 26.7k | if (dim2[2] > 0) |
1983 | 10.8k | { |
1984 | 10.8k | f << "paperLength=" << std::dec << float(dim2[0])/float(dim2[2]) << ","; |
1985 | 10.8k | f << "paperWidth=" << float(dim2[1])/float(dim2[2]) << ","; |
1986 | 10.8k | } |
1987 | 15.8k | else |
1988 | 15.8k | { |
1989 | 15.8k | f << "paperLength=" << dim2[0] << ","; |
1990 | 15.8k | f << "paperWidth=" << dim2[1] << ","; |
1991 | 15.8k | f << "dmScale=" << dim2[2] << ","; |
1992 | 15.8k | } |
1993 | 26.7k | f << "dmCopies=" << libwps::readU16(input) << ","; |
1994 | 26.7k | f << "dmDefaultSource=" << libwps::readU16(input) << ","; |
1995 | 26.7k | f << "dmPrintQuality=" << libwps::read16(input) << ","; |
1996 | 26.7k | f << std::hex; |
1997 | 26.7k | f << "dmColor=" << libwps::readU16(input) << ","; |
1998 | 26.7k | f << "dmDuplex=" << libwps::readU16(input) << ","; |
1999 | 26.7k | f << "dmYResolution=" << libwps::readU16(input) << ","; |
2000 | 26.7k | f << "dmTTOption=" << libwps::readU16(input) << ","; |
2001 | 26.7k | f << "dmCollate=" << libwps::readU16(input) << ","; |
2002 | | |
2003 | 26.7k | st=""; |
2004 | 883k | for (int i = 0; i < 32; i++) |
2005 | 856k | { |
2006 | 856k | unsigned char c = libwps::readU8(input); |
2007 | 856k | if (!c) continue; // normally end by c, check me |
2008 | 359k | st+= char(c); |
2009 | 359k | } |
2010 | 26.7k | f << "formName='" << st << "',"; |
2011 | 26.7k | f << "dmLogPixels=" << libwps::readU16(input) << ","; |
2012 | 26.7k | f << "dmBitsPerPel=" << libwps::readU32(input) << ","; |
2013 | 26.7k | f << "dmPelsWidth=" << libwps::readU32(input) << ","; |
2014 | 26.7k | f << "dmPelsHeight=" << libwps::readU32(input) << ","; |
2015 | 26.7k | f << "dmDisplayFlags=" << libwps::readU32(input) << ","; |
2016 | 26.7k | f << "dmDisplayFrequency=" << libwps::readU32(input) << ","; |
2017 | | |
2018 | 26.7k | ascii().addPos(actPos); |
2019 | 26.7k | ascii().addNote(f.str().c_str()); |
2020 | | |
2021 | 26.7k | long devEndPos = actPos+dmSize; |
2022 | 26.7k | actPos = input->tell(); |
2023 | 26.7k | if (actPos != devEndPos) |
2024 | 26.7k | { |
2025 | 26.7k | ascii().addPos(actPos); |
2026 | 26.7k | ascii().addNote("PRNT(DevMode-End)"); |
2027 | 26.7k | } |
2028 | | |
2029 | 26.7k | ascii().addPos(devEndPos); |
2030 | 26.7k | ascii().addNote("PRNT(Unknown)"); |
2031 | | |
2032 | 26.7k | return true; |
2033 | 162k | } |
2034 | | |
2035 | | //////////////////////////////////////////////////////////////// |
2036 | | // |
2037 | | // ? Syllabes seperator to read the text |
2038 | | // it is really related to spell check or to speech |
2039 | | // Can surely be safety ignored in normal version. |
2040 | | // |
2041 | | //////////////////////////////////////////////////////////////// |
2042 | | #ifndef DEBUG |
2043 | | bool WPS8Parser::readSPELLING(RVNGInputStreamPtr, std::string const &) |
2044 | 0 | { |
2045 | 0 | return true; |
2046 | 0 | } |
2047 | | #else |
2048 | | bool WPS8Parser::readSPELLING(RVNGInputStreamPtr input, std::string const &oleName) |
2049 | | { |
2050 | | // SPELLING |
2051 | | input->seek(0, librevenge::RVNG_SEEK_SET); |
2052 | | auto vers = int(libwps::read32(input)); // always 6 ? |
2053 | | if (vers < 0 || input->isEnd()) return false; |
2054 | | |
2055 | | std::string fName = libwps::Debug::flattenFileName(oleName); |
2056 | | libwps::DebugFile asciiFile(input); |
2057 | | asciiFile.open(fName); |
2058 | | |
2059 | | |
2060 | | int actId = 0; |
2061 | | std::map<uint32_t, int> listIds; |
2062 | | |
2063 | | libwps::DebugStream f; |
2064 | | int num = 0; |
2065 | | while (!input->isEnd()) |
2066 | | { |
2067 | | long pos = input->tell(); |
2068 | | auto numVal = int(libwps::read32(input)); |
2069 | | |
2070 | | if (numVal < 0 || input->seek(8*numVal, librevenge::RVNG_SEEK_CUR) || input->tell() != pos+4+8*numVal) |
2071 | | { |
2072 | | input->seek(pos, librevenge::RVNG_SEEK_SET); |
2073 | | break; |
2074 | | } |
2075 | | |
2076 | | f.str(""); |
2077 | | f << "SPELLING" << num++ << ": "; // linked to STRSj by num = numSTRS-j? |
2078 | | input->seek(pos+4, librevenge::RVNG_SEEK_SET); |
2079 | | for (int j = 0; j < numVal; j++) |
2080 | | { |
2081 | | uint32_t ptr = libwps::readU32(input); |
2082 | | int id; |
2083 | | if (listIds.find(ptr) == listIds.end()) |
2084 | | { |
2085 | | id = actId++; |
2086 | | listIds[ptr] = id; |
2087 | | } |
2088 | | else |
2089 | | id = listIds[ptr]; |
2090 | | auto sPos = long(libwps::read32(input)); |
2091 | | f << std::hex << 2*sPos << ":SP" << std::dec << id << ","; |
2092 | | } |
2093 | | asciiFile.addPos(pos); |
2094 | | asciiFile.addNote(f.str().c_str()); |
2095 | | } |
2096 | | f.str(""); |
2097 | | f << "SPELLING:"; |
2098 | | if (vers != 6) f << "version = " << vers << ", "; |
2099 | | f << "list=["; |
2100 | | for (auto const &it : listIds) |
2101 | | { |
2102 | | uint32_t val = it.first; |
2103 | | f << "SP" << std::dec << it.second << "(" << (val&0xFF) << ":" |
2104 | | << std::hex << (val>>8) << std::dec << "),"; |
2105 | | |
2106 | | // (val&0xFF) :121-123, 129, 133, 139, 145 |
2107 | | // (val>>8) : 0, e6, d9a3b, 3b75f4, 474555, 548bbb, 609daa,748cce, ba32b9, c068cd, d39bea |
2108 | | // seems constant in a SPELLING Ole |
2109 | | } |
2110 | | f << "]"; |
2111 | | asciiFile.addPos(0); |
2112 | | asciiFile.addNote(f.str().c_str()); |
2113 | | if (!input->isEnd()) |
2114 | | { |
2115 | | asciiFile.addPos(input->tell()); |
2116 | | asciiFile.addNote("###SPELLING"); |
2117 | | } |
2118 | | return true; |
2119 | | } |
2120 | | #endif |
2121 | | |
2122 | | /* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */ |