/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: */ |