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