/src/libwps/src/lib/WPSDocument.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) 2003 William Lachance (william.lachance@sympatico.ca) |
11 | | * Copyright (C) 2003-2004 Marc Maurer (uwog@uwog.net) |
12 | | * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch) |
13 | | * Copyright (C) 2006, 2007 Andrew Ziem (andrewziem users sourceforge net) |
14 | | * |
15 | | * For minor contributions see the git repository. |
16 | | * |
17 | | * Alternatively, the contents of this file may be used under the terms |
18 | | * of the GNU Lesser General Public License Version 2.1 or later |
19 | | * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are |
20 | | * applicable instead of those above. |
21 | | * |
22 | | * For further information visit http://libwps.sourceforge.net |
23 | | */ |
24 | | |
25 | | #include <libwps/libwps.h> |
26 | | |
27 | | #include "libwps_internal.h" |
28 | | #include "libwps_tools_win.h" |
29 | | |
30 | | #include "DosWord.h" |
31 | | #include "Lotus.h" |
32 | | #include "Multiplan.h" |
33 | | #include "PocketExcel.h" |
34 | | #include "PocketWord.h" |
35 | | #include "Quattro.h" |
36 | | #include "QuattroDos.h" |
37 | | #include "Quattro9.h" |
38 | | #include "WKS4.h" |
39 | | #include "WPS4.h" |
40 | | #include "WPS8.h" |
41 | | #include "MSWrite.h" |
42 | | #include "WPSHeader.h" |
43 | | #include "WPSParser.h" |
44 | | #include "XYWrite.h" |
45 | | |
46 | | using namespace libwps; |
47 | | |
48 | | /** |
49 | | \mainpage libwps documentation |
50 | | This document contains both the libwps API specification and the normal libwps |
51 | | documentation. |
52 | | \section api_docs libwps API documentation |
53 | | The external libwps API is provided by the WPSDocument class. This class, combined |
54 | | with the librevenge's librevenge::RVNGTextInterface class, are the only two classes that will be |
55 | | of interest for the application programmer using libwps. |
56 | | \section lib_docs libwps documentation |
57 | | If you are interrested in the structure of libwps itself, this whole document |
58 | | would be a good starting point for exploring the interals of libwps. Mind that |
59 | | this document is a work-in-progress, and will most likely not cover libwps for |
60 | | the full 100%. |
61 | | |
62 | | \warning When compiled with -DDEBUG_WITH__FILES, code is added to store the results of the parsing in different files: one file by Ole parts and some files to store the read pictures. These files are created in the current repository, therefore it is recommended to launch the tests in an empty repository...*/ |
63 | | |
64 | | WPSLIB WPSConfidence WPSDocument::isFileFormatSupported(librevenge::RVNGInputStream *ip, WPSKind &kind, WPSCreator &creator, bool &needEncoding) |
65 | 0 | { |
66 | 0 | WPS_DEBUG_MSG(("WPSDocument::isFileFormatSupported()\n")); |
67 | |
|
68 | 0 | if (!ip) |
69 | 0 | return WPS_CONFIDENCE_NONE; |
70 | | |
71 | 0 | kind=WPS_TEXT; |
72 | 0 | WPSHeaderPtr header; |
73 | 0 | std::shared_ptr<librevenge::RVNGInputStream > input(ip, WPS_shared_ptr_noop_deleter<librevenge::RVNGInputStream>()); |
74 | 0 | try |
75 | 0 | { |
76 | 0 | header.reset(WPSHeader::constructHeader(input)); |
77 | |
|
78 | 0 | if (!header) |
79 | 0 | return WPS_CONFIDENCE_NONE; |
80 | 0 | creator = header->getCreator(); |
81 | 0 | kind = header->getKind(); |
82 | 0 | needEncoding=false; |
83 | |
|
84 | 0 | WPSConfidence confidence = WPS_CONFIDENCE_NONE; |
85 | 0 | if (kind==WPS_TEXT && creator==WPS_MSWRITE) |
86 | 0 | { |
87 | 0 | needEncoding=true; |
88 | 0 | return WPS_CONFIDENCE_EXCELLENT; |
89 | 0 | } |
90 | 0 | else if (kind==WPS_TEXT && creator==WPS_DOSWORD) |
91 | 0 | { |
92 | | // create a DosWordParser to check the header validity |
93 | 0 | DosWordParser parser(header->getInput(), header); |
94 | 0 | if (!parser.checkHeader(header.get(), true)) |
95 | 0 | return WPS_CONFIDENCE_NONE; |
96 | 0 | needEncoding=header->getNeedEncoding(); |
97 | 0 | return WPS_CONFIDENCE_EXCELLENT; |
98 | 0 | } |
99 | 0 | else if (kind==WPS_TEXT && creator==WPS_POCKETWORD) |
100 | 0 | { |
101 | | // create a PocketWord parser to check the header validity |
102 | 0 | PocketWordParser parser(header->getInput(), header); |
103 | 0 | if (!parser.checkHeader(header.get(), true)) |
104 | 0 | return WPS_CONFIDENCE_NONE; |
105 | 0 | needEncoding=header->getNeedEncoding(); |
106 | 0 | return WPS_CONFIDENCE_EXCELLENT; |
107 | 0 | } |
108 | 0 | else if (kind==WPS_TEXT && creator==WPS_XYWRITE) |
109 | 0 | { |
110 | | // create a XYWrite parser to check the header validity |
111 | 0 | XYWriteParser parser(header->getInput(), header); |
112 | 0 | if (!parser.checkHeader(header.get(), true)) |
113 | 0 | return WPS_CONFIDENCE_NONE; |
114 | 0 | needEncoding=header->getNeedEncoding(); |
115 | 0 | return WPS_CONFIDENCE_EXCELLENT; |
116 | 0 | } |
117 | 0 | else if (kind==WPS_TEXT && header->getMajorVersion()<=4) |
118 | 0 | { |
119 | | // create a WPS4Parser to check the header validity |
120 | 0 | WPS4Parser parser(header->getInput(), header); |
121 | 0 | if (!parser.checkHeader(header.get(), true)) |
122 | 0 | return WPS_CONFIDENCE_NONE; |
123 | 0 | needEncoding=header->getNeedEncoding(); |
124 | 0 | return WPS_CONFIDENCE_EXCELLENT; |
125 | 0 | } |
126 | 0 | else if (kind==WPS_SPREADSHEET && creator==WPS_LOTUS && header->getMajorVersion()>=100) |
127 | 0 | { |
128 | | // create a Lotus parser to check the header validity |
129 | 0 | LotusParser parser(header->getInput(), header); |
130 | 0 | if (!parser.checkHeader(header.get(), true)) |
131 | 0 | return WPS_CONFIDENCE_NONE; |
132 | 0 | needEncoding=header->getNeedEncoding(); |
133 | 0 | return header->getIsEncrypted() ? WPS_CONFIDENCE_SUPPORTED_ENCRYPTION : WPS_CONFIDENCE_EXCELLENT; |
134 | 0 | } |
135 | 0 | else if (kind==WPS_SPREADSHEET && creator==WPS_QUATTRO_PRO) |
136 | 0 | { |
137 | 0 | if (header->getMajorVersion()<=2) // wq1-wq2 |
138 | 0 | { |
139 | | // create a QuattroDos parser to check the header validity |
140 | 0 | QuattroDosParser parser(header->getInput(), header); |
141 | 0 | if (!parser.checkHeader(header.get(), true)) |
142 | 0 | return WPS_CONFIDENCE_NONE; |
143 | 0 | needEncoding=header->getNeedEncoding(); |
144 | 0 | return WPS_CONFIDENCE_EXCELLENT; |
145 | 0 | } |
146 | 0 | else if (header->getMajorVersion()>=1000 && header->getMajorVersion()<2000) // wb1-wb3 |
147 | 0 | { |
148 | | // create a Quattro parser to check the header validity |
149 | 0 | QuattroParser parser(header->getInput(), header); |
150 | 0 | if (!parser.checkHeader(header.get(), true)) |
151 | 0 | return WPS_CONFIDENCE_NONE; |
152 | 0 | needEncoding=header->getNeedEncoding(); |
153 | 0 | return header->getIsEncrypted() ? WPS_CONFIDENCE_SUPPORTED_ENCRYPTION : WPS_CONFIDENCE_EXCELLENT; |
154 | 0 | } |
155 | 0 | else if (header->getMajorVersion()>=2000) // qwp |
156 | 0 | { |
157 | | // create a Quattro parser to check the header validity |
158 | 0 | Quattro9Parser parser(header->getInput(), header); |
159 | 0 | if (!parser.checkHeader(header.get(), true)) |
160 | 0 | return WPS_CONFIDENCE_NONE; |
161 | 0 | return header->getIsEncrypted() ? WPS_CONFIDENCE_SUPPORTED_ENCRYPTION : WPS_CONFIDENCE_EXCELLENT; |
162 | 0 | } |
163 | 0 | } |
164 | 0 | else if (kind==WPS_SPREADSHEET && creator==WPS_MULTIPLAN) |
165 | 0 | { |
166 | | // create a MS Multiplan parser to check the header validity |
167 | 0 | MultiplanParser parser(header->getInput(), header); |
168 | 0 | if (!parser.checkHeader(header.get(), true)) |
169 | 0 | return WPS_CONFIDENCE_NONE; |
170 | 0 | needEncoding=header->getNeedEncoding(); |
171 | 0 | return header->getIsEncrypted() ? WPS_CONFIDENCE_SUPPORTED_ENCRYPTION : WPS_CONFIDENCE_EXCELLENT; |
172 | 0 | } |
173 | | #ifdef DEBUG |
174 | | else if (kind==WPS_SPREADSHEET && creator==WPS_POCKETEXCEL) |
175 | | { |
176 | | // create a Quattro parser to check the header validity |
177 | | PocketExcelParser parser(header->getInput(), header); |
178 | | if (!parser.checkHeader(header.get(), true)) |
179 | | return WPS_CONFIDENCE_NONE; |
180 | | return header->getIsEncrypted() ? WPS_CONFIDENCE_SUPPORTED_ENCRYPTION : WPS_CONFIDENCE_EXCELLENT; |
181 | | } |
182 | | #endif |
183 | 0 | else if (kind==WPS_SPREADSHEET || kind==WPS_DATABASE) |
184 | 0 | { |
185 | | // create a WKS4Parser to check the header validity |
186 | 0 | WKS4Parser parser(header->getInput(), header); |
187 | 0 | if (!parser.checkHeader(header.get(), true)) |
188 | 0 | return WPS_CONFIDENCE_NONE; |
189 | | // checkHeader() may set new kind and creator values, |
190 | | // pass them up to caller. |
191 | 0 | kind = header->getKind(); |
192 | 0 | creator = header->getCreator(); |
193 | 0 | needEncoding=header->getNeedEncoding(); |
194 | 0 | return header->getIsEncrypted() ? WPS_CONFIDENCE_SUPPORTED_ENCRYPTION : WPS_CONFIDENCE_EXCELLENT; |
195 | 0 | } |
196 | | |
197 | | /* A word document: as WPS8Parser does not have a checkHeader |
198 | | function, only rely on the version |
199 | | */ |
200 | 0 | switch (header->getMajorVersion()) |
201 | 0 | { |
202 | 0 | case 8: |
203 | 0 | case 7: |
204 | 0 | case 5: |
205 | 0 | confidence = WPS_CONFIDENCE_EXCELLENT; |
206 | 0 | break; |
207 | 0 | default: |
208 | 0 | break; |
209 | 0 | } |
210 | 0 | return confidence; |
211 | 0 | } |
212 | 0 | catch (libwps::FileException) |
213 | 0 | { |
214 | 0 | WPS_DEBUG_MSG(("File exception trapped\n")); |
215 | 0 | } |
216 | 0 | catch (libwps::PasswordException) |
217 | 0 | { |
218 | 0 | WPS_DEBUG_MSG(("Password exception trapped\n")); |
219 | 0 | } |
220 | 0 | catch (libwps::ParseException) |
221 | 0 | { |
222 | 0 | WPS_DEBUG_MSG(("Parse exception trapped\n")); |
223 | 0 | } |
224 | 0 | catch (...) |
225 | 0 | { |
226 | | //fixme: too generic |
227 | 0 | WPS_DEBUG_MSG(("Unknown Exception trapped\n")); |
228 | 0 | } |
229 | | |
230 | 0 | return WPS_CONFIDENCE_NONE; |
231 | 0 | } |
232 | | |
233 | | WPSLIB WPSResult WPSDocument::parse(librevenge::RVNGInputStream *ip, librevenge::RVNGTextInterface *documentInterface, |
234 | | char const * /*password*/, char const *encoding) |
235 | 36.3k | { |
236 | 36.3k | if (!ip || !documentInterface) |
237 | 0 | return WPS_UNKNOWN_ERROR; |
238 | | |
239 | 36.3k | WPSResult error = WPS_OK; |
240 | | |
241 | 36.3k | WPSHeaderPtr header; |
242 | 36.3k | std::shared_ptr<WPSParser> parser; |
243 | 36.3k | std::shared_ptr<librevenge::RVNGInputStream > input(ip, WPS_shared_ptr_noop_deleter<librevenge::RVNGInputStream>()); |
244 | 36.3k | try |
245 | 36.3k | { |
246 | 36.3k | header.reset(WPSHeader::constructHeader(input)); |
247 | | |
248 | 36.3k | if (!header || header->getKind() != WPS_TEXT) |
249 | 3.37k | return WPS_UNKNOWN_ERROR; |
250 | | |
251 | 32.9k | if (header->getCreator() == WPS_MSWRITE) |
252 | 735 | { |
253 | 735 | parser.reset(new MSWriteParser(header->getInput(), header, |
254 | 735 | libwps_tools_win::Font::getTypeForString(encoding))); |
255 | 735 | if (!parser) return WPS_UNKNOWN_ERROR; |
256 | 735 | parser->parse(documentInterface); |
257 | 735 | } |
258 | 32.1k | else if (header->getCreator() == WPS_DOSWORD) |
259 | 1.91k | { |
260 | 1.91k | parser.reset(new DosWordParser(header->getInput(), header, |
261 | 1.91k | libwps_tools_win::Font::getTypeForString(encoding))); |
262 | 1.91k | if (!parser) return WPS_UNKNOWN_ERROR; |
263 | 1.91k | parser->parse(documentInterface); |
264 | 1.91k | } |
265 | 30.2k | else if (header->getCreator() == WPS_POCKETWORD) |
266 | 1.78k | { |
267 | 1.78k | parser.reset(new PocketWordParser(header->getInput(), header, |
268 | 1.78k | libwps_tools_win::Font::getTypeForString(encoding))); |
269 | 1.78k | if (!parser) return WPS_UNKNOWN_ERROR; |
270 | 1.78k | parser->parse(documentInterface); |
271 | 1.78k | } |
272 | 28.4k | else if (header->getCreator() == WPS_XYWRITE) |
273 | 12.5k | { |
274 | 12.5k | parser.reset(new XYWriteParser(header->getInput(), header, |
275 | 12.5k | libwps_tools_win::Font::getTypeForString(encoding))); |
276 | 12.5k | if (!parser) return WPS_UNKNOWN_ERROR; |
277 | 12.5k | parser->parse(documentInterface); |
278 | 12.5k | } |
279 | 15.9k | else switch (header->getMajorVersion()) |
280 | 15.9k | { |
281 | 1.55k | case 8: |
282 | 1.55k | case 7: |
283 | 1.55k | case 6: |
284 | 10.3k | case 5: |
285 | 10.3k | { |
286 | 10.3k | parser.reset(new WPS8Parser(header->getInput(), header)); |
287 | 10.3k | if (!parser) return WPS_UNKNOWN_ERROR; |
288 | 10.3k | parser->parse(documentInterface); |
289 | 10.3k | break; |
290 | 10.3k | } |
291 | | |
292 | 2.69k | case 4: |
293 | 2.69k | case 3: |
294 | 5.60k | case 2: |
295 | 5.60k | case 1: |
296 | 5.60k | { |
297 | 5.60k | parser.reset(new WPS4Parser(header->getInput(), header, |
298 | 5.60k | libwps_tools_win::Font::getTypeForString(encoding))); |
299 | 5.60k | if (!parser) return WPS_UNKNOWN_ERROR; |
300 | 5.60k | parser->parse(documentInterface); |
301 | 5.60k | break; |
302 | 5.60k | } |
303 | 0 | default: |
304 | 0 | break; |
305 | 15.9k | } |
306 | 32.9k | } |
307 | 36.3k | catch (libwps::FileException) |
308 | 36.3k | { |
309 | 0 | WPS_DEBUG_MSG(("File exception trapped\n")); |
310 | 0 | error = WPS_FILE_ACCESS_ERROR; |
311 | 0 | } |
312 | 36.3k | catch (libwps::ParseException) |
313 | 36.3k | { |
314 | 9.81k | WPS_DEBUG_MSG(("Parse exception trapped\n")); |
315 | 9.81k | error = WPS_PARSE_ERROR; |
316 | 9.81k | } |
317 | 36.3k | catch (libwps::PasswordException) |
318 | 36.3k | { |
319 | 0 | WPS_DEBUG_MSG(("Password exception trapped\n")); |
320 | 0 | error = WPS_ENCRYPTION_ERROR; |
321 | 0 | } |
322 | 36.3k | catch (...) |
323 | 36.3k | { |
324 | | //fixme: too generic |
325 | 0 | WPS_DEBUG_MSG(("Unknown exception trapped\n")); |
326 | 0 | error = WPS_UNKNOWN_ERROR; |
327 | 0 | } |
328 | | |
329 | 32.9k | return error; |
330 | 36.3k | } |
331 | | |
332 | | WPSLIB WPSResult WPSDocument::parse(librevenge::RVNGInputStream *ip, librevenge::RVNGSpreadsheetInterface *documentInterface, |
333 | | char const *password, char const *encoding) |
334 | 110k | { |
335 | 110k | if (!ip || !documentInterface) |
336 | 0 | return WPS_UNKNOWN_ERROR; |
337 | | |
338 | 110k | WPSResult error = WPS_OK; |
339 | | |
340 | 110k | WPSHeaderPtr header; |
341 | 110k | std::shared_ptr<WKSParser> parser; |
342 | 110k | std::shared_ptr<librevenge::RVNGInputStream > input(ip, WPS_shared_ptr_noop_deleter<librevenge::RVNGInputStream>()); |
343 | 110k | try |
344 | 110k | { |
345 | 110k | header.reset(WPSHeader::constructHeader(input)); |
346 | | |
347 | 110k | if (!header || (header->getKind() != WPS_SPREADSHEET && header->getKind() != WPS_DATABASE)) |
348 | 5.78k | return WPS_UNKNOWN_ERROR; |
349 | | |
350 | 104k | if (header->getKind() == WPS_SPREADSHEET && header->getCreator() == WPS_LOTUS && |
351 | 41.9k | header->getMajorVersion()>=100) |
352 | 41.9k | parser.reset(new LotusParser(header->getInput(), header, |
353 | 41.9k | libwps_tools_win::Font::getTypeForString(encoding), password)); |
354 | 62.8k | else if (header->getKind() == WPS_SPREADSHEET && header->getCreator() == WPS_QUATTRO_PRO) |
355 | 42.8k | { |
356 | 42.8k | if (header->getMajorVersion()<=2) |
357 | 10.1k | parser.reset(new QuattroDosParser(header->getInput(), header, |
358 | 10.1k | libwps_tools_win::Font::getTypeForString(encoding))); |
359 | 32.6k | else if (header->getMajorVersion()>=1000 && header->getMajorVersion()<2000) |
360 | 20.9k | parser.reset(new QuattroParser(header->getInput(), header, |
361 | 20.9k | libwps_tools_win::Font::getTypeForString(encoding), password)); |
362 | 11.6k | else if (header->getMajorVersion()>=2000) |
363 | 11.6k | parser.reset(new Quattro9Parser(header->getInput(), header, |
364 | 11.6k | libwps_tools_win::Font::getTypeForString(encoding), password)); |
365 | 42.8k | } |
366 | 19.9k | else if (header->getKind() == WPS_SPREADSHEET && header->getCreator() == WPS_MULTIPLAN) |
367 | 5.55k | parser.reset(new MultiplanParser(header->getInput(), header, |
368 | 5.55k | libwps_tools_win::Font::getTypeForString(encoding), password)); |
369 | | #ifdef DEBUG |
370 | | else if (header->getKind() == WPS_SPREADSHEET && header->getCreator() == WPS_POCKETEXCEL) |
371 | | parser.reset(new PocketExcelParser(header->getInput(), header)); |
372 | | #endif |
373 | 14.4k | else |
374 | 14.4k | { |
375 | 14.4k | switch (header->getMajorVersion()) |
376 | 14.4k | { |
377 | 89 | case 4: |
378 | 1.47k | case 3: |
379 | 8.18k | case 2: |
380 | 14.4k | case 1: |
381 | 14.4k | { |
382 | 14.4k | parser.reset(new WKS4Parser(header->getInput(), header, |
383 | 14.4k | libwps_tools_win::Font::getTypeForString(encoding), password)); |
384 | 14.4k | break; |
385 | 8.18k | } |
386 | 0 | default: |
387 | 0 | WPS_DEBUG_MSG(("WPSDocument::parse: find unknown version number\n")); |
388 | 0 | break; |
389 | 14.4k | } |
390 | 14.4k | } |
391 | 104k | if (!parser) return WPS_UNKNOWN_ERROR; |
392 | 104k | parser->parse(documentInterface); |
393 | 104k | } |
394 | 110k | catch (libwps::FileException) |
395 | 110k | { |
396 | 0 | WPS_DEBUG_MSG(("File exception trapped\n")); |
397 | 0 | error = WPS_FILE_ACCESS_ERROR; |
398 | 0 | } |
399 | 110k | catch (libwps::ParseException) |
400 | 110k | { |
401 | 39.2k | WPS_DEBUG_MSG(("Parse exception trapped\n")); |
402 | 39.2k | error = WPS_PARSE_ERROR; |
403 | 39.2k | } |
404 | 110k | catch (libwps::PasswordException) |
405 | 110k | { |
406 | 0 | WPS_DEBUG_MSG(("Password exception trapped\n")); |
407 | 0 | error = WPS_ENCRYPTION_ERROR; |
408 | 0 | } |
409 | 110k | catch (...) |
410 | 110k | { |
411 | | //fixme: too generic |
412 | 0 | WPS_DEBUG_MSG(("Unknown exception trapped\n")); |
413 | 0 | error = WPS_UNKNOWN_ERROR; |
414 | 0 | } |
415 | | |
416 | 104k | return error; |
417 | 110k | } |
418 | | /* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */ |