Coverage Report

Created: 2026-10-28 06:34

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
1.18k
{
45
1.18k
  if (!stream) return false;
46
1.18k
  RVNGInputStreamPtr &input=stream->m_input;
47
1.18k
  libwps::DebugFile &ascFile=stream->m_ascii;
48
1.18k
  libwps::DebugStream f;
49
50
1.18k
  if (endPos<=0) endPos=stream->m_eof;
51
1.18k
  else if (endPos>stream->m_eof) endPos=stream->m_eof;
52
53
1.18k
  long pos = input->tell();
54
1.18k
  if (pos+8+4>endPos)
55
47
    return false;
56
1.13k
  f << "Entries(Metafile):";
57
1.13k
  f << "type=" << libwps::readU16(input) << ",";
58
1.13k
  float fDim[2];
59
2.27k
  for (auto &d : fDim) d=float(libwps::read16(input)/1440.);
60
1.13k
  if (fDim[0]<0||fDim[1]<0)
61
151
  {
62
151
    input->seek(pos, librevenge::RVNG_SEEK_SET);
63
151
    return false;
64
151
  }
65
985
  if (object.m_size==Vec2f() && fDim[0]>0 && fDim[1]>0)
66
368
  {
67
368
    object.m_size=Vec2f(fDim[0],fDim[1]);
68
368
    f << "sz=" << object.m_size << ",";
69
368
  }
70
985
  input->seek(2, librevenge::RVNG_SEEK_CUR); // seek handle
71
985
  if (strict)
72
716
  {
73
716
    if (!checkIsWMF(stream, endPos))
74
424
    {
75
424
      input->seek(pos, librevenge::RVNG_SEEK_SET);
76
424
      return false;
77
424
    }
78
292
    input->seek(pos+8, librevenge::RVNG_SEEK_SET);
79
292
  }
80
561
  librevenge::RVNGBinaryData data;
81
561
  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
561
  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
561
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
97
561
  ascFile.addPos(pos);
98
561
  ascFile.addNote(f.str().c_str());
99
561
  return true;
100
561
}
101
102
bool WPSOLEObject::readWMF(std::shared_ptr<WPSStream> stream, WPSEmbeddedObject &object,long endPos)
103
8.40k
{
104
8.40k
  if (!stream) return false;
105
8.40k
  RVNGInputStreamPtr &input=stream->m_input;
106
8.40k
  libwps::DebugFile &ascFile=stream->m_ascii;
107
8.40k
  long pos=input->tell();
108
109
8.40k
  long lastPos=endPos<=0 ? stream->m_eof : endPos;
110
8.40k
  if (lastPos>stream->m_eof) lastPos=stream->m_eof;
111
8.40k
  if (!checkIsWMF(stream,lastPos)) return false;
112
113
1.39k
  input->seek(pos+6, librevenge::RVNG_SEEK_SET);
114
1.39k
  auto fSize = long(libwps::read32(input));
115
1.39k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
116
1.39k
  librevenge::RVNGBinaryData data;
117
1.39k
  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.39k
  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.39k
  if (endPos>0 && input->tell()!=endPos)
131
102
  {
132
102
    ascFile.addPos(input->tell());
133
102
    ascFile.addNote("_");
134
102
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
135
102
  }
136
1.39k
  return true;
137
1.39k
}
138
139
bool WPSOLEObject::readOLE(std::shared_ptr<WPSStream> stream, WPSEmbeddedObject &object, long endPos)
140
16.3k
{
141
16.3k
  if (!stream) return false;
142
16.3k
  RVNGInputStreamPtr &input=stream->m_input;
143
16.3k
  libwps::DebugStream f;
144
145
16.3k
  if (endPos<=0) endPos=stream->m_eof;
146
16.3k
  else if (endPos>stream->m_eof) endPos=stream->m_eof;
147
148
16.3k
  long pos = input->tell();
149
16.3k
  if (pos+24>endPos || libwps::read32(input)!=0x501)
150
3.30k
  {
151
3.30k
    WPS_DEBUG_MSG(("WPSOLEObject::readOLE: not a picture header\n"));
152
3.30k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
153
3.30k
    return false;
154
3.30k
  }
155
13.0k
  f.str("");
156
13.0k
  f << "Entries(OLEObject):";
157
13.0k
  auto type=int(readU32(input));
158
13.0k
  f << "type=" << type << ",";
159
13.0k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
160
13.0k
  bool ok=false;
161
13.0k
  switch (type)
162
13.0k
  {
163
0
  case 1:
164
0
    WPS_DEBUG_MSG(("WPSOLEObject::readOLE: find a link ole\n"));
165
0
    f << "link,";
166
0
    break;
167
10.9k
  case 2:
168
10.9k
    ok=readEmbeddedOLE(stream, object, endPos);
169
10.9k
    break;
170
1.18k
  case 3:
171
1.51k
  case 5:
172
1.51k
    ok=readStaticOLE(stream, object, endPos);
173
1.51k
    break;
174
615
  default:
175
615
    WPS_DEBUG_MSG(("WPSOLEObject::readOLE: find a unknown type\n"));
176
615
    f << "unknown,";
177
615
    break;
178
13.0k
  }
179
13.0k
  if (!ok)
180
11.9k
  {
181
11.9k
    libwps::DebugFile &ascFile=stream->m_ascii;
182
11.9k
    f << "###";
183
11.9k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
184
11.9k
    ascFile.addPos(pos);
185
11.9k
    ascFile.addNote(f.str().c_str());
186
11.9k
  }
187
13.0k
  return true;
188
13.0k
}
189
190
bool WPSOLEObject::readEmbeddedOLE(std::shared_ptr<WPSStream> stream, WPSEmbeddedObject &object, long endPos)
191
10.9k
{
192
10.9k
  if (!stream) return false;
193
10.9k
  RVNGInputStreamPtr &input=stream->m_input;
194
10.9k
  libwps::DebugFile &ascFile=stream->m_ascii;
195
10.9k
  libwps::DebugStream f;
196
197
10.9k
  long pos = input->tell();
198
10.9k
  if (pos+24+4>endPos || libwps::readU32(input)!=0x501)
199
305
  {
200
305
    input->seek(pos, librevenge::RVNG_SEEK_SET);
201
305
    return false;
202
305
  }
203
10.5k
  auto type=int(libwps::readU32(input));
204
10.5k
  if (type!=2)
205
0
  {
206
0
    input->seek(pos, librevenge::RVNG_SEEK_SET);
207
0
    return false;
208
0
  }
209
10.5k
  f << "Entries(OLEObject)[embedded]:";
210
10.5k
  std::string names[3];
211
10.5k
  for (auto &name : names)
212
28.4k
  {
213
28.4k
    if (!readString(stream, name, endPos) || input->tell()+4>endPos)
214
3.20k
    {
215
3.20k
      WPS_DEBUG_MSG(("WPSOLEObject::readEmbeddedOLE: can not read the name\n"));
216
3.20k
      input->seek(pos, librevenge::RVNG_SEEK_SET);
217
3.20k
      return false;
218
3.20k
    }
219
25.2k
    if (name.empty()) continue;
220
999
    f << name << ",";
221
999
  }
222
  // find Paint.Picture, WangImage.Document
223
7.39k
  unsigned long dSz=libwps::readU32(input);
224
7.39k
  long actPos=input->tell();
225
7.39k
  if (dSz>0x40000000 || dSz<10 || dSz>static_cast<unsigned long>(endPos-actPos))
226
6.46k
  {
227
6.46k
    WPS_DEBUG_MSG(("WPSOLEObject::readOLE: pict size seems bad\n"));
228
6.46k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
229
6.46k
    return false;
230
6.46k
  }
231
232
936
  bool ok=true;
233
936
  if (names[0]=="METAFILEPICT")
234
0
    ok=readMetafile(stream, object, actPos+long(dSz));
235
936
  else
236
936
  {
237
936
    librevenge::RVNGBinaryData data;
238
936
    if (!libwps::readData(input, dSz, data))
239
0
      ok=false;
240
936
    else
241
936
    {
242
936
      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
936
    }
251
936
  }
252
936
  if (!ok)
253
0
  {
254
0
    WPS_DEBUG_MSG(("WPSOLEObject::readEmbeddedOLE: I can not find the picture\n"));
255
0
    f << "###";
256
0
  }
257
936
  input->seek(actPos+long(dSz), librevenge::RVNG_SEEK_SET);
258
936
  ascFile.addPos(pos);
259
936
  ascFile.addNote(f.str().c_str());
260
936
  if (input->tell()<endPos) // normally followed by a static OLE
261
537
    readStaticOLE(stream, object, endPos);
262
936
  return true;
263
7.39k
}
264
265
bool WPSOLEObject::readStaticOLE(std::shared_ptr<WPSStream> stream, WPSEmbeddedObject &object, long endPos)
266
2.05k
{
267
2.05k
  if (!stream) return false;
268
2.05k
  RVNGInputStreamPtr &input=stream->m_input;
269
2.05k
  libwps::DebugFile &ascFile=stream->m_ascii;
270
2.05k
  libwps::DebugStream f;
271
272
2.05k
  long pos = input->tell();
273
2.05k
  if (pos+24+4>endPos || libwps::readU32(input)!=0x501)
274
437
  {
275
437
    input->seek(pos, librevenge::RVNG_SEEK_SET);
276
437
    return false;
277
437
  }
278
1.61k
  auto type=int(libwps::readU32(input));
279
1.61k
  if (type!=3 && type!=5)
280
133
  {
281
133
    input->seek(pos, librevenge::RVNG_SEEK_SET);
282
133
    return false;
283
133
  }
284
1.48k
  f << "Entries(OLEObject)[static]:";
285
1.48k
  f << "type=" << type << ",";
286
1.48k
  std::string name;
287
1.48k
  if (!readString(stream, name, endPos) || input->tell()+12>endPos)
288
621
  {
289
621
    WPS_DEBUG_MSG(("WPSOLEObject::readStaticOLE: can not read the name\n"));
290
621
    input->seek(pos, librevenge::RVNG_SEEK_SET);
291
621
    return false;
292
621
  }
293
  // find METAFILEPICT
294
861
  f << name << ",";
295
2.58k
  for (int i=0; i<2; ++i)   // g0+g1~0, some application id?
296
1.72k
  {
297
1.72k
    auto val=long(libwps::read32(input));
298
1.72k
    if (val) f << "g" << i << "=" << val << ",";
299
1.72k
  }
300
861
  unsigned long dSz=libwps::readU32(input);
301
861
  long actPos=input->tell();
302
861
  if (dSz>0x40000000 || dSz<10 || dSz>static_cast<unsigned long>(endPos-actPos))
303
668
  {
304
668
    WPS_DEBUG_MSG(("WPSOLEObject::readOLE: pict size seems bad\n"));
305
668
    input->seek(pos, librevenge::RVNG_SEEK_SET);
306
668
    return false;
307
668
  }
308
309
193
  bool ok=true;
310
193
  if (name=="METAFILEPICT")
311
8
    ok=readMetafile(stream, object, actPos+long(dSz));
312
185
  else
313
185
  {
314
185
    librevenge::RVNGBinaryData data;
315
185
    if (!libwps::readData(input, dSz, data))
316
0
      ok=false;
317
185
    else
318
185
    {
319
185
      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
185
    }
328
185
  }
329
193
  if (!ok)
330
0
  {
331
0
    WPS_DEBUG_MSG(("WPSOLEObject::readStaticOLE: I can not find the picture\n"));
332
0
    f << "###";
333
0
  }
334
193
  input->seek(actPos+long(dSz), librevenge::RVNG_SEEK_SET);
335
193
  ascFile.addPos(pos);
336
193
  ascFile.addNote(f.str().c_str());
337
193
  return true;
338
861
}
339
340
bool WPSOLEObject::readString(std::shared_ptr<WPSStream> stream, std::string &name, long endPos)
341
29.9k
{
342
29.9k
  if (!stream) return false;
343
29.9k
  name="";
344
29.9k
  RVNGInputStreamPtr &input=stream->m_input;
345
29.9k
  long pos=input->tell();
346
29.9k
  if (pos+4>endPos) return false;
347
29.9k
  auto sSz=long(libwps::readU32(input));
348
29.9k
  if (sSz<0 || sSz>endPos-pos-4)
349
2.64k
  {
350
2.64k
    WPS_DEBUG_MSG(("WPSOLEObject::readString: name size seems bad\n"));
351
2.64k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
352
2.64k
    return false;
353
2.64k
  }
354
27.2k
  if (sSz==0) return true;
355
13.6k
  for (long i=0; i+1<sSz; ++i)
356
11.7k
  {
357
11.7k
    auto c=char(libwps::readU8(input));
358
11.7k
    if (c)
359
11.1k
      name+=c;
360
586
    else
361
586
      return false;
362
11.7k
  }
363
1.91k
  return libwps::readU8(input)==0;
364
2.50k
}
365
366
bool WPSOLEObject::checkIsWMF(std::shared_ptr<WPSStream> stream, long endPos)
367
9.11k
{
368
9.11k
  RVNGInputStreamPtr &input=stream->m_input;
369
9.11k
  long pos=input->tell();
370
9.11k
  if (pos+18>endPos) return false;
371
5.30k
  auto fType = int(libwps::read16(input));
372
5.30k
  if ((fType!=1 && fType!=2) || libwps::read16(input)<9)
373
1.72k
  {
374
1.72k
    input->seek(pos, librevenge::RVNG_SEEK_SET);
375
1.72k
    return false;
376
1.72k
  }
377
  // seek version
378
3.58k
  input->seek(2, librevenge::RVNG_SEEK_CUR);
379
3.58k
  auto fSize = long(libwps::read32(input)); // size in words
380
3.58k
  input->seek(pos, librevenge::RVNG_SEEK_SET);
381
3.58k
  return (2*fSize>18 && 2*fSize<=endPos-pos);
382
5.30k
}
383
384
/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */