Coverage Report

Created: 2026-10-28 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/PowerPoint3OLE.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
/* libmwaw
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
#include <algorithm>
35
#include <iomanip>
36
#include <iostream>
37
#include <set>
38
#include <sstream>
39
#include <utility>
40
41
#include <librevenge/librevenge.h>
42
43
#include "MWAWDebug.hxx"
44
#include "MWAWEntry.hxx"
45
#include "MWAWOLEParser.hxx"
46
47
#include "PowerPoint3OLE.hxx"
48
49
/** Internal: the structures of a PowerPoint3OLE */
50
namespace PowerPoint3OLEInternal
51
{
52
////////////////////////////////////////
53
//! Internal: the state of a PowerPoint3OLE
54
struct State {
55
  //! constructor
56
  explicit State(MWAWInputStreamPtr input, int vers)
57
3.49k
    : m_input(input)
58
3.49k
    , m_version(vers)
59
3.49k
    , m_oleParser()
60
3.49k
    , m_unparsedNameSet()
61
3.49k
  {
62
3.49k
  }
63
  /** the input */
64
  MWAWInputStreamPtr m_input;
65
  /** the version */
66
  int m_version;
67
  /** the ole parser */
68
  std::shared_ptr<MWAWOLEParser> m_oleParser;
69
  /** the list of unparsed zone */
70
  std::set<std::string> m_unparsedNameSet;
71
};
72
73
}
74
75
////////////////////////////////////////////////////////////
76
// constructor/destructor, ...
77
////////////////////////////////////////////////////////////
78
PowerPoint3OLE::PowerPoint3OLE(MWAWInputStreamPtr const &input, int vers, MWAWFontConverterPtr const &fontConverter, int fId)
79
3.49k
  : m_state(new PowerPoint3OLEInternal::State(input, vers))
80
3.49k
{
81
3.49k
  char const *mainOle =(version()<=4 ? "PP40" : "PowerPoint Document");
82
3.49k
  if (input && input->isStructured() && input->getSubStreamByName(mainOle))
83
3.49k
    m_state->m_oleParser.reset(new MWAWOLEParser(mainOle, fontConverter, fId));
84
3.49k
}
85
86
PowerPoint3OLE::~PowerPoint3OLE()
87
3.49k
{
88
3.49k
}
89
90
int PowerPoint3OLE::version() const
91
9.54k
{
92
9.54k
  return m_state->m_version;
93
9.54k
}
94
95
int PowerPoint3OLE::getFontEncoding() const
96
3.49k
{
97
3.49k
  if (m_state->m_oleParser)
98
3.49k
    return m_state->m_oleParser->getFontEncoding();
99
0
  return -1;
100
3.49k
}
101
102
void PowerPoint3OLE::updateMetaData(librevenge::RVNGPropertyList &metaData) const
103
1.43k
{
104
1.43k
  if (m_state->m_oleParser)
105
1.43k
    m_state->m_oleParser->updateMetaData(metaData);
106
1.43k
}
107
108
////////////////////////////////////////////////////////////
109
// the parser
110
////////////////////////////////////////////////////////////
111
bool PowerPoint3OLE::parse()
112
3.49k
{
113
3.49k
  int const vers=version();
114
3.49k
  MWAWInputStreamPtr input=m_state->m_input;
115
3.49k
  if (!input || !m_state->m_oleParser || !m_state->m_oleParser->parse(input)) return false;
116
3.49k
  std::vector<std::string> unparsed = m_state->m_oleParser->getNotParse();
117
118
5.55k
  for (auto const &name : unparsed) {
119
    // separated the directory and the name
120
    //    MatOST/MatadorObject1/Ole10Native
121
    //      -> dir="MatOST/MatadorObject1", base="Ole10Native"
122
5.55k
    std::string::size_type pos = name.find_last_of('/');
123
5.55k
    std::string base;
124
5.55k
    if (pos == std::string::npos) base = name;
125
941
    else if (pos == 0) base = name.substr(1);
126
933
    else
127
933
      base = name.substr(pos+1);
128
129
5.55k
    MWAWInputStreamPtr ole = input->getSubStreamByName(name.c_str());
130
5.55k
    if (!ole.get()) {
131
0
      MWAW_DEBUG_MSG(("PowerPoint3OLE::createZones: error: can not find OLE part: \"%s\"\n", name.c_str()));
132
0
      continue;
133
0
    }
134
5.55k
    ole->setReadInverted(true);
135
5.55k
    bool done=false;
136
5.55k
    switch (base[0]) {
137
3.14k
    case 'C':
138
3.14k
      if (base=="Current User")
139
2.56k
        done=parseCurrentUser(ole, name);
140
579
      else if (base=="Current ID")
141
40
        done=parseCurrentId(ole, name);
142
3.14k
      break;
143
5
    case 'H':
144
5
      if (vers>=7 && name=="Header")
145
0
        done=parseHeader(ole, name);
146
5
      break;
147
1.67k
    case 'P':
148
1.67k
      if (vers>=7 && name=="PersistentStorage Directory")
149
1.58k
        done=parsePersistentStorage(ole, name);
150
1.67k
      break;
151
731
    default:
152
731
      break;
153
5.55k
    }
154
5.55k
    if (done) continue;
155
1.39k
    m_state->m_unparsedNameSet.insert(name);
156
1.39k
  }
157
3.49k
  return true;
158
3.49k
}
159
160
void PowerPoint3OLE::checkForUnparsedStream()
161
0
{
162
0
  int const vers=version();
163
0
  for (auto const &name : m_state->m_unparsedNameSet) {
164
0
    if (vers>=7 && name=="Text_Content") continue;
165
0
    auto pos = name.find_last_of('/');
166
0
    std::string base;
167
0
    if (pos == std::string::npos) base = name;
168
0
    else if (pos == 0) base = name.substr(1);
169
0
    else
170
0
      base = name.substr(pos+1);
171
0
    MWAWInputStreamPtr ole = m_state->m_input->getSubStreamByName(name.c_str());
172
0
    if (!ole.get()) {
173
0
      MWAW_DEBUG_MSG(("PowerPoint3OLE::checkForUnparsedStream: error: can not find OLE part: \"%s\"\n", name.c_str()));
174
0
      continue;
175
0
    }
176
0
    libmwaw::DebugFile asciiFile(ole);
177
0
    asciiFile.open(name);
178
0
    libmwaw::DebugStream f;
179
0
    f << "Entries(" << base << "):";
180
0
    asciiFile.addPos(0);
181
0
    asciiFile.addNote(f.str().c_str());
182
0
  }
183
0
}
184
185
////////////////////////////////////////////////////////////
186
// try to read the different stream
187
////////////////////////////////////////////////////////////
188
bool PowerPoint3OLE::parseCurrentId(MWAWInputStreamPtr input, std::string const &name)
189
40
{
190
40
  if (!input||input->size()!=4) {
191
1
    MWAW_DEBUG_MSG(("PowerPoint3OLE::parseCurrentId: can not find the input\n"));
192
1
    return false;
193
1
  }
194
39
  libmwaw::DebugFile ascFile(input);
195
39
  ascFile.open(name);
196
39
  input->seek(0, librevenge::RVNG_SEEK_SET);
197
39
  libmwaw::DebugStream f;
198
39
  f << "Entries(CurrentId):";
199
39
  auto val=int(input->readLong(4));
200
39
  if (val) f << "id=" << val << ",";
201
39
  ascFile.addPos(0);
202
39
  ascFile.addNote(f.str().c_str());
203
39
  return true;
204
40
}
205
206
bool PowerPoint3OLE::parseCurrentUser(MWAWInputStreamPtr input, std::string const &name)
207
2.56k
{
208
2.56k
  int const vers=version();
209
2.56k
  int const szSize=vers<=4 ? 1 : 4;
210
2.56k
  if (!input||input->size() < szSize) {
211
19
    MWAW_DEBUG_MSG(("PowerPoint3OLE::parseCurrentUser: can not find the input\n"));
212
19
    return false;
213
19
  }
214
2.54k
  libmwaw::DebugFile ascFile(input);
215
2.54k
  ascFile.open(name);
216
2.54k
  input->seek(0, librevenge::RVNG_SEEK_SET);
217
2.54k
  long endPos=input->size();
218
2.54k
  libmwaw::DebugStream f;
219
2.54k
  f << "Entries(CurrentUser):";
220
2.54k
  auto sSz=int(input->readULong(szSize));
221
2.54k
  if (sSz<0 || sSz>input->size()-szSize) {
222
109
    MWAW_DEBUG_MSG(("PowerPoint3OLE::parseCurrentUser: the stream size seems bad\n"));
223
109
    f << "###sSz,";
224
109
    ascFile.addPos(0);
225
109
    ascFile.addNote(f.str().c_str());
226
109
    return true;
227
109
  }
228
2.43k
  std::string user;
229
5.29k
  for (int c=0; c<sSz; ++c) {
230
2.85k
    auto ch=char(input->readULong(1));
231
2.85k
    if (ch)
232
1.81k
      user+=ch;
233
1.03k
    else if (c+1!=sSz)
234
1.01k
      f << "###";
235
2.85k
  }
236
2.43k
  f << user;
237
2.43k
  ascFile.addPos(0);
238
2.43k
  ascFile.addNote(f.str().c_str());
239
2.43k
  if (input->tell()!=endPos) {
240
2.39k
    ascFile.addPos(input->tell());
241
2.39k
    ascFile.addNote("CurrentUser:##extra");
242
2.39k
  }
243
2.43k
  return true;
244
2.54k
}
245
246
bool PowerPoint3OLE::parseHeader(MWAWInputStreamPtr input, std::string const &name)
247
0
{
248
0
  if (!input || input->size()<19) {
249
0
    MWAW_DEBUG_MSG(("PowerPoint3OLE::parseHeader: the input seems bad\n"));
250
0
    return false;
251
0
  }
252
0
  input->seek(0, librevenge::RVNG_SEEK_SET);
253
0
  long endPos=input->size();
254
0
  libmwaw::DebugFile ascFile(input);
255
0
  ascFile.open(name);
256
0
  libmwaw::DebugStream f;
257
0
  f << "Entries(Headr):";
258
0
  std::string text; // Microsoft (R) PowerPoint (R) Windows
259
0
  for (long i=0; i<endPos; ++i) {
260
0
    auto c=char(input->readULong(1));
261
0
    if (!c) break;
262
0
    text+=c;
263
0
  }
264
0
  f << text << ",";
265
0
  if (input->tell()+18>endPos) {
266
0
    MWAW_DEBUG_MSG(("PowerPoint3OLE::parseHeader: the input seems short\n"));
267
0
    f << "###";
268
0
    ascFile.addDelimiter(input->tell(),'|');
269
0
    ascFile.addPos(0);
270
0
    ascFile.addNote(f.str().c_str());
271
0
    return true;
272
0
  }
273
0
  for (int i=0; i<9; ++i) {
274
0
    auto val=int(input->readULong(2));
275
0
    int const expected[]= {7,0,0x3f0,0,0xc05f,0xe391,1,0,0};
276
0
    if (val!=expected[i]) f << "f" << i << "=" << std::hex << val << std::dec << ",";
277
0
  }
278
0
  ascFile.addPos(0);
279
0
  ascFile.addNote(f.str().c_str());
280
0
  if (input->tell()!=endPos) {
281
0
    ascFile.addPos(input->tell());
282
0
    ascFile.addNote("Headr:###");
283
0
  }
284
0
  return true;
285
0
}
286
287
bool PowerPoint3OLE::parsePersistentStorage(MWAWInputStreamPtr input, std::string const &name)
288
1.58k
{
289
1.58k
  if (!input || input->size()<62) {
290
10
    MWAW_DEBUG_MSG(("PowerPoint3OLE::parsePersistentStorage: the input seems bad\n"));
291
10
    return false;
292
10
  }
293
1.57k
  input->seek(0, librevenge::RVNG_SEEK_SET);
294
1.57k
  long endPos=input->size();
295
1.57k
  libmwaw::DebugFile ascFile(input);
296
1.57k
  ascFile.open(name);
297
1.57k
  libmwaw::DebugStream f;
298
1.57k
  f << "Entries(PersistentStorage):";
299
1.57k
  int val;
300
4.72k
  for (int i=0; i<2; ++i) { // f1=3c6|3e0
301
3.15k
    val=int(input->readULong(2));
302
3.15k
    int const expected[]= {7,0x3e0};
303
3.15k
    if (val!=expected[i])
304
3.15k
      f << "f" << i << "=" << val << ",";
305
3.15k
  }
306
22.0k
  for (int i=0; i<13; ++i) { // f9=f11=f13=1
307
20.4k
    val=int(input->readULong(2));
308
20.4k
    if (val) f << "f" << i+2 << "=" << val << ",";
309
20.4k
  }
310
1.57k
  auto sSz=int(input->readULong(4));
311
1.57k
  if (sSz<0 || endPos-30-8<sSz || 30+sSz+8>endPos) {
312
45
    MWAW_DEBUG_MSG(("PowerPoint3OLE::parsePersistentStorage: the string size seems bad\n"));
313
45
    f << "###sSz=" << sSz << ",";
314
45
    ascFile.addPos(0);
315
45
    ascFile.addNote(f.str().c_str());
316
45
    return true;
317
45
  }
318
1.53k
  std::string text; // PowerPoint Document
319
16.3k
  for (int i=0; i<sSz; ++i) {
320
14.8k
    auto c=char(input->readULong(1));
321
14.8k
    if (c)
322
6.25k
      text+=c;
323
8.57k
    else if (i+1!=sSz) {
324
8.56k
      MWAW_DEBUG_MSG(("PowerPoint3OLE::parsePersistentStorage: the name seems bad\n"));
325
8.56k
      f << "##name,";
326
8.56k
    }
327
14.8k
  }
328
1.53k
  f << text << ",";
329
7.65k
  for (int i=0; i<4; ++i) { // g0=1
330
6.12k
    val=int(input->readULong(2));
331
6.12k
    if (val) f << "g" << i << "=" << val << ",";
332
6.12k
  }
333
1.53k
  ascFile.addPos(0);
334
1.53k
  ascFile.addNote(f.str().c_str());
335
1.53k
  if (input->tell()!=endPos) { // seems junk, unsure
336
1.52k
    ascFile.addPos(input->tell());
337
1.52k
    ascFile.addNote("_");
338
1.52k
  }
339
1.53k
  return true;
340
1.57k
}
341
342
////////////////////////////////////////////////////////////
343
// try to send data
344
////////////////////////////////////////////////////////////
345
346
347
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: