Coverage Report

Created: 2026-04-29 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libstaroffice/src/lib/STOFFDocument.cxx
Line
Count
Source
1
/* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */
2
3
/* libstaroffice
4
* Version: MPL 2.0 / LGPLv2+
5
*
6
* The contents of this file are subject to the Mozilla Public License Version
7
* 2.0 (the "License"); you may not use this file except in compliance with
8
* the License or as specified alternatively below. You may obtain a copy of
9
* the License at http://www.mozilla.org/MPL/
10
*
11
* Software distributed under the License is distributed on an "AS IS" basis,
12
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13
* for the specific language governing rights and limitations under the
14
* License.
15
*
16
* Major Contributor(s):
17
* Copyright (C) 2002 William Lachance (wrlach@gmail.com)
18
* Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net)
19
* Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
20
* Copyright (C) 2006, 2007 Andrew Ziem
21
* Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr)
22
*
23
*
24
* All Rights Reserved.
25
*
26
* For minor contributions see the git repository.
27
*
28
* Alternatively, the contents of this file may be used under the terms of
29
* the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
30
* in which case the provisions of the LGPLv2+ are applicable
31
* instead of those above.
32
*/
33
34
/** \file STOFFDocument.cxx
35
 * libstoff API: implementation of main interface functions
36
 */
37
38
#include "SDAParser.hxx"
39
#include "SDCParser.hxx"
40
#include "SDGParser.hxx"
41
#include "SDWParser.hxx"
42
#include "SDXParser.hxx"
43
44
#include "STOFFHeader.hxx"
45
#include "STOFFGraphicDecoder.hxx"
46
#include "STOFFParser.hxx"
47
#include "STOFFPropertyHandler.hxx"
48
#include "STOFFSpreadsheetDecoder.hxx"
49
50
#include <libstaroffice/libstaroffice.hxx>
51
52
/** small namespace use to define private class/method used by STOFFDocument */
53
namespace STOFFDocumentInternal
54
{
55
std::shared_ptr<STOFFGraphicParser> getGraphicParserFromHeader(STOFFInputStreamPtr &input, STOFFHeader *header, char const *passwd);
56
std::shared_ptr<STOFFGraphicParser> getPresentationParserFromHeader(STOFFInputStreamPtr &input, STOFFHeader *header, char const *passwd);
57
std::shared_ptr<STOFFTextParser> getTextParserFromHeader(STOFFInputStreamPtr &input, STOFFHeader *header, char const *passwd);
58
std::shared_ptr<STOFFSpreadsheetParser> getSpreadsheetParserFromHeader(STOFFInputStreamPtr &input, STOFFHeader *header, char const *passwd);
59
STOFFHeader *getHeader(STOFFInputStreamPtr &input, bool strict);
60
bool checkHeader(STOFFInputStreamPtr &input, STOFFHeader &header, bool strict);
61
}
62
63
STOFFDocument::Confidence STOFFDocument::isFileFormatSupported(librevenge::RVNGInputStream *input, Kind &kind)
64
0
try
65
0
{
66
0
  kind = STOFF_K_UNKNOWN;
67
68
0
  if (!input) {
69
0
    STOFF_DEBUG_MSG(("STOFFDocument::isFileFormatSupported(): no input\n"));
70
0
    return STOFF_C_NONE;
71
0
  }
72
73
0
  STOFFInputStreamPtr ip(new STOFFInputStream(input, false));
74
0
  std::shared_ptr<STOFFHeader> header;
75
#ifdef DEBUG
76
  header.reset(STOFFDocumentInternal::getHeader(ip, false));
77
#else
78
0
  header.reset(STOFFDocumentInternal::getHeader(ip, true));
79
0
#endif
80
81
0
  if (!header.get())
82
0
    return STOFF_C_NONE;
83
0
  kind = static_cast<STOFFDocument::Kind>(header->getKind());
84
0
  return header->isEncrypted() ? STOFF_C_SUPPORTED_ENCRYPTION : STOFF_C_EXCELLENT;
85
0
}
86
0
catch (...)
87
0
{
88
0
  STOFF_DEBUG_MSG(("STOFFDocument::isFileFormatSupported: exception catched\n"));
89
0
  kind = STOFF_K_UNKNOWN;
90
0
  return STOFF_C_NONE;
91
0
}
92
93
STOFFDocument::Result STOFFDocument::parse(librevenge::RVNGInputStream *input, librevenge::RVNGDrawingInterface *documentInterface, char const *password)
94
24.3k
try
95
24.3k
{
96
24.3k
  if (!input)
97
0
    return STOFF_R_UNKNOWN_ERROR;
98
99
24.3k
  STOFFInputStreamPtr ip(new STOFFInputStream(input, false));
100
24.3k
  std::shared_ptr<STOFFHeader> header(STOFFDocumentInternal::getHeader(ip, false));
101
102
24.3k
  if (!header.get()) return STOFF_R_UNKNOWN_ERROR;
103
22.4k
  auto parser=STOFFDocumentInternal::getGraphicParserFromHeader(ip, header.get(), password);
104
22.4k
  if (!parser) return STOFF_R_UNKNOWN_ERROR;
105
22.3k
  parser->parse(documentInterface);
106
22.3k
  return STOFF_R_OK;
107
22.4k
}
108
24.3k
catch (libstoff::FileException)
109
24.3k
{
110
0
  STOFF_DEBUG_MSG(("STOFFDocument::parse: File exception trapped\n"));
111
0
  return STOFF_R_FILE_ACCESS_ERROR;
112
0
}
113
24.3k
catch (libstoff::ParseException)
114
24.3k
{
115
2.98k
  STOFF_DEBUG_MSG(("STOFFDocument::parse: Parse exception trapped\n"));
116
2.98k
  return STOFF_R_PARSE_ERROR;
117
2.98k
}
118
24.3k
catch (libstoff::WrongPasswordException)
119
24.3k
{
120
0
  STOFF_DEBUG_MSG(("STOFFDocument::parse: Parse password trapped\n"));
121
0
  return STOFF_R_PASSWORD_MISSMATCH_ERROR;
122
0
}
123
24.3k
catch (...)
124
24.3k
{
125
  //fixme: too generic
126
0
  STOFF_DEBUG_MSG(("STOFFDocument::parse: Unknown exception trapped\n"));
127
0
  return STOFF_R_UNKNOWN_ERROR;
128
0
}
129
130
STOFFDocument::Result STOFFDocument::parse(librevenge::RVNGInputStream *input, librevenge::RVNGPresentationInterface *documentInterface, char const *password)
131
1.98k
try
132
1.98k
{
133
1.98k
  if (!input)
134
0
    return STOFF_R_UNKNOWN_ERROR;
135
136
1.98k
  STOFFInputStreamPtr ip(new STOFFInputStream(input, false));
137
1.98k
  std::shared_ptr<STOFFHeader> header(STOFFDocumentInternal::getHeader(ip, false));
138
139
1.98k
  if (!header.get()) return STOFF_R_UNKNOWN_ERROR;
140
1.87k
  auto parser=STOFFDocumentInternal::getPresentationParserFromHeader(ip, header.get(), password);
141
1.87k
  if (!parser) return STOFF_R_UNKNOWN_ERROR;
142
1.85k
  parser->parse(documentInterface);
143
1.85k
  return STOFF_R_OK;
144
1.87k
}
145
1.98k
catch (libstoff::FileException)
146
1.98k
{
147
0
  STOFF_DEBUG_MSG(("STOFFDocument::parse: File exception trapped\n"));
148
0
  return STOFF_R_FILE_ACCESS_ERROR;
149
0
}
150
1.98k
catch (libstoff::ParseException)
151
1.98k
{
152
12
  STOFF_DEBUG_MSG(("STOFFDocument::parse: Parse exception trapped\n"));
153
12
  return STOFF_R_PARSE_ERROR;
154
12
}
155
1.98k
catch (libstoff::WrongPasswordException)
156
1.98k
{
157
0
  STOFF_DEBUG_MSG(("STOFFDocument::parse: Parse password trapped\n"));
158
0
  return STOFF_R_PASSWORD_MISSMATCH_ERROR;
159
0
}
160
1.98k
catch (...)
161
1.98k
{
162
  //fixme: too generic
163
0
  STOFF_DEBUG_MSG(("STOFFDocument::parse: Unknown exception trapped\n"));
164
0
  return STOFF_R_UNKNOWN_ERROR;
165
0
}
166
167
STOFFDocument::Result STOFFDocument::parse(librevenge::RVNGInputStream *input, librevenge::RVNGSpreadsheetInterface *documentInterface, char const *password)
168
9.84k
try
169
9.84k
{
170
9.84k
  if (!input)
171
0
    return STOFF_R_UNKNOWN_ERROR;
172
173
9.84k
  STOFFInputStreamPtr ip(new STOFFInputStream(input, false));
174
9.84k
  std::shared_ptr<STOFFHeader> header(STOFFDocumentInternal::getHeader(ip, false));
175
176
9.84k
  if (!header.get()) return STOFF_R_UNKNOWN_ERROR;
177
9.51k
  auto parser=STOFFDocumentInternal::getSpreadsheetParserFromHeader(ip, header.get(), password);
178
9.51k
  if (!parser) return STOFF_R_UNKNOWN_ERROR;
179
9.33k
  parser->parse(documentInterface);
180
9.33k
  return STOFF_R_OK;
181
9.51k
}
182
9.84k
catch (libstoff::FileException)
183
9.84k
{
184
0
  STOFF_DEBUG_MSG(("STOFFDocument::parse: File exception trapped\n"));
185
0
  return STOFF_R_FILE_ACCESS_ERROR;
186
0
}
187
9.84k
catch (libstoff::ParseException)
188
9.84k
{
189
46
  STOFF_DEBUG_MSG(("STOFFDocument::parse: Parse exception trapped\n"));
190
46
  return STOFF_R_PARSE_ERROR;
191
46
}
192
9.84k
catch (libstoff::WrongPasswordException)
193
9.84k
{
194
0
  STOFF_DEBUG_MSG(("STOFFDocument::parse: Parse password trapped\n"));
195
0
  return STOFF_R_PASSWORD_MISSMATCH_ERROR;
196
0
}
197
9.84k
catch (...)
198
9.84k
{
199
  //fixme: too generic
200
0
  STOFF_DEBUG_MSG(("STOFFDocument::parse: Unknown exception trapped\n"));
201
0
  return STOFF_R_UNKNOWN_ERROR;
202
0
}
203
204
STOFFDocument::Result STOFFDocument::parse(librevenge::RVNGInputStream *input, librevenge::RVNGTextInterface *documentInterface, char const *password)
205
25.6k
try
206
25.6k
{
207
25.6k
  if (!input)
208
0
    return STOFF_R_UNKNOWN_ERROR;
209
210
25.6k
  STOFFInputStreamPtr ip(new STOFFInputStream(input, false));
211
25.6k
  std::shared_ptr<STOFFHeader> header(STOFFDocumentInternal::getHeader(ip, false));
212
213
25.6k
  if (!header.get()) return STOFF_R_UNKNOWN_ERROR;
214
23.8k
  auto parser=STOFFDocumentInternal::getTextParserFromHeader(ip, header.get(), password);
215
23.8k
  if (!parser) return STOFF_R_UNKNOWN_ERROR;
216
23.4k
  parser->parse(documentInterface);
217
218
23.4k
  return STOFF_R_OK;
219
23.8k
}
220
25.6k
catch (libstoff::FileException)
221
25.6k
{
222
0
  STOFF_DEBUG_MSG(("STOFFDocument::parse: File exception trapped\n"));
223
0
  return STOFF_R_FILE_ACCESS_ERROR;
224
0
}
225
25.6k
catch (libstoff::ParseException)
226
25.6k
{
227
158
  STOFF_DEBUG_MSG(("STOFFDocument::parse: Parse exception trapped\n"));
228
158
  return STOFF_R_PARSE_ERROR;
229
158
}
230
25.6k
catch (libstoff::WrongPasswordException)
231
25.6k
{
232
0
  STOFF_DEBUG_MSG(("STOFFDocument::parse: Parse password trapped\n"));
233
0
  return STOFF_R_PASSWORD_MISSMATCH_ERROR;
234
0
}
235
25.6k
catch (...)
236
25.6k
{
237
  //fixme: too generic
238
0
  STOFF_DEBUG_MSG(("STOFFDocument::parse: Unknown exception trapped\n"));
239
0
  return STOFF_R_UNKNOWN_ERROR;
240
0
}
241
242
bool STOFFDocument::decodeGraphic(librevenge::RVNGBinaryData const &binary, librevenge::RVNGDrawingInterface *paintInterface)
243
0
try
244
0
{
245
0
  if (!paintInterface || !binary.size()) {
246
0
    STOFF_DEBUG_MSG(("STOFFDocument::decodeGraphic: called with no data or no converter\n"));
247
0
    return false;
248
0
  }
249
0
  STOFFGraphicDecoder tmpHandler(paintInterface);
250
0
  if (!tmpHandler.checkData(binary) || !tmpHandler.readData(binary)) return false;
251
0
  return true;
252
0
}
253
0
catch (...)
254
0
{
255
0
  STOFF_DEBUG_MSG(("STOFFDocument::decodeGraphic: unknown error\n"));
256
0
  return false;
257
0
}
258
259
bool STOFFDocument::decodeSpreadsheet(librevenge::RVNGBinaryData const &binary, librevenge::RVNGSpreadsheetInterface *sheetInterface)
260
0
try
261
0
{
262
0
  if (!sheetInterface || !binary.size()) {
263
0
    STOFF_DEBUG_MSG(("STOFFDocument::decodeSpreadsheet: called with no data or no converter\n"));
264
0
    return false;
265
0
  }
266
0
  STOFFSpreadsheetDecoder tmpHandler(sheetInterface);
267
0
  if (!tmpHandler.checkData(binary) || !tmpHandler.readData(binary)) return false;
268
0
  return true;
269
0
}
270
0
catch (...)
271
0
{
272
0
  STOFF_DEBUG_MSG(("STOFFDocument::decodeSpreadsheet: unknown error\n"));
273
0
  return false;
274
0
}
275
276
bool STOFFDocument::decodeText(librevenge::RVNGBinaryData const &, librevenge::RVNGTextInterface *)
277
0
{
278
0
  STOFF_DEBUG_MSG(("STOFFDocument::decodeText: unimplemented\n"));
279
0
  return false;
280
0
}
281
282
namespace STOFFDocumentInternal
283
{
284
/** return the header corresponding to an input. Or 0L if no input are found */
285
STOFFHeader *getHeader(STOFFInputStreamPtr &ip, bool strict)
286
61.8k
try
287
61.8k
{
288
61.8k
  if (!ip.get()) return nullptr;
289
290
61.8k
  if (ip->size() < 10) return nullptr;
291
292
61.8k
  ip->seek(0, librevenge::RVNG_SEEK_SET);
293
61.8k
  ip->setReadInverted(false);
294
295
61.8k
  auto listHeaders = STOFFHeader::constructHeader(ip);
296
61.8k
  for (auto &h : listHeaders) {
297
57.7k
    if (!STOFFDocumentInternal::checkHeader(ip, h, strict))
298
155
      continue;
299
57.6k
    return new STOFFHeader(h);
300
57.7k
  }
301
4.17k
  return nullptr;
302
61.8k
}
303
61.8k
catch (libstoff::FileException)
304
61.8k
{
305
0
  STOFF_DEBUG_MSG(("STOFFDocumentInternal::STOFFDocument[getHeader]:File exception trapped\n"));
306
0
  return nullptr;
307
0
}
308
61.8k
catch (libstoff::ParseException)
309
61.8k
{
310
0
  STOFF_DEBUG_MSG(("STOFFDocumentInternal::getHeader:Parse exception trapped\n"));
311
0
  return nullptr;
312
0
}
313
61.8k
catch (...)
314
61.8k
{
315
  //fixme: too generic
316
0
  STOFF_DEBUG_MSG(("STOFFDocumentInternal::getHeader:Unknown exception trapped\n"));
317
0
  return nullptr;
318
0
}
319
320
/** Factory wrapper to construct a parser corresponding to an graphic header */
321
std::shared_ptr<STOFFGraphicParser> getGraphicParserFromHeader(STOFFInputStreamPtr &input, STOFFHeader *header, char const *passwd)
322
47.3k
{
323
47.3k
  std::shared_ptr<STOFFGraphicParser> parser;
324
47.3k
  if (!header || (header->getKind()!=STOFFDocument::STOFF_K_DRAW && header->getKind()!=STOFFDocument::STOFF_K_GRAPHIC))
325
210
    return parser;
326
47.1k
  try {
327
47.1k
    if (header->getKind()==STOFFDocument::STOFF_K_DRAW) {
328
40.9k
      SDAParser *sdaParser=new SDAParser(input, header);
329
40.9k
      parser.reset(sdaParser);
330
40.9k
      if (passwd) sdaParser->setDocumentPassword(passwd);
331
40.9k
    }
332
6.16k
    else {
333
6.16k
      SDGParser *sdgParser=new SDGParser(input, header);
334
6.16k
      parser.reset(sdgParser);
335
6.16k
      if (passwd) sdgParser->setDocumentPassword(passwd);
336
6.16k
    }
337
47.1k
  }
338
47.1k
  catch (...) {
339
0
  }
340
47.1k
  return parser;
341
47.1k
}
342
343
/** Factory wrapper to construct a parser corresponding to an presentation header */
344
std::shared_ptr<STOFFGraphicParser> getPresentationParserFromHeader(STOFFInputStreamPtr &input, STOFFHeader *header, char const *passwd)
345
1.87k
{
346
1.87k
  std::shared_ptr<STOFFGraphicParser> parser;
347
1.87k
  if (!header || header->getKind()!=STOFFDocument::STOFF_K_PRESENTATION)
348
16
    return parser;
349
1.85k
  try {
350
1.85k
    SDAParser *sdaParser=new SDAParser(input, header);
351
1.85k
    parser.reset(sdaParser);
352
1.85k
    if (passwd) sdaParser->setDocumentPassword(passwd);
353
1.85k
  }
354
1.85k
  catch (...) {
355
0
  }
356
1.85k
  return parser;
357
1.85k
}
358
359
/** Factory wrapper to construct a parser corresponding to an text header */
360
std::shared_ptr<STOFFTextParser> getTextParserFromHeader(STOFFInputStreamPtr &input, STOFFHeader *header, char const *passwd)
361
81.6k
{
362
81.6k
  std::shared_ptr<STOFFTextParser> parser;
363
81.6k
  if (!header)
364
0
    return parser;
365
81.6k
  if (header->getKind()==STOFFDocument::STOFF_K_TEXT) {
366
46.9k
    try {
367
46.9k
      SDWParser *sdwParser=new SDWParser(input, header);
368
46.9k
      parser.reset(sdwParser);
369
46.9k
      if (passwd) sdwParser->setDocumentPassword(passwd);
370
46.9k
      return parser;
371
46.9k
    }
372
46.9k
    catch (...) {
373
0
    }
374
46.9k
  }
375
#ifdef DEBUG
376
  if (header->getKind()==STOFFDocument::STOFF_K_SPREADSHEET || header->getKind()==STOFFDocument::STOFF_K_DRAW || header->getKind()==STOFFDocument::STOFF_K_GRAPHIC)
377
    return parser;
378
  try {
379
    SDXParser *sdxParser=new SDXParser(input, header);
380
    parser.reset(sdxParser);
381
    if (passwd) sdxParser->setDocumentPassword(passwd);
382
  }
383
  catch (...) {
384
  }
385
#endif
386
34.6k
  return parser;
387
81.6k
}
388
389
/** Factory wrapper to construct a parser corresponding to an spreadsheet header */
390
std::shared_ptr<STOFFSpreadsheetParser> getSpreadsheetParserFromHeader(STOFFInputStreamPtr &input, STOFFHeader *header, char const *passwd)
391
43.7k
{
392
43.7k
  std::shared_ptr<STOFFSpreadsheetParser> parser;
393
43.7k
  if (!header || header->getKind()!=STOFFDocument::STOFF_K_SPREADSHEET)
394
25.0k
    return parser;
395
18.7k
  try {
396
18.7k
    SDCParser *sdcParser=new SDCParser(input, header);
397
18.7k
    parser.reset(sdcParser);
398
18.7k
    if (passwd) sdcParser->setDocumentPassword(passwd);
399
18.7k
  }
400
18.7k
  catch (...) {
401
0
  }
402
18.7k
  return parser;
403
18.7k
}
404
405
/** Wrapper to check a basic header of a mac file */
406
bool checkHeader(STOFFInputStreamPtr &input, STOFFHeader &header, bool strict)
407
57.7k
try
408
57.7k
{
409
57.7k
  std::shared_ptr<STOFFParser> parser=getTextParserFromHeader(input, &header, nullptr);
410
57.7k
  if (!parser) parser=getSpreadsheetParserFromHeader(input, &header, nullptr);
411
57.7k
  if (!parser) parser=getGraphicParserFromHeader(input, &header, nullptr);
412
57.7k
  if (!parser) return false;
413
57.6k
  return parser->checkHeader(&header, strict);
414
57.7k
}
415
57.7k
catch (...)
416
57.7k
{
417
0
  STOFF_DEBUG_MSG(("STOFFDocumentInternal::checkHeader:Unknown exception trapped\n"));
418
0
  return false;
419
0
}
420
421
}
422
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: