Coverage Report

Created: 2026-09-14 06:37

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