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 <cstring>
35 #include <iomanip>
36 #include <iostream>
37 #include <limits>
38 #include <sstream>
39
40 #include <librevenge/librevenge.h>
41
42 #include "StarEncryption.hxx"
43
44 #include "StarZone.hxx"
45
46 ////////////////////////////////////////////////////////////
47 // constructor/destructor, ...
48 ////////////////////////////////////////////////////////////
StarZone(STOFFInputStreamPtr const & inputStream,std::string const & ascName,std::string const & zoneName,char const * password)49 StarZone::StarZone(STOFFInputStreamPtr const &inputStream, std::string const &ascName, std::string const &zoneName, char const *password)
50 : m_input(inputStream)
51 , m_ascii(inputStream)
52 , m_version(0)
53 , m_documentVersion(0)
54 , m_headerVersionStack()
55 , m_encoding(StarEncoding::E_DONTKNOW)
56 , m_guiType(0)
57 , m_encryption()
58 , m_asciiName(ascName)
59 , m_zoneName(zoneName)
60 , m_typeStack()
61 , m_positionStack()
62 , m_beginToEndMap()
63 , m_flagEndZone()
64 , m_poolList()
65 {
66 if (password)
67 m_encryption.reset(new StarEncryption(password));
68 }
69
~StarZone()70 StarZone::~StarZone()
71 {
72 m_ascii.reset();
73 }
74
setInput(STOFFInputStreamPtr ip)75 void StarZone::setInput(STOFFInputStreamPtr ip)
76 {
77 m_input=ip;
78 m_ascii.setStream(ip);
79 }
80
readString(std::vector<uint32_t> & string,std::vector<size_t> & srcPositions,int encoding,bool chckEncryption) const81 bool StarZone::readString(std::vector<uint32_t> &string, std::vector<size_t> &srcPositions, int encoding, bool chckEncryption) const
82 {
83 auto sSz=int(m_input->readULong(2));
84 string.clear();
85 srcPositions.clear();
86 if (!sSz) return true;
87 unsigned long numRead;
88 uint8_t const *data=m_input->read(size_t(sSz), numRead);
89 if (!data || numRead!=static_cast<unsigned long>(sSz)) {
90 STOFF_DEBUG_MSG(("StarZone::readString: the sSz seems bad\n"));
91 return false;
92 }
93 std::vector<uint8_t> buffer;
94 buffer.resize(size_t(sSz));
95 std::memcpy(&buffer[0], data, size_t(sSz));
96 if (chckEncryption && m_encryption)
97 m_encryption->decode(buffer);
98 auto encod=m_encoding;
99 if (encoding>=1) encod=StarEncoding::getEncodingForId(encoding);
100 return StarEncoding::convert(buffer, encod, string, srcPositions);
101 }
102
readStringsPool()103 bool StarZone::readStringsPool()
104 {
105 long pos=m_input->tell();
106 unsigned char type;
107 if (m_input->peek()!='!' || !openSWRecord(type)) {
108 m_input->seek(pos, librevenge::RVNG_SEEK_SET);
109 return false;
110 }
111 libstoff::DebugStream f;
112 f << "Entries(SWPoolList)[" << getRecordLevel() << "]:";
113 // sw_sw3misc.xx: InStringPool sw_sw3imp.cxx: LoadOld and Load
114 int encoding=m_encoding;
115 m_poolList.clear();
116 long lastPos=getRecordLastPosition();
117 if (!isCompatibleWith(3)) {
118 auto n=int(m_input->readULong(2));
119 if (n>=256) {
120 m_input->seek(-1, librevenge::RVNG_SEEK_CUR);
121 encoding=int(m_input->readULong(1));
122 f << "encoding=" << encoding << ",";
123 n=int(m_input->readULong(2));
124 }
125 f << "n=" << n << ",";
126 m_ascii.addPos(pos);
127 m_ascii.addNote(f.str().c_str());
128 std::vector<uint32_t> string;
129 for (int i=0; i<n; ++i) {
130 pos=m_input->tell();
131 f.str("");
132 f << "SWPoolList-" << i << ":";
133 if (!readString(string, encoding) || m_input->tell()>lastPos) {
134 STOFF_DEBUG_MSG(("StarZone::readStringsPool: can not read a string\n"));
135 m_input->seek(pos, librevenge::RVNG_SEEK_SET);
136 break;
137 }
138 m_poolList.push_back(libstoff::getString(string));
139 f << m_poolList.back().cstr() << ",";
140 m_ascii.addPos(pos);
141 m_ascii.addNote(f.str().c_str());
142 }
143 }
144 else {
145 encoding=int(m_input->readULong(1));
146 f << "encoding=" << encoding << ",";
147 auto n=int(m_input->readULong(2));
148 f << "n=" << n << ",";
149 m_ascii.addPos(pos);
150 m_ascii.addNote(f.str().c_str());
151
152 std::vector<uint32_t> string;
153 for (int i=0; i<n; ++i) { // checkme
154 pos=m_input->tell();
155 f.str("");
156 f << "SWPoolList-" << i << ":";
157 auto nId=int(m_input->readULong(2));
158 f << "nId=" << nId << ",";
159 if (!readString(string, encoding) || m_input->tell()>lastPos) {
160 STOFF_DEBUG_MSG(("StarZone::readStringsPool: can not read a string\n"));
161 m_input->seek(pos, librevenge::RVNG_SEEK_SET);
162 break;
163 }
164 m_poolList.push_back(libstoff::getString(string));
165 f << m_poolList.back().cstr() << ",";
166 m_ascii.addPos(pos);
167 m_ascii.addNote(f.str().c_str());
168 }
169 }
170 closeSWRecord(type, "SWPoolList");
171 return true;
172 }
173
checkEncryption(uint32_t date,uint32_t time,std::vector<uint8_t> const & passwd)174 bool StarZone::checkEncryption(uint32_t date, uint32_t time, std::vector<uint8_t> const &passwd)
175 {
176 if ((!date && !time) || passwd.empty())
177 return true;
178 if (m_encryption && m_encryption->checkPassword(date,time,passwd))
179 return true;
180 if (!m_encryption) m_encryption.reset(new StarEncryption);
181
182 if (!m_encryption->guessPassword(date,time,passwd) || !m_encryption->checkPassword(date,time,passwd)) {
183 STOFF_DEBUG_MSG(("StarZone::readZoneHeader: can not find the password\n"));
184 throw libstoff::WrongPasswordException();
185 }
186 STOFF_DEBUG_MSG(("StarZone::readZoneHeader: find a potential password, let continue\n"));
187 return true;
188 }
189
readSWHeader()190 bool StarZone::readSWHeader()
191 {
192 m_ascii.open(m_asciiName);
193
194 libstoff::DebugStream f;
195 f << "Entries(" << m_zoneName << "):";
196
197 // sw_sw3doc.cxx: Sw3IoImp::InHeader
198 if (m_input->size()<0x36) {
199 STOFF_DEBUG_MSG(("StarZone::readSWHeader: the zone is too short\n"));
200 f << "###";
201 m_ascii.addPos(0);
202 m_ascii.addNote(f.str().c_str());
203
204 return false;
205 }
206 m_input->seek(0, librevenge::RVNG_SEEK_SET);
207
208 auto val=int(m_input->readULong(2));
209 if (val==0x5357)
210 m_input->setReadInverted(!m_input->readInverted());
211 else if (val!=0x5753) {
212 STOFF_DEBUG_MSG(("StarZone::readSWHeader: can not set the endian\n"));
213 f << "###";
214 m_ascii.addPos(0);
215 m_ascii.addNote(f.str().c_str());
216
217 return false;
218 }
219
220 m_input->seek(0, librevenge::RVNG_SEEK_SET);
221 for (int i=0; i<7; ++i) {
222 auto c=char(m_input->readULong(1));
223 static char const expected[]= {'S','W',char(0),'H', 'D', 'R', char(0)};
224 if (c==expected[i]) continue;
225 if (i!=2) {
226 STOFF_DEBUG_MSG(("StarZone::readSWHeader: can not read the header\n"));
227 f << "###";
228 m_ascii.addPos(0);
229 m_ascii.addNote(f.str().c_str());
230
231 return false;
232 }
233 if (c<'3' || c>'5') {
234 STOFF_DEBUG_MSG(("StarZone::readZoneHeader: find unexpected version number\n"));
235 f << "##version=" << int(c) << ",";
236 }
237 else {
238 m_version=int(c-'0');
239 f << "version=" << m_version << ",";
240 }
241 }
242 auto hSz=int(m_input->readULong(1));
243 if (hSz<0x2e || !m_input->checkPosition(8+hSz)) {
244 STOFF_DEBUG_MSG(("StarZone::readSWHeader: the header seems bad\n"));
245 f << "###hSz";
246 m_ascii.addPos(0);
247 m_ascii.addNote(f.str().c_str());
248
249 return false;
250 }
251 m_documentVersion=int(m_input->readULong(2));
252 f << "docVersion=" << std::hex << m_documentVersion << std::dec << ",";
253 auto fFlags=int(m_input->readULong(2));
254 bool hasPasswd=false;
255 if (fFlags&2) f << "hasBlockName,";
256 if (fFlags&8) {
257 hasPasswd=true;
258 f << "hasPasswd,";
259 }
260 if (fFlags&0x100) f << "hasPGNums,";
261 if (fFlags&0x8000) {
262 f << "#badFile,";
263 STOFF_DEBUG_MSG(("StarZone::readSWHeader: bad file is set\n"));
264
265 m_ascii.addPos(0);
266 m_ascii.addNote(f.str().c_str());
267
268 return false;
269 }
270 fFlags&=0x7EF5;
271 if (fFlags) f << "flags=" << std::hex << fFlags << std::dec << ",";
272 auto dFlags=long(m_input->readULong(4));
273 if (dFlags&1) f << "browse[mode],";
274 if (dFlags&2) f << "browse[mode2],";
275 if (dFlags&4) f << "html[mode],";
276 if (dFlags&8) f << "show[header],";
277 if (dFlags&0x10) f << "show[footer],";
278 if (dFlags&0x20) f << "global[doc],";
279 if (dFlags&0x40) f << "hasSections,";
280 if (dFlags&0x80) f << "isLabel,";
281 dFlags&=0xffffff00;
282 if (dFlags) f << "dFlags=" << std::hex << dFlags << std::dec << ",";
283 long recPos=int(m_input->readULong(4));
284 if (recPos) f << "recPos=" << std::hex << val << std::dec << ",";
285 m_input->seek(6, librevenge::RVNG_SEEK_CUR); // dummy
286 val=int(m_input->readULong(1));
287 if (val&1)
288 f << "redline[on],";
289 if (val&2)
290 f << "redline[ignore],";
291 if (val&0x10)
292 f << "redline[showInsert],";
293 if (val&0x20)
294 f << "redline[showDelete],";
295 val&=0xCC;
296 if (val) f << "redline=" << std::hex << val << std::dec << ",";
297 val=int(m_input->readULong(1));
298 if (val) f << "compVers=" << val << ",";
299 std::vector<uint8_t> passwd;
300 for (int i=0; i<16; ++i) passwd.push_back(static_cast<uint8_t>(m_input->readULong(1)));
301 val=int(m_input->readULong(1));
302 if (val) f << "charSet[encoding]=" << val << ",";
303 m_encoding=StarEncoding::getEncodingForId(val);
304 val=int(m_input->readULong(1));
305 if (val) f << "f0=" << val << ",";
306 uint32_t date, time;
307 *m_input >> date >> time;
308 f << "date=" << date << ",";
309 f << "time=" << time << ",";
310 if (hasPasswd)
311 checkEncryption(date,time,passwd);
312 else
313 m_encryption.reset();
314 if (hSz==0x2e +64 && (fFlags&2)) {
315 std::string string("");
316 for (int i=0; i<64; ++i) {
317 auto c=char(m_input->readULong(1));
318 if (!c) break;
319 string+=c;
320 }
321 f << string;
322 m_input->seek(8+0x2e +64, librevenge::RVNG_SEEK_SET);
323 }
324 if (m_input->tell()!=8+hSz) {
325 m_ascii.addDelimiter(m_input->tell(),'|');
326 STOFF_DEBUG_MSG(("StarZone::readSWHeader: find extra data\n"));
327 f << "###extra";
328 }
329 m_ascii.addPos(0);
330 m_ascii.addNote(f.str().c_str());
331 m_input->seek(8+hSz, librevenge::RVNG_SEEK_SET);
332 if (recPos && isCompatibleWith(int('%')))
333 return readRecordSizes(recPos);
334
335 return true;
336 }
337
338 ////////////////////////////////////////////////////////////
339 // sdrheader: open/close
340 ////////////////////////////////////////////////////////////
openSCHHeader()341 bool StarZone::openSCHHeader()
342 {
343 long pos=m_input->tell();
344 if (!m_input->checkPosition(pos+6)) return false;
345 // schiocmp.cxx: SchIOHeader::SchIOHeader
346 auto len=long(m_input->readULong(4));
347 m_headerVersionStack.push(int(m_input->readULong(2)));
348 long endPos=pos+len;
349 if (len<6 || !m_input->checkPosition(endPos)) {
350 m_headerVersionStack.pop();
351 m_input->seek(pos, librevenge::RVNG_SEEK_SET);
352 return false;
353 }
354 // check the position ends in the current group (if a group is open)
355 if (!m_positionStack.empty() && endPos>m_positionStack.top() && m_positionStack.top()) {
356 STOFF_DEBUG_MSG(("StarZone::openSCHHeader: argh endPosition is not in the current group\n"));
357 m_headerVersionStack.pop();
358 m_input->seek(pos, librevenge::RVNG_SEEK_SET);
359 return false;
360 }
361 m_typeStack.push('@');
362 m_positionStack.push(endPos);
363 return true;
364 }
365
closeSCHHeader(std::string const & debugName)366 bool StarZone::closeSCHHeader(std::string const &debugName)
367 {
368 if (!m_headerVersionStack.empty()) m_headerVersionStack.pop();
369 return closeRecord('@', debugName);
370 }
371
openVersionCompatHeader()372 bool StarZone::openVersionCompatHeader()
373 {
374 long pos=m_input->tell();
375 if (!m_input->checkPosition(pos+6)) return false;
376 // vcompat.cxx: VersionCompat::VersionCompat
377 m_headerVersionStack.push(int(m_input->readULong(2)));
378 auto len=long(m_input->readULong(4));
379 long endPos=pos+6+len;
380 if (len<0 || !m_input->checkPosition(endPos)) {
381 m_headerVersionStack.pop();
382 m_input->seek(pos, librevenge::RVNG_SEEK_SET);
383 return false;
384 }
385 // check the position ends in the current group (if a group is open)
386 if (!m_positionStack.empty() && endPos>m_positionStack.top() && m_positionStack.top()) {
387 STOFF_DEBUG_MSG(("StarZone::openVersionCompatHeader: argh endPosition is not in the current group\n"));
388 m_headerVersionStack.pop();
389 m_input->seek(pos, librevenge::RVNG_SEEK_SET);
390 return false;
391 }
392 m_typeStack.push('*');
393 m_positionStack.push(endPos);
394 return true;
395 }
396
closeVersionCompatHeader(std::string const & debugName)397 bool StarZone::closeVersionCompatHeader(std::string const &debugName)
398 {
399 if (!m_headerVersionStack.empty()) m_headerVersionStack.pop();
400 return closeRecord('*', debugName);
401 }
402
openSDRHeader(std::string & magic)403 bool StarZone::openSDRHeader(std::string &magic)
404 {
405 long pos=m_input->tell();
406 if (!m_input->checkPosition(pos+4)) return false;
407 // svdio.cxx: SdrIOHeader::Read
408 magic="";
409 for (int i=0; i<4; ++i) magic+=char(m_input->readULong(1));
410 // special case: ok to have only magic if ...
411 if (magic=="DrXX") {
412 m_typeStack.push('_');
413 m_positionStack.push(m_input->tell());
414 return true;
415 }
416 m_headerVersionStack.push(int(m_input->readULong(2)));
417 auto len=long(m_input->readULong(4));
418 long endPos=pos+len;
419 if (len<10 || magic.compare(0,2,"Dr")!=0 || !m_input->checkPosition(endPos)) {
420 m_headerVersionStack.pop();
421 m_input->seek(pos, librevenge::RVNG_SEEK_SET);
422 return false;
423 }
424 // check the position ends in the current group (if a group is open)
425 if (!m_positionStack.empty() && endPos>m_positionStack.top() && m_positionStack.top()) {
426 STOFF_DEBUG_MSG(("StarZone::openSDRHeader: argh endPosition is not in the current group\n"));
427 m_headerVersionStack.pop();
428 m_input->seek(pos, librevenge::RVNG_SEEK_SET);
429 return false;
430 }
431 m_typeStack.push('_');
432 m_positionStack.push(endPos);
433 return true;
434 }
435
closeSDRHeader(std::string const & debugName)436 bool StarZone::closeSDRHeader(std::string const &debugName)
437 {
438 if (!m_headerVersionStack.empty()) m_headerVersionStack.pop();
439 return closeRecord('_', debugName);
440 }
441
442 ////////////////////////////////////////////////////////////
443 // record: open/close, read size
444 ////////////////////////////////////////////////////////////
openDummyRecord()445 bool StarZone::openDummyRecord()
446 {
447 m_typeStack.push('@');
448 if (!m_positionStack.empty())
449 m_positionStack.push(m_positionStack.top());
450 else
451 m_positionStack.push(m_input->size());
452 return true;
453 }
454
openRecord()455 bool StarZone::openRecord()
456 {
457 long pos=m_input->tell();
458 if (!m_input->checkPosition(pos+4)) return false;
459 unsigned long sz=m_input->readULong(4);
460 long endPos=0;
461
462 m_flagEndZone=0;
463 if (sz<4) {
464 STOFF_DEBUG_MSG(("StarZone::openRecord: size can be less than 4\n"));
465 return false;
466 }
467 endPos=pos+long(sz);
468 // check the position is in the file
469 if (endPos && !m_input->checkPosition(endPos)) {
470 STOFF_DEBUG_MSG(("StarZone::openRecord: endPosition is bad\n"));
471 return false;
472 }
473 // check the position ends in the current group (if a group is open)
474 if (!m_positionStack.empty() && endPos>m_positionStack.top() && m_positionStack.top()) {
475 STOFF_DEBUG_MSG(("StarZone::openRecord: argh endPosition is not in the current group\n"));
476 return false;
477 }
478 m_typeStack.push(' ');
479 m_positionStack.push(endPos);
480 return true;
481 }
482
openSCRecord()483 bool StarZone::openSCRecord()
484 {
485 long pos=m_input->tell();
486 if (!m_input->checkPosition(pos+4)) return false;
487 unsigned long sz=m_input->readULong(4);
488 long endPos=0;
489
490 m_flagEndZone=0;
491 endPos=pos+4+long(sz);
492 // check the position is in the file
493 if (endPos && !m_input->checkPosition(endPos)) {
494 STOFF_DEBUG_MSG(("StarZone::openSCRecord: endPosition is bad\n"));
495 return false;
496 }
497 // check the position ends in the current group (if a group is open)
498 if (!m_positionStack.empty() && endPos>m_positionStack.top() && m_positionStack.top()) {
499 STOFF_DEBUG_MSG(("StarZone::openSCRecord: argh endPosition is not in the current group\n"));
500 return false;
501 }
502 m_typeStack.push('_');
503 m_positionStack.push(endPos);
504 return true;
505 }
506
openSWRecord(unsigned char & type)507 bool StarZone::openSWRecord(unsigned char &type)
508 {
509 long pos=m_input->tell();
510 if (!m_input->checkPosition(pos+4)) return false;
511 unsigned long val=m_input->readULong(4);
512 type=static_cast<unsigned char>(val&0xff);
513 if (!type) {
514 STOFF_DEBUG_MSG(("StarZone::openSWRecord: type can not be null\n"));
515 return false;
516 }
517 unsigned long sz=(val>>8);
518 long endPos=0;
519
520 m_flagEndZone=0;
521 if (sz==0xffffff && isCompatibleWith(0x0209)) {
522 if (m_beginToEndMap.find(pos)!=m_beginToEndMap.end())
523 endPos=m_beginToEndMap.find(pos)->second;
524 else {
525 STOFF_DEBUG_MSG(("StarZone::openSWRecord: can not find size for a zone, we may have some problem\n"));
526 }
527 }
528 else {
529 if (sz<4) {
530 STOFF_DEBUG_MSG(("StarZone::openSWRecord: size can be less than 4\n"));
531 return false;
532 }
533 endPos=pos+long(sz);
534 }
535 // check the position is in the file
536 if (endPos && !m_input->checkPosition(endPos)) {
537 STOFF_DEBUG_MSG(("StarZone::openSWRecord: endPosition is bad\n"));
538 return false;
539 }
540 // check the position ends in the current group (if a group is open)
541 if (!m_positionStack.empty() && endPos>m_positionStack.top() && m_positionStack.top()) {
542 STOFF_DEBUG_MSG(("StarZone::openSWRecord: argh endPosition is not in the current group\n"));
543 return false;
544 }
545 m_typeStack.push(type);
546 m_positionStack.push(endPos);
547 return true;
548 }
549
openSfxRecord(unsigned char & type)550 bool StarZone::openSfxRecord(unsigned char &type)
551 {
552 long pos=m_input->tell();
553 if (!m_input->checkPosition(pos+4)) return false;
554 // filerec.cxx SfxMiniRecordReader::SfxMiniRecordReader
555 unsigned long val=m_input->readULong(4);
556 type=static_cast<unsigned char>(val&0xff);
557 // checkme: can type be null
558 unsigned long sz=(val>>8);
559 long endPos=0;
560
561 m_flagEndZone=0;
562 endPos=pos+4+long(sz);
563 // check the position is in the file
564 if (endPos && !m_input->checkPosition(endPos)) {
565 STOFF_DEBUG_MSG(("StarZone::openSfxRecord: endPosition is bad\n"));
566 return false;
567 }
568 // check the position ends in the current group (if a group is open)
569 if (!m_positionStack.empty() && endPos>m_positionStack.top() && m_positionStack.top()) {
570 STOFF_DEBUG_MSG(("StarZone::openSfxRecord: argh endPosition is not in the current group\n"));
571 return false;
572 }
573 m_typeStack.push(type);
574 m_positionStack.push(endPos);
575 return true;
576 }
577
closeRecord(unsigned char type,std::string const & debugName)578 bool StarZone::closeRecord(unsigned char type, std::string const &debugName)
579 {
580 m_flagEndZone=0;
581 while (!m_typeStack.empty()) {
582 unsigned char typ=m_typeStack.top();
583 long pos=m_positionStack.top();
584
585 m_typeStack.pop();
586 m_positionStack.pop();
587 if (typ!=type) continue;
588 if (!pos || type=='@')
589 return true;
590 long actPos=m_input->tell();
591 if (actPos!=pos) {
592 if (actPos>pos) {
593 STOFF_DEBUG_MSG(("StarZone::closeRecord: oops, we read to much data\n"));
594 }
595 else if (actPos<pos) {
596 STOFF_DEBUG_MSG(("StarZone::closeRecord: oops, some data have been ignored\n"));
597 }
598 libstoff::DebugStream f;
599 f << debugName << ":###extra";
600 m_ascii.addPos(actPos);
601 m_ascii.addNote(f.str().c_str());
602 }
603
604 m_input->seek(pos, librevenge::RVNG_SEEK_SET);
605 return true;
606 }
607 STOFF_DEBUG_MSG(("StarZone::closeRecord: oops, can not find type %d\n", int(type)));
608 return false;
609 }
610
openFlagZone()611 unsigned char StarZone::openFlagZone()
612 {
613 auto cFlags=static_cast<unsigned char>(m_input->readULong(1));
614 m_flagEndZone=m_input->tell()+long(cFlags&0xf);
615 return cFlags;
616 }
617
closeFlagZone()618 void StarZone::closeFlagZone()
619 {
620 if (!m_flagEndZone) {
621 STOFF_DEBUG_MSG(("StarZone::closeFlagZone: oops, can not find end position\n"));
622 return;
623 }
624 if (m_flagEndZone<m_input->tell()) {
625 STOFF_DEBUG_MSG(("StarZone::closeFlagZone: oops, we have read too much data\n"));
626 m_ascii.addPos(m_input->tell());
627 m_ascii.addNote("Entries(BadFlagZone):###");
628 }
629 else if (m_flagEndZone>m_input->tell()) {
630 STOFF_DEBUG_MSG(("StarZone::closeFlagZone: oops, we do not have read all data\n"));
631 m_ascii.addPos(m_input->tell());
632 m_ascii.addNote("Entries(BadFlagZone):#");
633 }
634 m_input->seek(m_flagEndZone, librevenge::RVNG_SEEK_SET);
635 }
636
readRecordSizes(long pos)637 bool StarZone::readRecordSizes(long pos)
638 {
639 if (!pos || !isCompatibleWith('%'))
640 return true;
641 // read the position: sw_sw3imp.cxx: Sw3IoImp::InRecSizes
642 long oldPos=m_input->tell();
643 if (oldPos!=pos)
644 m_input->seek(pos, librevenge::RVNG_SEEK_SET);
645 libstoff::DebugStream f;
646 f << m_zoneName << "[RecSize]:";
647 unsigned char type;
648 bool ok=openSWRecord(type);
649 if (!ok || type!='%') {
650 STOFF_DEBUG_MSG(("StarZone::readRecordSizes: can not open the record(recsize)\n"));
651 f << "###extra";
652 m_ascii.addPos(pos);
653 m_ascii.addNote(f.str().c_str());
654
655 m_input->seek(oldPos, librevenge::RVNG_SEEK_SET);
656 return ok || (oldPos!=pos);
657 }
658
659 openFlagZone();
660 auto nCount=int(m_input->readULong(4));
661 f << "N=" << nCount << ",";
662 closeFlagZone();
663
664 if (nCount<0 || (getRecordLastPosition()-m_input->tell())/8<nCount || !m_input->checkPosition(m_input->tell()+8*nCount)) {
665 STOFF_DEBUG_MSG(("StarZone::readRecordSizes: endCPos seems bad\n"));
666 f << "###badN,";
667
668 m_ascii.addPos(pos);
669 m_ascii.addNote(f.str().c_str());
670 closeSWRecord('%',m_zoneName);
671 if (oldPos!=pos)
672 m_input->seek(oldPos, librevenge::RVNG_SEEK_SET);
673 return true;
674 }
675 f << "pos:size=[";
676 for (int i=0; i<nCount; ++i) {
677 auto cPos=long(m_input->readULong(4));
678 auto sz=long(m_input->readULong(4));
679 m_beginToEndMap[cPos]=cPos+sz;
680 f << std::hex << cPos << "<->" << cPos+sz << std::dec << ",";
681 }
682 f << "],";
683
684 closeSWRecord('%',m_zoneName);
685 if (oldPos!=pos)
686 m_input->seek(oldPos, librevenge::RVNG_SEEK_SET);
687
688 m_ascii.addPos(pos);
689 m_ascii.addNote(f.str().c_str());
690 return true;
691 }
692
693 // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab:
694