Coverage Report

Created: 2026-07-20 07:04

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
2.99k
    : m_input(input)
58
2.99k
    , m_version(vers)
59
2.99k
    , m_oleParser()
60
2.99k
    , m_unparsedNameSet()
61
2.99k
  {
62
2.99k
  }
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
2.99k
  : m_state(new PowerPoint3OLEInternal::State(input, vers))
80
2.99k
{
81
2.99k
  char const *mainOle =(version()<=4 ? "PP40" : "PowerPoint Document");
82
2.99k
  if (input && input->isStructured() && input->getSubStreamByName(mainOle))
83
2.99k
    m_state->m_oleParser.reset(new MWAWOLEParser(mainOle, fontConverter, fId));
84
2.99k
}
85
86
PowerPoint3OLE::~PowerPoint3OLE()
87
2.99k
{
88
2.99k
}
89
90
int PowerPoint3OLE::version() const
91
8.36k
{
92
8.36k
  return m_state->m_version;
93
8.36k
}
94
95
int PowerPoint3OLE::getFontEncoding() const
96
2.99k
{
97
2.99k
  if (m_state->m_oleParser)
98
2.99k
    return m_state->m_oleParser->getFontEncoding();
99
0
  return -1;
100
2.99k
}
101
102
void PowerPoint3OLE::updateMetaData(librevenge::RVNGPropertyList &metaData) const
103
1.20k
{
104
1.20k
  if (m_state->m_oleParser)
105
1.20k
    m_state->m_oleParser->updateMetaData(metaData);
106
1.20k
}
107
108
////////////////////////////////////////////////////////////
109
// the parser
110
////////////////////////////////////////////////////////////
111
bool PowerPoint3OLE::parse()
112
2.99k
{
113
2.99k
  int const vers=version();
114
2.99k
  MWAWInputStreamPtr input=m_state->m_input;
115
2.99k
  if (!input || !m_state->m_oleParser || !m_state->m_oleParser->parse(input)) return false;
116
2.99k
  std::vector<std::string> unparsed = m_state->m_oleParser->getNotParse();
117
118
6.13k
  for (auto const &name : unparsed) {
119
    // separated the directory and the name
120
    //    MatOST/MatadorObject1/Ole10Native
121
    //      -> dir="MatOST/MatadorObject1", base="Ole10Native"
122
6.13k
    std::string::size_type pos = name.find_last_of('/');
123
6.13k
    std::string base;
124
6.13k
    if (pos == std::string::npos) base = name;
125
1.15k
    else if (pos == 0) base = name.substr(1);
126
1.15k
    else
127
1.15k
      base = name.substr(pos+1);
128
129
6.13k
    MWAWInputStreamPtr ole = input->getSubStreamByName(name.c_str());
130
6.13k
    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
6.13k
    ole->setReadInverted(true);
135
6.13k
    bool done=false;
136
6.13k
    switch (base[0]) {
137
3.00k
    case 'C':
138
3.00k
      if (base=="Current User")
139
2.36k
        done=parseCurrentUser(ole, name);
140
632
      else if (base=="Current ID")
141
56
        done=parseCurrentId(ole, name);
142
3.00k
      break;
143
470
    case 'H':
144
470
      if (vers>=7 && name=="Header")
145
463
        done=parseHeader(ole, name);
146
470
      break;
147
1.33k
    case 'P':
148
1.33k
      if (vers>=7 && name=="PersistentStorage Directory")
149
1.31k
        done=parsePersistentStorage(ole, name);
150
1.33k
      break;
151
1.33k
    default:
152
1.33k
      break;
153
6.13k
    }
154
6.13k
    if (done) continue;
155
1.96k
    m_state->m_unparsedNameSet.insert(name);
156
1.96k
  }
157
2.99k
  return true;
158
2.99k
}
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
56
{
190
56
  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
55
  libmwaw::DebugFile ascFile(input);
195
55
  ascFile.open(name);
196
55
  input->seek(0, librevenge::RVNG_SEEK_SET);
197
55
  libmwaw::DebugStream f;
198
55
  f << "Entries(CurrentId):";
199
55
  auto val=int(input->readLong(4));
200
55
  if (val) f << "id=" << val << ",";
201
55
  ascFile.addPos(0);
202
55
  ascFile.addNote(f.str().c_str());
203
55
  return true;
204
56
}
205
206
bool PowerPoint3OLE::parseCurrentUser(MWAWInputStreamPtr input, std::string const &name)
207
2.36k
{
208
2.36k
  int const vers=version();
209
2.36k
  int const szSize=vers<=4 ? 1 : 4;
210
2.36k
  if (!input||input->size() < szSize) {
211
23
    MWAW_DEBUG_MSG(("PowerPoint3OLE::parseCurrentUser: can not find the input\n"));
212
23
    return false;
213
23
  }
214
2.34k
  libmwaw::DebugFile ascFile(input);
215
2.34k
  ascFile.open(name);
216
2.34k
  input->seek(0, librevenge::RVNG_SEEK_SET);
217
2.34k
  long endPos=input->size();
218
2.34k
  libmwaw::DebugStream f;
219
2.34k
  f << "Entries(CurrentUser):";
220
2.34k
  auto sSz=int(input->readULong(szSize));
221
2.34k
  if (sSz<0 || sSz>input->size()-szSize) {
222
96
    MWAW_DEBUG_MSG(("PowerPoint3OLE::parseCurrentUser: the stream size seems bad\n"));
223
96
    f << "###sSz,";
224
96
    ascFile.addPos(0);
225
96
    ascFile.addNote(f.str().c_str());
226
96
    return true;
227
96
  }
228
2.25k
  std::string user;
229
7.43k
  for (int c=0; c<sSz; ++c) {
230
5.18k
    auto ch=char(input->readULong(1));
231
5.18k
    if (ch)
232
4.29k
      user+=ch;
233
888
    else if (c+1!=sSz)
234
865
      f << "###";
235
5.18k
  }
236
2.25k
  f << user;
237
2.25k
  ascFile.addPos(0);
238
2.25k
  ascFile.addNote(f.str().c_str());
239
2.25k
  if (input->tell()!=endPos) {
240
1.73k
    ascFile.addPos(input->tell());
241
1.73k
    ascFile.addNote("CurrentUser:##extra");
242
1.73k
  }
243
2.25k
  return true;
244
2.34k
}
245
246
bool PowerPoint3OLE::parseHeader(MWAWInputStreamPtr input, std::string const &name)
247
463
{
248
463
  if (!input || input->size()<19) {
249
3
    MWAW_DEBUG_MSG(("PowerPoint3OLE::parseHeader: the input seems bad\n"));
250
3
    return false;
251
3
  }
252
460
  input->seek(0, librevenge::RVNG_SEEK_SET);
253
460
  long endPos=input->size();
254
460
  libmwaw::DebugFile ascFile(input);
255
460
  ascFile.open(name);
256
460
  libmwaw::DebugStream f;
257
460
  f << "Entries(Headr):";
258
460
  std::string text; // Microsoft (R) PowerPoint (R) Windows
259
15.2k
  for (long i=0; i<endPos; ++i) {
260
15.2k
    auto c=char(input->readULong(1));
261
15.2k
    if (!c) break;
262
14.8k
    text+=c;
263
14.8k
  }
264
460
  f << text << ",";
265
460
  if (input->tell()+18>endPos) {
266
16
    MWAW_DEBUG_MSG(("PowerPoint3OLE::parseHeader: the input seems short\n"));
267
16
    f << "###";
268
16
    ascFile.addDelimiter(input->tell(),'|');
269
16
    ascFile.addPos(0);
270
16
    ascFile.addNote(f.str().c_str());
271
16
    return true;
272
16
  }
273
4.44k
  for (int i=0; i<9; ++i) {
274
3.99k
    auto val=int(input->readULong(2));
275
3.99k
    int const expected[]= {7,0,0x3f0,0,0xc05f,0xe391,1,0,0};
276
3.99k
    if (val!=expected[i]) f << "f" << i << "=" << std::hex << val << std::dec << ",";
277
3.99k
  }
278
444
  ascFile.addPos(0);
279
444
  ascFile.addNote(f.str().c_str());
280
444
  if (input->tell()!=endPos) {
281
112
    ascFile.addPos(input->tell());
282
112
    ascFile.addNote("Headr:###");
283
112
  }
284
444
  return true;
285
460
}
286
287
bool PowerPoint3OLE::parsePersistentStorage(MWAWInputStreamPtr input, std::string const &name)
288
1.31k
{
289
1.31k
  if (!input || input->size()<62) {
290
11
    MWAW_DEBUG_MSG(("PowerPoint3OLE::parsePersistentStorage: the input seems bad\n"));
291
11
    return false;
292
11
  }
293
1.30k
  input->seek(0, librevenge::RVNG_SEEK_SET);
294
1.30k
  long endPos=input->size();
295
1.30k
  libmwaw::DebugFile ascFile(input);
296
1.30k
  ascFile.open(name);
297
1.30k
  libmwaw::DebugStream f;
298
1.30k
  f << "Entries(PersistentStorage):";
299
1.30k
  int val;
300
3.92k
  for (int i=0; i<2; ++i) { // f1=3c6|3e0
301
2.61k
    val=int(input->readULong(2));
302
2.61k
    int const expected[]= {7,0x3e0};
303
2.61k
    if (val!=expected[i])
304
2.36k
      f << "f" << i << "=" << val << ",";
305
2.61k
  }
306
18.2k
  for (int i=0; i<13; ++i) { // f9=f11=f13=1
307
16.9k
    val=int(input->readULong(2));
308
16.9k
    if (val) f << "f" << i+2 << "=" << val << ",";
309
16.9k
  }
310
1.30k
  auto sSz=int(input->readULong(4));
311
1.30k
  if (sSz<0 || endPos-30-8<sSz || 30+sSz+8>endPos) {
312
287
    MWAW_DEBUG_MSG(("PowerPoint3OLE::parsePersistentStorage: the string size seems bad\n"));
313
287
    f << "###sSz=" << sSz << ",";
314
287
    ascFile.addPos(0);
315
287
    ascFile.addNote(f.str().c_str());
316
287
    return true;
317
287
  }
318
1.02k
  std::string text; // PowerPoint Document
319
22.3k
  for (int i=0; i<sSz; ++i) {
320
21.2k
    auto c=char(input->readULong(1));
321
21.2k
    if (c)
322
11.0k
      text+=c;
323
10.2k
    else if (i+1!=sSz) {
324
10.0k
      MWAW_DEBUG_MSG(("PowerPoint3OLE::parsePersistentStorage: the name seems bad\n"));
325
10.0k
      f << "##name,";
326
10.0k
    }
327
21.2k
  }
328
1.02k
  f << text << ",";
329
5.10k
  for (int i=0; i<4; ++i) { // g0=1
330
4.08k
    val=int(input->readULong(2));
331
4.08k
    if (val) f << "g" << i << "=" << val << ",";
332
4.08k
  }
333
1.02k
  ascFile.addPos(0);
334
1.02k
  ascFile.addNote(f.str().c_str());
335
1.02k
  if (input->tell()!=endPos) { // seems junk, unsure
336
1.01k
    ascFile.addPos(input->tell());
337
1.01k
    ascFile.addNote("_");
338
1.01k
  }
339
1.02k
  return true;
340
1.30k
}
341
342
////////////////////////////////////////////////////////////
343
// try to send data
344
////////////////////////////////////////////////////////////
345
346
347
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: