Coverage Report

Created: 2026-04-29 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmspub/src/lib/MSPUBDocument.cpp
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/*
3
 * This file is part of the libmspub project.
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
10
#include <libmspub/libmspub.h>
11
12
#include <memory>
13
14
#include "MSPUBCollector.h"
15
#include "MSPUBParser.h"
16
#include "MSPUBParser2k.h"
17
#include "MSPUBParser97.h"
18
#include "libmspub_utils.h"
19
20
namespace libmspub
21
{
22
23
namespace
24
{
25
26
enum MSPUBVersion
27
{
28
  MSPUB_UNKNOWN_VERSION = 0,
29
  MSPUB_2K,
30
  MSPUB_2K2
31
};
32
33
MSPUBVersion getVersion(librevenge::RVNGInputStream *input)
34
12.5k
{
35
12.5k
  try
36
12.5k
  {
37
12.5k
    if (!input->isStructured())
38
729
      return MSPUB_UNKNOWN_VERSION;
39
40
11.8k
    std::unique_ptr<librevenge::RVNGInputStream> contentsStream(input->getSubStreamByName("Contents"));
41
11.8k
    if (!contentsStream)
42
1.66k
      return MSPUB_UNKNOWN_VERSION;
43
44
10.1k
    if (0xe8 != readU8(contentsStream.get()) || 0xac != readU8(contentsStream.get()))
45
563
      return MSPUB_UNKNOWN_VERSION;
46
47
9.63k
    unsigned char magicVersionByte = readU8(contentsStream.get());
48
49
9.63k
    if (0x00 != readU8(contentsStream.get()))
50
2
      return MSPUB_UNKNOWN_VERSION;
51
52
9.63k
    MSPUBVersion version = MSPUB_UNKNOWN_VERSION;
53
9.63k
    switch (magicVersionByte)
54
9.63k
    {
55
5.48k
    case 0x2C:
56
5.48k
      version = MSPUB_2K2;
57
5.48k
      break;
58
4.12k
    case 0x22:
59
4.12k
      version =  MSPUB_2K;
60
4.12k
      break;
61
12
    default:
62
12
      break;
63
9.63k
    }
64
9.62k
    return version;
65
9.63k
  }
66
12.5k
  catch (...)
67
12.5k
  {
68
3
    return MSPUB_UNKNOWN_VERSION;
69
3
  }
70
71
12.5k
}
72
73
} // anonymous namespace
74
75
76
77
/**
78
Analyzes the content of an input stream to see if it can be parsed
79
\param input The input stream
80
\return A value that indicates whether the content from the input
81
stream is a Microsoft Publisher Document that libmspub is able to parse
82
*/
83
PUBAPI bool MSPUBDocument::isSupported(librevenge::RVNGInputStream *input)
84
0
{
85
0
  if (!input)
86
0
    return false;
87
88
0
  try
89
0
  {
90
0
    MSPUBVersion version = getVersion(input);
91
0
    if (version == MSPUB_UNKNOWN_VERSION)
92
0
      return false;
93
94
0
    if (version == MSPUB_2K2)
95
0
    {
96
0
      std::unique_ptr<librevenge::RVNGInputStream> escherStream(input->getSubStreamByName("Escher/EscherStm"));
97
0
      if (!escherStream)
98
0
        return false;
99
0
      std::unique_ptr<librevenge::RVNGInputStream> quillStream(input->getSubStreamByName("Quill/QuillSub/CONTENTS"));
100
0
      if (!quillStream)
101
0
        return false;
102
0
    }
103
0
    return true;
104
0
  }
105
0
  catch (...)
106
0
  {
107
0
    return false;
108
0
  }
109
0
}
110
111
/**
112
Parses the input stream content. It will make callbacks to the functions provided by a
113
RVNGDrawingInterface class implementation when needed. This is often commonly called the
114
'main parsing routine'.
115
\param input The input stream
116
\param painter A MSPUBPainterInterface implementation
117
\return A value that indicates whether the parsing was successful
118
*/
119
PUBAPI bool MSPUBDocument::parse(librevenge::RVNGInputStream *input, librevenge::RVNGDrawingInterface *painter)
120
12.5k
{
121
12.5k
  if (!input || !painter)
122
0
    return false;
123
124
12.5k
  try
125
12.5k
  {
126
12.5k
    MSPUBCollector collector(painter);
127
12.5k
    input->seek(0, librevenge::RVNG_SEEK_SET);
128
12.5k
    std::unique_ptr<MSPUBParser> parser;
129
12.5k
    switch (getVersion(input))
130
12.5k
    {
131
4.12k
    case MSPUB_2K:
132
4.12k
    {
133
4.12k
      std::unique_ptr<librevenge::RVNGInputStream> quillStream(input->getSubStreamByName("Quill/QuillSub/CONTENTS"));
134
4.12k
      if (!quillStream)
135
3.64k
        parser.reset(new MSPUBParser97(input, &collector));
136
482
      else
137
482
        parser.reset(new MSPUBParser2k(input, &collector));
138
4.12k
      break;
139
0
    }
140
5.48k
    case MSPUB_2K2:
141
5.48k
    {
142
5.48k
      parser.reset(new MSPUBParser(input, &collector));
143
5.48k
      break;
144
0
    }
145
2.97k
    default:
146
2.97k
      return false;
147
12.5k
    }
148
9.61k
    if (parser)
149
9.61k
    {
150
9.61k
      return parser->parse();
151
9.61k
    }
152
0
    return false;
153
9.61k
  }
154
12.5k
  catch (...)
155
12.5k
  {
156
2.99k
    return false;
157
2.99k
  }
158
12.5k
}
159
160
}
161
162
/* vim:set shiftwidth=2 softtabstop=2 expandtab: */