Coverage Report

Created: 2026-09-06 07:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwps/src/lib/WPSOLEObject.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) 2009, 2011 Alonso Laurent (alonso@loria.fr)
11
 * Copyright (C) 2006, 2007 Andrew Ziem
12
 * Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
13
 * Copyright (C) 2004 Marc Maurer (uwog@uwog.net)
14
 * Copyright (C) 2003-2005 William Lachance (william.lachance@sympatico.ca)
15
 *
16
 * For minor contributions see the git repository.
17
 *
18
 * Alternatively, the contents of this file may be used under the terms
19
 * of the GNU Lesser General Public License Version 2.1 or later
20
 * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are
21
 * applicable instead of those above.
22
 *
23
 * For further information visit http://libwps.sourceforge.net
24
 */
25
26
#include <sstream>
27
#include <string>
28
29
#include <librevenge/librevenge.h>
30
31
#include "WPSOLEObject.h"
32
33
#include "WPSDebug.h"
34
#include "WPSStream.h"
35
#include "WPSStringStream.h"
36
37
using namespace libwps;
38
39
40
////////////////////////////////////////////////////////////
41
// read the OLE object
42
////////////////////////////////////////////////////////////
43
bool WPSOLEObject::readMetafile(std::shared_ptr<WPSStream> stream, WPSEmbeddedObject &object, long endPos, bool strict)
44
481
{
45
481
  if (!stream) return false;
46
481
  RVNGInputStreamPtr &input=stream->m_input;
47
481
  libwps::DebugFile &ascFile=stream->m_ascii;
48
481
  libwps::DebugStream f;
49
50
481
  if (endPos<=0) endPos=stream->m_eof;
51
481
  else if (endPos>stream->m_eof) endPos=stream->m_eof;
52
53
481
  long pos = input->tell();
54
481
  if (pos+8+4>endPos)
55
24
    return false;
56
457
  f << "Entries(Metafile):";
57
457
  f << "type=" << libwps::readU16(input) << ",";
58
457
  float fDim[2];
59
914
  for (auto &d : fDim) d=float(libwps::read16(input)/1440.);
60
457
  if (fDim[0]<0||fDim[1]<0)
61
76
  {
62
76
    input->seek(pos, librevenge::RVNG_SEEK_SET);
63
76
    return false;
64
76
  }
65
381
  if (object.m_size==Vec2f() && fDim[0]>0 && fDim[1]>0)
66
133
  {
67
133
    object.m_size=Vec2f(fDim[0],fDim[1]);
68
133
    f << "sz=" << object.m_size << ",";
69
133
  }
70
381
  input->seek(2, librevenge::RVNG_SEEK_CUR); // seek handle
71
381
  if (strict)
72
276
  {
73
276
    if (!checkIsWMF(stream, endPos))
74
154
    {
75
154
      input->seek(pos, librevenge::RVNG_SEEK_SET);
76
154
      return false;
77
154
    }
78
122
    input->seek(pos+8, librevenge::RVNG_SEEK_SET);
79
122
  }
80
227
  librevenge::RVNGBinaryData data;
81
227
  if (!libwps::readData(input, static_cast<unsigned long>(endPos-pos-8), data))
82
0
  {
83
0
    WPS_DEBUG_MSG(("WPSOLEObject::readMetafile: I can not find the picture\n"));
84
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
85
0
    return false;
86
0
  }
87
227
  object.add(data,"application/x-wmf");
88
#ifdef DEBUG_WITH_FILES
89
  ascFile.skipZone(pos+8, endPos-1);
90
  std::stringstream s;
91
  static int fileId=0;
92
  s << "PictMeta" << ++fileId << ".wmf";
93
  libwps::Debug::dumpFile(data, s.str().c_str());
94
#endif
95
96
227
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
97
227
  ascFile.addPos(pos);
98
227
  ascFile.addNote(f.str().c_str());
99
227
  return true;
100
227
}
101
102
bool WPSOLEObject::readWMF(std::shared_ptr<WPSStream> stream, WPSEmbeddedObject &object,long endPos)
103
13.2k
{
104
13.2k
  if (!stream) return false;
105
13.2k
  RVNGInputStreamPtr &input=stream->m_input;
106
13.2k
  libwps::DebugFile &ascFile=stream->m_ascii;
107
13.2k
  long pos=input->tell();
108
109
13.2k
  long lastPos=endPos<=0 ? stream->m_eof : endPos;
110
13.2k
  if (lastPos>stream->m_eof) lastPos=stream->m_eof;
111
13.2k
  if (!checkIsWMF(stream,lastPos)) return false;
112
113
1.28k
  input->seek(pos+6, librevenge::RVNG_SEEK_SET);
114
1.28k
  auto fSize = long(libwps::read32(input));
115
1.28k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
116
1.28k
  librevenge::RVNGBinaryData data;
117
1.28k
  if (!libwps::readData(input, static_cast<unsigned long>(2*fSize), data))
118
0
  {
119
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
120
0
    return false;
121
0
  }
122
1.28k
  object.add(data,"application/x-wmf");
123
#ifdef DEBUG_WITH_FILES
124
  std::stringstream f;
125
  static volatile int actPict = 0;
126
  f << "WMF" << actPict++ << ".wmf";
127
  libwps::Debug::dumpFile(data, f.str().c_str());
128
  ascFile.skipZone(pos,pos+2*fSize-1);
129
#endif
130
1.28k
  if (endPos>0 && input->tell()!=endPos)
131
61
  {
132
61
    ascFile.addPos(input->tell());
133
61
    ascFile.addNote("_");
134
61
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
135
61
  }
136
1.28k
  return true;
137
1.28k
}
138
139
bool WPSOLEObject::readOLE(std::shared_ptr<WPSStream> stream, WPSEmbeddedObject &object, long endPos)
140
14.0k
{
141
14.0k
  if (!stream) return false;
142
14.0k
  RVNGInputStreamPtr &input=stream->m_input;
143
14.0k
  libwps::DebugStream f;
144
145
14.0k
  if (endPos<=0) endPos=stream->m_eof;
146
13.9k
  else if (endPos>stream->m_eof) endPos=stream->m_eof;
147
148
14.0k
  long pos = input->tell();
149
14.0k
  if (pos+24>endPos || libwps::read32(input)!=0x501)
150
2.90k
  {
151
2.90k
    WPS_DEBUG_MSG(("WPSOLEObject::readOLE: not a picture header\n"));
152
2.90k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
153
2.90k
    return false;
154
2.90k
  }
155
11.1k
  f.str("");
156
11.1k
  f << "Entries(OLEObject):";
157
11.1k
  auto type=int(readU32(input));
158
11.1k
  f << "type=" << type << ",";
159
11.1k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
160
11.1k
  bool ok=false;
161
11.1k
  switch (type)
162
11.1k
  {
163
0
  case 1:
164
0
    WPS_DEBUG_MSG(("WPSOLEObject::readOLE: find a link ole\n"));
165
0
    f << "link,";
166
0
    break;
167
9.86k
  case 2:
168
9.86k
    ok=readEmbeddedOLE(stream, object, endPos);
169
9.86k
    break;
170
592
  case 3:
171
782
  case 5:
172
782
    ok=readStaticOLE(stream, object, endPos);
173
782
    break;
174
473
  default:
175
473
    WPS_DEBUG_MSG(("WPSOLEObject::readOLE: find a unknown type\n"));
176
473
    f << "unknown,";
177
473
    break;
178
11.1k
  }
179
11.1k
  if (!ok)
180
10.3k
  {
181
10.3k
    libwps::DebugFile &ascFile=stream->m_ascii;
182
10.3k
    f << "###";
183
10.3k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
184
10.3k
    ascFile.addPos(pos);
185
10.3k
    ascFile.addNote(f.str().c_str());
186
10.3k
  }
187
11.1k
  return true;
188
11.1k
}
189
190
bool WPSOLEObject::readEmbeddedOLE(std::shared_ptr<WPSStream> stream, WPSEmbeddedObject &object, long endPos)
191
9.86k
{
192
9.86k
  if (!stream) return false;
193
9.86k
  RVNGInputStreamPtr &input=stream->m_input;
194
9.86k
  libwps::DebugFile &ascFile=stream->m_ascii;
195
9.86k
  libwps::DebugStream f;
196
197
9.86k
  long pos = input->tell();
198
9.86k
  if (pos+24+4>endPos || libwps::readU32(input)!=0x501)
199
262
  {
200
262
    input->seek(pos, librevenge::RVNG_SEEK_SET);
201
262
    return false;
202
262
  }
203
9.60k
  auto type=int(libwps::readU32(input));
204
9.60k
  if (type!=2)
205
0
  {
206
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
207
0
    return false;
208
0
  }
209
9.60k
  f << "Entries(OLEObject)[embedded]:";
210
9.60k
  std::string names[3];
211
9.60k
  for (auto &name : names)
212
26.2k
  {
213
26.2k
    if (!readString(stream, name, endPos) || input->tell()+4>endPos)
214
2.28k
    {
215
2.28k
      WPS_DEBUG_MSG(("WPSOLEObject::readEmbeddedOLE: can not read the name\n"));
216
2.28k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
217
2.28k
      return false;
218
2.28k
    }
219
23.9k
    if (name.empty()) continue;
220
363
    f << name << ",";
221
363
  }
222
  // find Paint.Picture, WangImage.Document
223
7.32k
  unsigned long dSz=libwps::readU32(input);
224
7.32k
  long actPos=input->tell();
225
7.32k
  if (dSz>0x40000000 || dSz<10 || dSz>static_cast<unsigned long>(endPos-actPos))
226
6.77k
  {
227
6.77k
    WPS_DEBUG_MSG(("WPSOLEObject::readOLE: pict size seems bad\n"));
228
6.77k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
229
6.77k
    return false;
230
6.77k
  }
231
232
542
  bool ok=true;
233
542
  if (names[0]=="METAFILEPICT")
234
0
    ok=readMetafile(stream, object, actPos+long(dSz));
235
542
  else
236
542
  {
237
542
    librevenge::RVNGBinaryData data;
238
542
    if (!libwps::readData(input, dSz, data))
239
0
      ok=false;
240
542
    else
241
542
    {
242
542
      object.add(data);
243
#ifdef DEBUG_WITH_FILES
244
      ascFile.skipZone(actPos, actPos+long(dSz)-1);
245
      std::stringstream s;
246
      static int fileId=0;
247
      s << "PictOLEEmbedded" << ++fileId << ".pct";
248
      libwps::Debug::dumpFile(data, s.str().c_str());
249
#endif
250
542
    }
251
542
  }
252
542
  if (!ok)
253
0
  {
254
0
    WPS_DEBUG_MSG(("WPSOLEObject::readEmbeddedOLE: I can not find the picture\n"));
255
0
    f << "###";
256
0
  }
257
542
  input->seek(actPos+long(dSz), librevenge::RVNG_SEEK_SET);
258
542
  ascFile.addPos(pos);
259
542
  ascFile.addNote(f.str().c_str());
260
542
  if (input->tell()<endPos) // normally followed by a static OLE
261
341
    readStaticOLE(stream, object, endPos);
262
542
  return true;
263
7.32k
}
264
265
bool WPSOLEObject::readStaticOLE(std::shared_ptr<WPSStream> stream, WPSEmbeddedObject &object, long endPos)
266
1.12k
{
267
1.12k
  if (!stream) return false;
268
1.12k
  RVNGInputStreamPtr &input=stream->m_input;
269
1.12k
  libwps::DebugFile &ascFile=stream->m_ascii;
270
1.12k
  libwps::DebugStream f;
271
272
1.12k
  long pos = input->tell();
273
1.12k
  if (pos+24+4>endPos || libwps::readU32(input)!=0x501)
274
307
  {
275
307
    input->seek(pos, librevenge::RVNG_SEEK_SET);
276
307
    return false;
277
307
  }
278
816
  auto type=int(libwps::readU32(input));
279
816
  if (type!=3 && type!=5)
280
23
  {
281
23
    input->seek(pos, librevenge::RVNG_SEEK_SET);
282
23
    return false;
283
23
  }
284
793
  f << "Entries(OLEObject)[static]:";
285
793
  f << "type=" << type << ",";
286
793
  std::string name;
287
793
  if (!readString(stream, name, endPos) || input->tell()+12>endPos)
288
249
  {
289
249
    WPS_DEBUG_MSG(("WPSOLEObject::readStaticOLE: can not read the name\n"));
290
249
    input->seek(pos, librevenge::RVNG_SEEK_SET);
291
249
    return false;
292
249
  }
293
  // find METAFILEPICT
294
544
  f << name << ",";
295
1.63k
  for (int i=0; i<2; ++i)   // g0+g1~0, some application id?
296
1.08k
  {
297
1.08k
    auto val=long(libwps::read32(input));
298
1.08k
    if (val) f << "g" << i << "=" << val << ",";
299
1.08k
  }
300
544
  unsigned long dSz=libwps::readU32(input);
301
544
  long actPos=input->tell();
302
544
  if (dSz>0x40000000 || dSz<10 || dSz>static_cast<unsigned long>(endPos-actPos))
303
294
  {
304
294
    WPS_DEBUG_MSG(("WPSOLEObject::readOLE: pict size seems bad\n"));
305
294
    input->seek(pos, librevenge::RVNG_SEEK_SET);
306
294
    return false;
307
294
  }
308
309
250
  bool ok=true;
310
250
  if (name=="METAFILEPICT")
311
41
    ok=readMetafile(stream, object, actPos+long(dSz));
312
209
  else
313
209
  {
314
209
    librevenge::RVNGBinaryData data;
315
209
    if (!libwps::readData(input, dSz, data))
316
0
      ok=false;
317
209
    else
318
209
    {
319
209
      object.add(data);
320
#ifdef DEBUG_WITH_FILES
321
      ascFile.skipZone(actPos, actPos+long(dSz)-1);
322
      std::stringstream s;
323
      static int fileId=0;
324
      s << "PictOLEStatic" << ++fileId << ".pct";
325
      libwps::Debug::dumpFile(data, s.str().c_str());
326
#endif
327
209
    }
328
209
  }
329
250
  if (!ok)
330
2
  {
331
2
    WPS_DEBUG_MSG(("WPSOLEObject::readStaticOLE: I can not find the picture\n"));
332
2
    f << "###";
333
2
  }
334
250
  input->seek(actPos+long(dSz), librevenge::RVNG_SEEK_SET);
335
250
  ascFile.addPos(pos);
336
250
  ascFile.addNote(f.str().c_str());
337
250
  return true;
338
544
}
339
340
bool WPSOLEObject::readString(std::shared_ptr<WPSStream> stream, std::string &name, long endPos)
341
27.0k
{
342
27.0k
  if (!stream) return false;
343
27.0k
  name="";
344
27.0k
  RVNGInputStreamPtr &input=stream->m_input;
345
27.0k
  long pos=input->tell();
346
27.0k
  if (pos+4>endPos) return false;
347
27.0k
  auto sSz=long(libwps::readU32(input));
348
27.0k
  if (sSz<0 || sSz>endPos-pos-4)
349
1.81k
  {
350
1.81k
    WPS_DEBUG_MSG(("WPSOLEObject::readString: name size seems bad\n"));
351
1.81k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
352
1.81k
    return false;
353
1.81k
  }
354
25.2k
  if (sSz==0) return true;
355
7.44k
  for (long i=0; i+1<sSz; ++i)
356
6.51k
  {
357
6.51k
    auto c=char(libwps::readU8(input));
358
6.51k
    if (c)
359
6.13k
      name+=c;
360
381
    else
361
381
      return false;
362
6.51k
  }
363
926
  return libwps::readU8(input)==0;
364
1.30k
}
365
366
bool WPSOLEObject::checkIsWMF(std::shared_ptr<WPSStream> stream, long endPos)
367
13.5k
{
368
13.5k
  RVNGInputStreamPtr &input=stream->m_input;
369
13.5k
  long pos=input->tell();
370
13.5k
  if (pos+18>endPos) return false;
371
8.23k
  auto fType = int(libwps::read16(input));
372
8.23k
  if ((fType!=1 && fType!=2) || libwps::read16(input)<9)
373
2.32k
  {
374
2.32k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
375
2.32k
    return false;
376
2.32k
  }
377
  // seek version
378
5.90k
  input->seek(2, librevenge::RVNG_SEEK_CUR);
379
5.90k
  auto fSize = long(libwps::read32(input)); // size in words
380
5.90k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
381
5.90k
  return (2*fSize>18 && 2*fSize<=endPos-pos);
382
8.23k
}
383
384
/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */