Coverage Report

Created: 2026-06-13 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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: */