1 /* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */
2
3 /* libstaroffice
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 <string.h>
35
36 #include <limits>
37 #include <cmath>
38 #include <cstring>
39
40 #include <librevenge-stream/librevenge-stream.h>
41 #include <librevenge/librevenge.h>
42
43 #include "STOFFDebug.hxx"
44
45 #include "STOFFInputStream.hxx"
46
STOFFInputStream(std::shared_ptr<librevenge::RVNGInputStream> inp,bool inverted)47 STOFFInputStream::STOFFInputStream(std::shared_ptr<librevenge::RVNGInputStream> inp, bool inverted)
48 : m_stream(inp)
49 , m_streamSize(0)
50 , m_inverseRead(inverted)
51 {
52 updateStreamSize();
53 }
54
STOFFInputStream(librevenge::RVNGInputStream * inp,bool inverted)55 STOFFInputStream::STOFFInputStream(librevenge::RVNGInputStream *inp, bool inverted)
56 : m_stream()
57 , m_streamSize(0)
58 , m_inverseRead(inverted)
59 {
60 if (!inp) return;
61
62 m_stream = std::shared_ptr<librevenge::RVNGInputStream>(inp, STOFF_shared_ptr_noop_deleter<librevenge::RVNGInputStream>());
63 updateStreamSize();
64 if (m_stream)
65 seek(0, librevenge::RVNG_SEEK_SET);
66 }
67
~STOFFInputStream()68 STOFFInputStream::~STOFFInputStream()
69 {
70 }
71
get(librevenge::RVNGBinaryData const & data,bool inverted)72 std::shared_ptr<STOFFInputStream> STOFFInputStream::get(librevenge::RVNGBinaryData const &data, bool inverted)
73 {
74 std::shared_ptr<STOFFInputStream> res;
75 if (!data.size())
76 return res;
77 auto *dataStream = const_cast<librevenge::RVNGInputStream *>(data.getDataStream());
78 if (!dataStream) {
79 STOFF_DEBUG_MSG(("STOFFInputStream::get: can not retrieve a librevenge::RVNGInputStream\n"));
80 return res;
81 }
82 res.reset(new STOFFInputStream(dataStream, inverted));
83 if (res && res->size()>=long(data.size())) {
84 res->seek(0, librevenge::RVNG_SEEK_SET);
85 return res;
86 }
87 STOFF_DEBUG_MSG(("STOFFInputStream::get: the final stream seems bad\n"));
88 res.reset();
89 return res;
90 }
91
updateStreamSize()92 void STOFFInputStream::updateStreamSize()
93 {
94 if (!m_stream)
95 m_streamSize=0;
96 else {
97 long actPos = tell();
98 m_stream->seek(0, librevenge::RVNG_SEEK_END);
99 m_streamSize=tell();
100 m_stream->seek(actPos, librevenge::RVNG_SEEK_SET);
101 }
102 }
103
read(size_t numBytes,unsigned long & numBytesRead)104 const uint8_t *STOFFInputStream::read(size_t numBytes, unsigned long &numBytesRead)
105 {
106 if (!hasDataFork())
107 throw libstoff::FileException();
108 return m_stream->read(numBytes,numBytesRead);
109 }
110
tell()111 long STOFFInputStream::tell()
112 {
113 if (!hasDataFork())
114 return 0;
115 return m_stream->tell();
116 }
117
seek(long offset,librevenge::RVNG_SEEK_TYPE seekType)118 int STOFFInputStream::seek(long offset, librevenge::RVNG_SEEK_TYPE seekType)
119 {
120 if (!hasDataFork()) {
121 if (offset == 0)
122 return 0;
123 throw libstoff::FileException();
124 }
125
126 if (seekType == librevenge::RVNG_SEEK_CUR)
127 offset += tell();
128 else if (seekType==librevenge::RVNG_SEEK_END)
129 offset += m_streamSize;
130
131 if (offset < 0)
132 offset = 0;
133 if (offset > size())
134 offset = size();
135
136 return m_stream->seek(offset, librevenge::RVNG_SEEK_SET);
137 }
138
isEnd()139 bool STOFFInputStream::isEnd()
140 {
141 if (!hasDataFork())
142 return true;
143 long pos = m_stream->tell();
144 if (pos >= size()) return true;
145
146 return m_stream->isEnd();
147 }
148
readULong(librevenge::RVNGInputStream * stream,int num,unsigned long a,bool inverseRead)149 unsigned long STOFFInputStream::readULong(librevenge::RVNGInputStream *stream, int num, unsigned long a, bool inverseRead)
150 {
151 if (!stream || num == 0 || stream->isEnd()) return a;
152 if (inverseRead) {
153 unsigned long val = readU8(stream);
154 return val + (readULong(stream, num-1,0, inverseRead) << 8);
155 }
156 switch (num) {
157 case 4:
158 case 2:
159 case 1: {
160 unsigned long numBytesRead;
161 uint8_t const *p = stream->read(static_cast<unsigned long>(num), numBytesRead);
162 if (!p || int(numBytesRead) != num)
163 return 0;
164 switch (num) {
165 case 4:
166 return static_cast<unsigned long>(p[3])|(static_cast<unsigned long>(p[2])<<8)|
167 (static_cast<unsigned long>(p[1])<<16)|(static_cast<unsigned long>(p[0])<<24)|((a<<16)<<16);
168 case 2:
169 return (static_cast<unsigned long>(p[1]))|(static_cast<unsigned long>(p[0])<<8)|(a<<16);
170 case 1:
171 return (static_cast<unsigned long>(p[0]))|(a<<8);
172 default:
173 break;
174 }
175 break;
176 }
177 default:
178 return readULong(stream, num-1,(a<<8) + static_cast<unsigned long>(readU8(stream)), inverseRead);
179 }
180 return 0;
181 }
182
readLong(int num)183 long STOFFInputStream::readLong(int num)
184 {
185 auto v = long(readULong(num));
186 switch (num) {
187 case 4:
188 return static_cast<int32_t>(v);
189 case 2:
190 return static_cast<int16_t>(v);
191 case 1:
192 return static_cast<int8_t>(v);
193 default:
194 break;
195 }
196
197 if ((v & long(0x1 << (num*8-1))) == 0) return v;
198 return v | long(0xFFFFFFFF << 8*num);
199 }
200
readU8(librevenge::RVNGInputStream * stream)201 uint8_t STOFFInputStream::readU8(librevenge::RVNGInputStream *stream)
202 {
203 if (!stream)
204 return 0;
205 unsigned long numBytesRead;
206 uint8_t const *p = stream->read(sizeof(uint8_t), numBytesRead);
207
208 if (!p || numBytesRead != sizeof(uint8_t))
209 return 0;
210
211 return *reinterpret_cast<uint8_t const *>(p);
212 }
213
peek()214 int STOFFInputStream::peek()
215 {
216 if (isEnd()) return -1;
217 auto res=int(readULong(1));
218 seek(-1, librevenge::RVNG_SEEK_CUR);
219 return res;
220 }
221
readColor(STOFFColor & color)222 bool STOFFInputStream::readColor(STOFFColor &color)
223 {
224 if (!m_stream || !checkPosition(tell()+2)) return false;
225 auto colId=int(readULong(2));
226 if (colId & 0x8000) {
227 if (!checkPosition(tell()+6)) return false;
228 unsigned char col[3];
229 for (unsigned char &i : col) i=static_cast<unsigned char>(readULong(2)>>8);
230 color=STOFFColor(col[0],col[1],col[2]);
231 return true;
232 }
233 static uint32_t const listColors[] = {
234 0, // COL_BLACK
235 0x000080, // COL_BLUE
236 0x008000, // COL_GREEN
237 0x008080, // COL_CYAN
238 0x800000, // COL_RED
239 0x800080, // COL_MAGENTA
240 0x808000, // COL_BROWN
241 0x808080, // COL_GRAY
242 0xc0c0c0, // COL_LIGHTGRAY
243 0x0000ff, // COL_LIGHTBLUE
244 0x00ff00, // COL_LIGHTGREEN
245 0x00ffff, // COL_LIGHTCYAN
246 0xff0000, // COL_LIGHTRED
247 0xff00ff, // COL_LIGHTMAGENTA
248 0xffff00, // COL_YELLOW
249 0xffffff, // COL_WHITE
250 0xffffff, // COL_MENUBAR
251 0, // COL_MENUBARTEXT
252 0xffffff, // COL_POPUPMENU
253 0, // COL_POPUPMENUTEXT
254 0, // COL_WINDOWTEXT
255 0xffffff, // COL_WINDOWWORKSPACE
256 0, // COL_HIGHLIGHT
257 0xffffff, // COL_HIGHLIGHTTEXT
258 0, // COL_3DTEXT
259 0xc0c0c0, // COL_3DFACE
260 0xffffff, // COL_3DLIGHT
261 0x808080, // COL_3DSHADOW
262 0xc0c0c0, // COL_SCROLLBAR
263 0xffffff, // COL_FIELD
264 0 // COL_FIELDTEXT
265 };
266 if (colId<0 || colId>=int(STOFF_N_ELEMENTS(listColors))) {
267 STOFF_DEBUG_MSG(("STOFFInputStream::readColor: can not find color %d\n", colId));
268 return false;
269 }
270 color=STOFFColor(listColors[colId]);
271 return true;
272 }
273
readCompressedULong(unsigned long & res)274 bool STOFFInputStream::readCompressedULong(unsigned long &res)
275 {
276 // sw_sw3imp.cxx Sw3IoImp::InULong
277 if (!m_stream)
278 return false;
279
280 unsigned long numBytesRead;
281 uint8_t const *p = m_stream->read(sizeof(uint8_t), numBytesRead);
282
283 if (!p || numBytesRead != sizeof(uint8_t))
284 return false;
285 if ((p[0]&0x80)==0) {
286 res=p[0]&0x7f;
287 return true;
288 }
289 if ((p[0]&0xC0)==0x80) {
290 res=(p[0]&0x3f);
291 p = m_stream->read(sizeof(uint8_t), numBytesRead);
292 if (!p || numBytesRead != sizeof(uint8_t))
293 return false;
294 res=(res<<8)|p[0];
295 return true;
296 }
297 if ((p[0]&0xe0)==0xc0) {
298 res=p[0]&0x1f;
299 p = m_stream->read(2*sizeof(uint8_t), numBytesRead);
300
301 if (!p || numBytesRead != 2*sizeof(uint8_t))
302 return false;
303 res= (res<<16)|static_cast<unsigned long>(p[1]<<8)|p[0];//checkme
304 return true;
305 }
306 if ((p[0]&0xf0)==0xe0) {
307 res=p[0]&0xf;
308 p = m_stream->read(3*sizeof(uint8_t), numBytesRead);
309
310 if (!p || numBytesRead != 3*sizeof(uint8_t))
311 return false;
312 res=(res<<24)|static_cast<unsigned long>(p[0]<<16)|static_cast<unsigned long>(p[2]<<8)|p[1];//checkme
313 return true;
314 }
315 if ((p[0]&0xf8)==0xf0) {
316 res=readULong(4);
317 return true;
318 }
319 return false;
320 }
321
readCompressedLong(long & res)322 bool STOFFInputStream::readCompressedLong(long &res)
323 {
324 if (!m_stream)
325 return false;
326
327 unsigned long numBytesRead;
328 uint8_t const *p = m_stream->read(sizeof(uint8_t), numBytesRead);
329
330 if (!p || numBytesRead != sizeof(uint8_t))
331 return false;
332 if (p[0]&0x80) {
333 res=p[0]&0x7f;
334 return true;
335 }
336 if (p[0]&0x40) {
337 res=p[0]&0x3f;
338 p = m_stream->read(sizeof(uint8_t), numBytesRead);
339
340 if (!p || numBytesRead != sizeof(uint8_t))
341 return false;
342 res=(res<<8)|p[0];
343 return true;
344 }
345 else if (p[0]&0x20) {
346 res=p[0]&0x1f;
347 p = m_stream->read(3*sizeof(uint8_t), numBytesRead);
348
349 if (!p || numBytesRead != 3*sizeof(uint8_t))
350 return false;
351 res=(res<<24)|(p[0]<<16)|(p[2]<<8)|p[1];//checkme
352 return true;
353 }
354 else if (p[0]==0x10) {
355 long pos=tell();
356 if (pos+4 > m_streamSize) return false;
357 res=long(readULong(4));
358 return true;
359 }
360 return false;
361 }
362
readDouble8(double & res,bool & isNotANumber)363 bool STOFFInputStream::readDouble8(double &res, bool &isNotANumber)
364 {
365 if (!m_stream) return false;
366 long pos=tell();
367 if (pos+8 > m_streamSize) return false;
368
369 isNotANumber=false;
370 res=0;
371 auto mantExp=int(readULong(1));
372 auto val=int(readULong(1));
373 int exp=(mantExp<<4)+(val>>4);
374 double mantisse=double(val&0xF)/16.;
375 double factor=1./16/256.;
376 for (int j = 0; j < 6; ++j, factor/=256)
377 mantisse+=double(readULong(1))*factor;
378 int sign = 1;
379 if (exp & 0x800) {
380 exp &= 0x7ff;
381 sign = -1;
382 }
383 if (exp == 0) {
384 if (mantisse <= 1.e-5 || mantisse >= 1-1.e-5)
385 return true;
386 // a Nan representation ?
387 return false;
388 }
389 if (exp == 0x7FF) {
390 if (mantisse >= 1.-1e-5) {
391 isNotANumber=true;
392 res=std::numeric_limits<double>::quiet_NaN();
393 return true; // ok 0x7FF and 0xFFF are nan
394 }
395 return false;
396 }
397 exp -= 0x3ff;
398 res = std::ldexp(1.+mantisse, exp);
399 if (sign == -1)
400 res *= -1.;
401 return true;
402 }
403
readDouble10(double & res,bool & isNotANumber)404 bool STOFFInputStream::readDouble10(double &res, bool &isNotANumber)
405 {
406 if (!m_stream) return false;
407 long pos=tell();
408 if (pos+10 > m_streamSize) return false;
409
410 auto exp = int(readULong(2));
411 int sign = 1;
412 if (exp & 0x8000) {
413 exp &= 0x7fff;
414 sign = -1;
415 }
416 exp -= 0x3fff;
417
418 isNotANumber=false;
419 auto mantisse = static_cast<unsigned long>(readULong(4));
420 if ((mantisse & 0x80000001) == 0) {
421 // unormalized number are not frequent, but can appear at least for date, ...
422 if (readULong(4) != 0)
423 seek(-4, librevenge::RVNG_SEEK_CUR);
424 else {
425 if (exp == -0x3fff && mantisse == 0) {
426 res=0;
427 return true; // ok zero
428 }
429 if (exp == 0x4000 && (mantisse & 0xFFFFFFL)==0) { // ok Nan
430 isNotANumber = true;
431 res=std::numeric_limits<double>::quiet_NaN();
432 return true;
433 }
434 return false;
435 }
436 }
437 // or std::ldexp((total value)/double(0x80000000), exp);
438 res=std::ldexp(double(readULong(4)),exp-63)+std::ldexp(double(mantisse),exp-31);
439 if (sign == -1)
440 res *= -1.;
441 return true;
442 }
443
readDoubleReverted8(double & res,bool & isNotANumber)444 bool STOFFInputStream::readDoubleReverted8(double &res, bool &isNotANumber)
445 {
446 if (!m_stream) return false;
447 long pos=tell();
448 if (pos+8 > m_streamSize) return false;
449
450 isNotANumber=false;
451 res=0;
452 int bytes[6];
453 for (int &byte : bytes) byte=int(readULong(1));
454
455 auto val=int(readULong(1));
456 auto mantExp=int(readULong(1));
457 int exp=(mantExp<<4)+(val>>4);
458 double mantisse=double(val&0xF)/16.;
459 double factor=1./16./256.;
460 for (int j = 0; j < 6; ++j, factor/=256)
461 mantisse+=double(bytes[5-j])*factor;
462 int sign = 1;
463 if (exp & 0x800) {
464 exp &= 0x7ff;
465 sign = -1;
466 }
467 if (exp == 0) {
468 if (mantisse <= 1.e-5 || mantisse >= 1-1.e-5)
469 return true;
470 // a Nan representation ?
471 return false;
472 }
473 if (exp == 0x7FF) {
474 if (mantisse >= 1.-1e-5) {
475 isNotANumber=true;
476 res=std::numeric_limits<double>::quiet_NaN();
477 return true; // ok 0x7FF and 0xFFF are nan
478 }
479 return false;
480 }
481 exp -= 0x3ff;
482 res = std::ldexp(1.+mantisse, exp);
483 if (sign == -1)
484 res *= -1.;
485 return true;
486 }
487
488 ////////////////////////////////////////////////////////////
489 //
490 // OLE part
491 //
492 ////////////////////////////////////////////////////////////
493
isStructured()494 bool STOFFInputStream::isStructured()
495 {
496 if (!m_stream) return false;
497 long pos=m_stream->tell();
498 bool ok=m_stream->isStructured();
499 m_stream->seek(pos, librevenge::RVNG_SEEK_SET);
500 return ok;
501 }
502
subStreamCount()503 unsigned STOFFInputStream::subStreamCount()
504 {
505 if (!m_stream || !m_stream->isStructured()) {
506 STOFF_DEBUG_MSG(("STOFFInputStream::subStreamCount: called on unstructured file\n"));
507 return 0;
508 }
509 return m_stream->subStreamCount();
510 }
511
subStreamName(unsigned id)512 std::string STOFFInputStream::subStreamName(unsigned id)
513 {
514 if (!m_stream || !m_stream->isStructured()) {
515 STOFF_DEBUG_MSG(("STOFFInputStream::subStreamName: called on unstructured file\n"));
516 return std::string("");
517 }
518 auto const *nm=m_stream->subStreamName(id);
519 if (!nm) {
520 STOFF_DEBUG_MSG(("STOFFInputStream::subStreamName: can not find stream %d\n", int(id)));
521 return std::string("");
522 }
523 return std::string(nm);
524 }
525
getSubStreamByName(std::string const & name)526 std::shared_ptr<STOFFInputStream> STOFFInputStream::getSubStreamByName(std::string const &name)
527 {
528 std::shared_ptr<STOFFInputStream> empty;
529 if (!m_stream || !m_stream->isStructured() || name.empty()) {
530 STOFF_DEBUG_MSG(("STOFFInputStream::getSubStreamByName: called on unstructured file\n"));
531 return empty;
532 }
533
534 long actPos = tell();
535 seek(0, librevenge::RVNG_SEEK_SET);
536 std::shared_ptr<librevenge::RVNGInputStream> res(m_stream->getSubStreamByName(name.c_str()));
537 seek(actPos, librevenge::RVNG_SEEK_SET);
538
539 if (!res)
540 return empty;
541 std::shared_ptr<STOFFInputStream> inp(new STOFFInputStream(res,m_inverseRead));
542 inp->seek(0, librevenge::RVNG_SEEK_SET);
543 return inp;
544 }
545
getSubStreamById(unsigned id)546 std::shared_ptr<STOFFInputStream> STOFFInputStream::getSubStreamById(unsigned id)
547 {
548 std::shared_ptr<STOFFInputStream> empty;
549 if (!m_stream || !m_stream->isStructured()) {
550 STOFF_DEBUG_MSG(("STOFFInputStream::getSubStreamById: called on unstructured file\n"));
551 return empty;
552 }
553
554 long actPos = tell();
555 seek(0, librevenge::RVNG_SEEK_SET);
556 std::shared_ptr<librevenge::RVNGInputStream> res(m_stream->getSubStreamById(id));
557 seek(actPos, librevenge::RVNG_SEEK_SET);
558
559 if (!res)
560 return empty;
561 std::shared_ptr<STOFFInputStream> inp(new STOFFInputStream(res,m_inverseRead));
562 inp->seek(0, librevenge::RVNG_SEEK_SET);
563 return inp;
564 }
565
566 ////////////////////////////////////////////////////////////
567 //
568 // a function to read a data block
569 //
570 ////////////////////////////////////////////////////////////
571
readDataBlock(long sz,librevenge::RVNGBinaryData & data)572 bool STOFFInputStream::readDataBlock(long sz, librevenge::RVNGBinaryData &data)
573 {
574 if (!hasDataFork()) return false;
575
576 data.clear();
577 if (sz < 0) return false;
578 if (sz == 0) return true;
579 long endPos=tell()+sz;
580 if (endPos > size()) return false;
581
582 const unsigned char *readData;
583 unsigned long sizeRead;
584 if ((readData=m_stream->read(static_cast<unsigned long>(sz), sizeRead)) == nullptr || long(sizeRead)!=sz)
585 return false;
586 data.append(readData, sizeRead);
587 return true;
588 }
589
readEndDataBlock(librevenge::RVNGBinaryData & data)590 bool STOFFInputStream::readEndDataBlock(librevenge::RVNGBinaryData &data)
591 {
592 data.clear();
593 if (!hasDataFork()) return false;
594
595 return readDataBlock(size()-tell(), data);
596 }
597
598 // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab:
599