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 "StarAttribute.hxx"
43 #include "StarFileManager.hxx"
44 #include "StarItemPool.hxx"
45 #include "StarZone.hxx"
46 #include "StarFormatManager.hxx"
47 
48 #include "StarObject.hxx"
49 
50 /** Internal: the structures of a StarObject */
51 namespace StarObjectInternal
52 {
53 //! the state of a StarObject
54 struct State {
55   //! constructor
StateStarObjectInternal::State56   State()
57     : m_poolList()
58     , m_attributeManager(new StarAttributeManager)
59     , m_formatManager(new StarFormatManager)
60   {
61   }
62   //! copy constructor
63   State(State const &) = default;
64   //! the list of pool
65   std::vector<std::shared_ptr<StarItemPool> > m_poolList;
66   //! the attribute manager
67   std::shared_ptr<StarAttributeManager> m_attributeManager;
68   //! the format manager
69   std::shared_ptr<StarFormatManager> m_formatManager;
70   //! the list of user name
71   librevenge::RVNGString m_userMetaNames[4];
72 private:
73   State operator=(State const &) = delete;
74 };
75 }
76 
77 ////////////////////////////////////////////////////////////
78 // constructor/destructor, ...
79 ////////////////////////////////////////////////////////////
StarObject(char const * passwd,std::shared_ptr<STOFFOLEParser> & oleParser,std::shared_ptr<STOFFOLEParser::OleDirectory> & directory)80 StarObject::StarObject(char const *passwd, std::shared_ptr<STOFFOLEParser> &oleParser, std::shared_ptr<STOFFOLEParser::OleDirectory> &directory)
81   : m_password(passwd)
82   , m_oleParser(oleParser)
83   , m_directory(directory)
84   , m_state(new StarObjectInternal::State())
85   , m_metaData()
86 {
87 }
88 
StarObject(StarObject const & orig,bool duplicateState)89 StarObject::StarObject(StarObject const &orig, bool duplicateState)
90   : m_password(orig.m_password)
91   , m_oleParser(orig.m_oleParser)
92   , m_directory(orig.m_directory)
93   , m_state()
94   , m_metaData(orig.m_metaData)
95 {
96   if (duplicateState)
97     m_state.reset(new StarObjectInternal::State(*orig.m_state));
98   else
99     m_state.reset(new StarObjectInternal::State);
100 }
101 
~StarObject()102 StarObject::~StarObject()
103 {
104 }
105 
cleanPools()106 void StarObject::cleanPools()
107 {
108   for (auto &p : m_state->m_poolList) {
109     if (p)
110       p->clean();
111   }
112   m_state->m_poolList.clear();
113 }
114 
getDocumentKind() const115 STOFFDocument::Kind StarObject::getDocumentKind() const
116 {
117   return m_directory ? m_directory->m_kind : STOFFDocument::STOFF_K_UNKNOWN;
118 }
119 
getAttributeManager()120 std::shared_ptr<StarAttributeManager> StarObject::getAttributeManager()
121 {
122   return m_state->m_attributeManager;
123 }
124 
getFormatManager()125 std::shared_ptr<StarFormatManager> StarObject::getFormatManager()
126 {
127   return m_state->m_formatManager;
128 }
129 
getUserNameMetaData(int i) const130 librevenge::RVNGString StarObject::getUserNameMetaData(int i) const
131 {
132   if (i>=0 && i<=3) {
133     if (!m_state->m_userMetaNames[i].empty())
134       return m_state->m_userMetaNames[i];
135   }
136   STOFF_DEBUG_MSG(("StarObject::parse: can not find user meta data %d\n", i));
137   librevenge::RVNGString res;
138   res.sprintf("Info%d", i);
139   return res;
140 }
141 
getNewItemPool(StarItemPool::Type type)142 std::shared_ptr<StarItemPool> StarObject::getNewItemPool(StarItemPool::Type type)
143 {
144   std::shared_ptr<StarItemPool> pool(new StarItemPool(*this, type));
145   m_state->m_poolList.push_back(pool);
146   return pool;
147 }
148 
getCurrentPool(bool onlyInside)149 std::shared_ptr<StarItemPool> StarObject::getCurrentPool(bool onlyInside)
150 {
151   for (size_t i=m_state->m_poolList.size(); i>0;) {
152     auto pool=m_state->m_poolList[--i];
153     if (pool && !pool->isSecondaryPool() && (!onlyInside || pool->isInside()))
154       return pool;
155   }
156   return std::shared_ptr<StarItemPool>();
157 }
158 
findItemPool(StarItemPool::Type type,bool isInside)159 std::shared_ptr<StarItemPool> StarObject::findItemPool(StarItemPool::Type type, bool isInside)
160 {
161   for (size_t i=m_state->m_poolList.size(); i>0;) {
162     auto pool=m_state->m_poolList[--i];
163     if (!pool || pool->getType()!=type) continue;
164     if (isInside && !pool->isInside()) continue;
165     return pool;
166   }
167   return std::shared_ptr<StarItemPool>();
168 }
169 
parse()170 bool StarObject::parse()
171 {
172   if (!m_directory) {
173     STOFF_DEBUG_MSG(("StarObject::parse: can not find directory\n"));
174     return false;
175   }
176   if (!m_directory->m_hasCompObj) {
177     STOFF_DEBUG_MSG(("StarObject::parse: called with unknown document\n"));
178   }
179   for (auto &content : m_directory->m_contentList) {
180     if (content.isParsed()) continue;
181     auto name = content.getOleName();
182     auto const &base = content.getBaseName();
183     STOFFInputStreamPtr ole;
184     if (m_directory->m_input)
185       ole = m_directory->m_input->getSubStreamByName(name.c_str());
186     if (!ole.get()) {
187       STOFF_DEBUG_MSG(("StarObject::createZones: error: can not find OLE part: \"%s\"\n", name.c_str()));
188       continue;
189     }
190 
191     ole->setReadInverted(true);
192     if (base=="VCPool") {
193       content.setParsed(true);
194       StarZone zone(ole, name, "VCPool", m_password);
195       zone.ascii().open(name);
196       ole->seek(0, librevenge::RVNG_SEEK_SET);
197       getNewItemPool(StarItemPool::T_VCControlPool)->read(zone);
198       continue;
199     }
200     if (base=="persist elements") {
201       content.setParsed(true);
202       readPersistElements(ole, name);
203       continue;
204     }
205     if (base=="SfxPreview") {
206       content.setParsed(true);
207       readSfxPreview(ole, name);
208       continue;
209     }
210     if (base=="SfxDocumentInfo") {
211       content.setParsed(true);
212       readSfxDocumentInformation(ole, name);
213       continue;
214     }
215     libstoff::DebugFile asciiFile(ole);
216     asciiFile.open(name);
217 
218     bool ok=false;
219     if (base=="SfxWindows")
220       ok=readSfxWindows(ole, asciiFile);
221     else if (base=="Star Framework Config File")
222       ok=readStarFrameworkConfigFile(ole, asciiFile);
223     content.setParsed(ok);
224   }
225 
226   return true;
227 }
228 
readItemSet(StarZone & zone,std::vector<STOFFVec2i> const &,long lastPos,StarItemSet & itemSet,StarItemPool * pool,bool isDirect)229 bool StarObject::readItemSet(StarZone &zone, std::vector<STOFFVec2i> const &/*limits*/, long lastPos,
230                              StarItemSet &itemSet, StarItemPool *pool, bool isDirect)
231 {
232   STOFFInputStreamPtr input=zone.input();
233   long pos=input->tell();
234   libstoff::DebugFile &ascFile=zone.ascii();
235   libstoff::DebugStream f;
236 
237   itemSet.m_whichToItemMap.clear();
238   f << "Entries(StarItem):pool,";
239   // itemset.cxx: SfxItemSet::Load (ncount)
240   uint16_t n;
241   *input >> n;
242   f << "N=" << n << ",";
243   if (!pool) {
244     if (input->tell()+6*n > lastPos) {
245       STOFF_DEBUG_MSG(("StarObject::readItemSet: can not read a SfxItemSet\n"));
246       f << "###,";
247       ascFile.addPos(pos);
248       ascFile.addNote(f.str().c_str());
249 
250       return false;
251     }
252     if (n) {
253       if (lastPos!=pos+2+6*n) {
254         // TODO poolio.cxx SfxItemPool::LoadItem
255         static bool first=true;
256         if (first) {
257           STOFF_DEBUG_MSG(("StarObject::readItemSet: reading a SfxItem is not implemented without pool\n"));
258           first=false;
259         }
260         f << "##noPool,";
261       }
262       else
263         f << "#";
264       input->seek(pos+2+6*n, librevenge::RVNG_SEEK_SET);
265     }
266     ascFile.addPos(pos);
267     ascFile.addNote(f.str().c_str());
268     return true;
269   }
270   ascFile.addPos(pos);
271   ascFile.addNote(f.str().c_str());
272   for (int i=0; i<int(n); ++i) {
273     pos=input->tell();
274     auto item=pool->readItem(zone, isDirect, lastPos);
275     if (item && input->tell()<=lastPos) {
276       itemSet.add(item);
277       continue;
278     }
279     input->seek(pos, librevenge::RVNG_SEEK_SET);
280     ascFile.addPos(pos);
281     ascFile.addNote("StarItem:pool,###extra");
282     break;
283   }
284   return true;
285 }
286 
readPersistElements(STOFFInputStreamPtr input,std::string const & name)287 bool StarObject::readPersistElements(STOFFInputStreamPtr input, std::string const &name)
288 {
289   StarZone zone(input, name, "PersistsElement", m_password);
290   libstoff::DebugFile &ascii=zone.ascii();
291   ascii.open(name);
292   input->seek(0, librevenge::RVNG_SEEK_SET);
293   libstoff::DebugStream f;
294   f << "Entries(Persists):";
295   // persist.cxx: SvPersist::LoadContent
296   if (input->size()<21 || input->readLong(1)!=2) {
297     STOFF_DEBUG_MSG(("StarObject::readPersistElements: data seems bad\n"));
298     f << "###";
299     ascii.addPos(0);
300     ascii.addNote(f.str().c_str());
301     return true;
302   }
303   auto hasElt=int(input->readLong(1));
304   if (hasElt==1) {
305     if (input->size()<29) {
306       STOFF_DEBUG_MSG(("StarObject::readPersistElements: flag hasData, but zone seems too short\n"));
307       f << "###";
308       hasElt=0;
309     }
310     f << "hasData,";
311   }
312   else if (hasElt) {
313     STOFF_DEBUG_MSG(("StarObject::readPersistElements: flag hasData seems bad\n"));
314     f << "#hasData=" << hasElt << ",";
315     hasElt=0;
316   }
317   int val;
318   int N=0;
319   long endDataPos=0;
320   if (hasElt) {
321     val=int(input->readULong(1)); // always 80?
322     if (val!=0x80) f << "#f0=" << std::hex << val << std::dec << ",";
323     auto dSz=long(input->readULong(4));
324     N=int(input->readULong(4));
325     f << "dSz=" << dSz << ",N=" << N << ",";
326     if (!dSz || 7+dSz+18>input->size()) {
327       STOFF_DEBUG_MSG(("StarObject::readPersistElements: data size seems bad\n"));
328       f << "###dSz";
329       dSz=0;
330       N=0;
331     }
332     endDataPos=7+dSz;
333   }
334   ascii.addPos(0);
335   ascii.addNote(f.str().c_str());
336   for (int i=0; i<N; ++i) {
337     long pos=input->tell();
338     if (readPersistData(zone, endDataPos))
339       continue;
340     input->seek(pos, librevenge::RVNG_SEEK_SET);
341     f.str("");
342     f << "Persists-A" << i << ":";
343     STOFF_DEBUG_MSG(("StarObject::readPersistElements: data %d seems bad\n", i));
344     f << "###";
345     ascii.addPos(pos);
346     ascii.addNote(f.str().c_str());
347     break;
348   }
349   input->seek(-18, librevenge::RVNG_SEEK_END);
350   long pos=input->tell();
351   f.str("");
352   f << "Persists-B:";
353   int dim[4];
354   for (int &i : dim) i=int(input->readLong(4));
355   f << "dim=" << STOFFBox2i(STOFFVec2i(dim[0],dim[1]), STOFFVec2i(dim[2],dim[3])) << ",";
356   val=int(input->readLong(2)); // 0|9
357   if (val) f << "f0=" << val << ",";
358   ascii.addPos(pos);
359   ascii.addNote(f.str().c_str());
360   return true;
361 }
362 
readPersistData(StarZone & zone,long lastPos)363 bool StarObject::readPersistData(StarZone &zone, long lastPos)
364 {
365   // pstm.cxx SvPersistStream::ReadObj
366   STOFFInputStreamPtr input=zone.input();
367   long pos=input->tell();
368   libstoff::DebugFile &ascii=zone.ascii();
369   libstoff::DebugStream f;
370   f << "Entries(PersistData)["<< zone.getRecordLevel() << "]:";
371   // SvPersistStream::ReadId
372   uint8_t hdr;
373   *input >> hdr;
374   long id=0, classId=0;
375   bool ok=true;
376   if (hdr&0x80) // nId=0
377     ;
378   else {
379     if ((hdr&0xf)==0) {
380       if ((hdr&0x20) || !(hdr&0x40))
381         ok=input->readCompressedLong(id);
382     }
383     else if (hdr&0x10)
384       ok=input->readCompressedLong(id);
385     if (hdr&0x60)
386       ok=input->readCompressedLong(classId);
387   }
388   if (id) f << "id=" << id << ",";
389   if (classId) f << "id[class]=" << classId << ",";
390   if (!ok || !hdr || input->tell()>lastPos) {
391     STOFF_DEBUG_MSG(("StarObject::readPersistData: find unexpected header\n"));
392     f << "###header";
393     ascii.addPos(pos);
394     ascii.addNote(f.str().c_str());
395     return false;
396   }
397   if (hdr&0x80 || (hdr&0x40)==0) {
398     ascii.addPos(pos);
399     ascii.addNote(f.str().c_str());
400     return true;
401   }
402   if (hdr&0x20) {
403     ok=zone.openSCRecord();
404     if (!ok || zone.getRecordLastPosition()>lastPos) {
405       STOFF_DEBUG_MSG(("StarObject::readPersistData: can not open main zone\n"));
406       if (ok) zone.closeSCRecord("PersistData");
407       f << "###,";
408       ascii.addPos(pos);
409       ascii.addNote(f.str().c_str());
410       return false;
411     }
412     lastPos=zone.getRecordLastPosition();
413   }
414   if (hdr&0x40) {
415     // app.cxx OfficeApplication::Init, or SV_DECL_PERSIST1
416     switch (classId) {
417     // case 1 SvxFieldData:: or SvInfoObject:: or SvClassElement::
418     case 2: { // embobj.cxx SvEmbeddedInfoObject::Load
419       long actPos=input->tell();
420       // SvInfoObject::Load
421       uint8_t vers;
422       *input>>vers;
423       f << "objData,";
424       if (vers) f << "vers=" << int(vers) << ","; // 0 or 1
425       bool objOk=true;
426       for (int i=0; i<2; ++i) {
427         std::vector<uint32_t> text;
428         if (!zone.readString(text)||input->tell()+16>=lastPos) {
429           input->seek(actPos, librevenge::RVNG_SEEK_SET);
430           f << "##stringId" << i << ",";
431           objOk=false;
432           break;
433         }
434         f << libstoff::getString(text).cstr() << ",";
435       }
436       if (!objOk) break;
437       // SvGlobalName::operator<<
438       int val;
439       for (int i=0; i<3; ++i) {
440         val=int(input->readULong(i==0 ? 4 : 2));
441         if (val)
442           f << "data" << i << "=" << std::hex << val << std::dec << ",";
443       }
444       f << "data3=[";
445       for (int i=0; i<8; ++i) {
446         val=int (input->readULong(1));
447         if (val)
448           f<< std::hex << val << std::dec << ",";
449         else
450           f << "_,";
451       }
452       f << "],";
453       if (vers>0) {
454         val=int (input->readULong(1));
455         if (val) f << "deleted,";
456       }
457       if (input->readULong(1)!=2 || input->tell()+17>lastPos) {
458         STOFF_DEBUG_MSG(("StarObject::readPersistData: can not find the object info\n"));
459         input->seek(actPos, librevenge::RVNG_SEEK_SET);
460         f << "##badInfo" << ",";
461         break;
462       }
463       val=int (input->readULong(1));
464       if (val)
465         f << "isLink,";
466       f << "rect=[";
467       for (int i=0; i<4; ++i) f << input->readLong(4) << ",";
468       f << "],";
469       break;
470     }
471     default:
472       STOFF_DEBUG_MSG(("StarObject::readPersistData: unknown class id\n"));
473       f << "##classId";
474       break;
475     }
476   }
477   if (input->tell()!=lastPos)
478     ascii.addDelimiter(input->tell(),'|');
479   input->seek(lastPos, librevenge::RVNG_SEEK_SET);
480   if (hdr&0x20)
481     zone.closeSCRecord("PersistData");
482 
483   ascii.addPos(pos);
484   ascii.addNote(f.str().c_str());
485   return true;
486 }
487 
readSfxDocumentInformation(STOFFInputStreamPtr input,std::string const & name)488 bool StarObject::readSfxDocumentInformation(STOFFInputStreamPtr input, std::string const &name)
489 {
490   StarZone zone(input, name, "SfxDocInfo", nullptr); // no password
491   libstoff::DebugFile &ascii=zone.ascii();
492   ascii.open(name);
493   input->seek(0, librevenge::RVNG_SEEK_SET);
494 
495   libstoff::DebugStream f;
496   f << "Entries(SfxDocInfo):";
497 
498   // see sfx2_docinf.cxx
499   auto sSz=int(input->readULong(2));
500   if (2+sSz>input->size()) {
501     STOFF_DEBUG_MSG(("StarObject::readSfxDocumentInformation: header seems bad\n"));
502     f << "###sSz=" << sSz << ",";
503     ascii.addPos(0);
504     ascii.addNote(f.str().c_str());
505     return true;
506   }
507   std::string text("");
508   for (int i=0; i<sSz; ++i) text+=char(input->readULong(1));
509   if (text!="SfxDocumentInfo") {
510     STOFF_DEBUG_MSG(("StarObject::readSfxDocumentInformation: header seems bad\n"));
511     f << "###text=" << text << ",";
512     ascii.addPos(0);
513     ascii.addNote(f.str().c_str());
514     return true;
515   }
516   // FileHeader::FileHeader, SfxDocumentInfo::Load
517   uint16_t nVersion, nUS;
518   bool bPasswd, bPGraphic, bQTemplate;
519   *input >> nVersion >> bPasswd >> nUS >> bPGraphic >> bQTemplate;
520   if (nVersion) f << "vers=" << std::hex << nVersion << std::dec << ",";
521   if (nUS) f << "encoding=" << nUS << ","; // need to load encoding here
522   if (bPasswd) f << "passwd,"; // the password does not seems to be kept/used in this block
523   if (bPGraphic) f << "portableGraphic,";
524   if (bQTemplate) f << "queryTemplate,";
525   auto encoding=StarEncoding::getEncodingForId(nUS);
526   ascii.addPos(0);
527   ascii.addNote(f.str().c_str());
528 
529   librevenge::RVNGString prevAttrib;
530   for (int i=0; i<17; ++i) {
531     long pos=input->tell();
532     f.str("");
533     f << "SfxDocInfo-A" << i << ":";
534     auto dSz=int(input->readULong(2));
535     int expectedSz= i < 3 ? 33 : i < 5 ? 65 : i==5 ? 257 : i==6 ? 129 : i<15 ? 21 : 2;
536     static char const *wh[]= {
537       "time[creation]","time[mod]","time[print]","title","subject","comment","keyword",
538       "user0[name]", "user0[data]","user1[name]", "user1[data]","user2[name]", "user2[data]","user3[name]", "user3[data]",
539       "template[name]", "template[filename]"
540     };
541     f << wh[i] << ",";
542     if (dSz+2>expectedSz) {
543       if (i<15)
544         expectedSz+=0x10000; // rare but can happen, probably due to a bug when calling SkipRep with a negative value
545       else
546         expectedSz=2+dSz;
547     }
548     if (pos+expectedSz+(i<3 ? 8 : 0)>input->size()) {
549       STOFF_DEBUG_MSG(("StarObject::readSfxDocumentInformation: can not read string %d\n", i));
550       f << "###";
551       ascii.addPos(pos);
552       ascii.addNote(f.str().c_str());
553       return true;
554     }
555     std::vector<uint8_t> string;
556     for (int c=0; c<dSz; ++c) string.push_back(static_cast<uint8_t>(input->readULong(1)));
557     std::vector<uint32_t> finalString;
558     std::vector<size_t> srcPositions;
559     if (StarEncoding::convert(string, encoding, finalString, srcPositions)) {
560       auto attrib=libstoff::getString(finalString);
561       f << attrib.cstr() << ",";
562       static char const *attribNames[] = {
563         "meta:initial-creator", "dc:creator", "", "dc:title", "dc:subject", "dc:description"/*comment*/, "meta:keywords",
564         "", "user", "", "user", "", "user", "", "user",
565         "librevenge:template-name", "librevenge:template-filename"
566       };
567       if ((i%2)==1 && i>=7 && i<=13)
568         m_state->m_userMetaNames[(i-7)/2]=attrib;
569       if (attrib.empty() || std::string(attribNames[i]).empty())
570         prevAttrib=attrib;
571       else if (std::string(attribNames[i])=="user") {
572         if (!prevAttrib.empty()) {
573           librevenge::RVNGString userMeta("librevenge:");
574           userMeta.append(prevAttrib);
575           m_metaData.insert(userMeta.cstr(), attrib);
576         }
577       }
578       else
579         m_metaData.insert(attribNames[i], attrib);
580     }
581     else {
582       STOFF_DEBUG_MSG(("StarObject::readSfxDocumentInformation: can not convert a string\n"));
583       f << "###string,";
584       prevAttrib.clear();
585     }
586     input->seek(pos+expectedSz, librevenge::RVNG_SEEK_SET);
587     if (i<3) {
588       uint32_t date, time;
589       *input >> date >> time;
590       f << "date=" << date << ", time=" << time << ",";
591       std::string dateTime;
592       if (date && libstoff::convertToDateTime(date,time, dateTime)) {
593         static char const *attribNames[]= { "meta:creation-date", "dc:date", "meta:print-date" };
594         m_metaData.insert(attribNames[i], dateTime.c_str());
595       }
596     }
597     ascii.addPos(pos);
598     ascii.addNote(f.str().c_str());
599   }
600 
601   long pos=input->tell();
602   f.str("");
603   f << "SfxDocInfo-B:";
604   if (pos+8>input->size()) {
605     STOFF_DEBUG_MSG(("StarObject::readSfxDocumentInformation: last zone seems too short\n"));
606     f << "###";
607     ascii.addPos(pos);
608     ascii.addNote(f.str().c_str());
609     return true;
610   }
611   uint32_t date, time;
612   *input >> date >> time;
613   f << "date=" << date << ", time=" << time << ",";
614   // the following depend on the file version, so let try to get the mail address and stop
615   if (input->tell()+6 <= input->size()) {  // [MailAddr], lTime, ...
616     uint16_t nMailAdr;
617     *input >> nMailAdr;
618     if (nMailAdr && nMailAdr<20 && input->tell()+4*nMailAdr<input->tell()) {
619       f << "mailAdr=[";
620       for (int i=0; i<int(nMailAdr); ++i) {
621         sSz=int(input->readULong(2));
622         if (input->tell()+sSz+2>input->size())
623           break;
624         for (int c=0; c<sSz; ++c) text+=char(input->readULong(1));
625         f << text.c_str() << ",";
626         input->seek(2, librevenge::RVNG_SEEK_CUR); // flag dummy
627       }
628       f << "],";
629     }
630   }
631   if (!input->isEnd()) ascii.addDelimiter(input->tell(),'|');
632   ascii.addPos(pos);
633   ascii.addNote(f.str().c_str());
634 
635   return true;
636 }
637 
readSfxStyleSheets(STOFFInputStreamPtr input,std::string const & name)638 bool StarObject::readSfxStyleSheets(STOFFInputStreamPtr input, std::string const &name)
639 {
640   StarZone zone(input, name, "SfxStyleSheets", getPassword());
641   input->seek(0, librevenge::RVNG_SEEK_SET);
642   libstoff::DebugFile &ascFile=zone.ascii();
643   ascFile.open(name);
644 
645   // sd_sdbinfilter.cxx SdBINFilter::Import: one pool followed by a pool style
646   // chart sch_docshell.cxx SchChartDocShell::Load
647   std::shared_ptr<StarItemPool> pool;
648   if (getDocumentKind()==STOFFDocument::STOFF_K_DRAW || getDocumentKind()==STOFFDocument::STOFF_K_PRESENTATION) {
649     pool=getNewItemPool(StarItemPool::T_XOutdevPool);
650     pool->addSecondaryPool(getNewItemPool(StarItemPool::T_EditEnginePool));
651   }
652   auto mainPool=pool;
653   while (!input->isEnd()) {
654     // REMOVEME: remove this loop, when creation of secondary pool is checked
655     long pos=input->tell();
656     bool extraPool=false;
657     if (!pool) {
658       extraPool=true;
659       pool=getNewItemPool(StarItemPool::T_Unknown);
660     }
661     if (pool && pool->read(zone)) {
662       if (extraPool) {
663         STOFF_DEBUG_MSG(("StarObject::readSfxStyleSheets: create extra pool for %d of type %d\n",
664                          int(getDocumentKind()), int(pool->getType())));
665       }
666       if (!mainPool) mainPool=pool;
667       pool.reset();
668       continue;
669     }
670     input->seek(pos, librevenge::RVNG_SEEK_SET);
671     break;
672   }
673   if (input->isEnd()) return true;
674   long pos=input->tell();
675   if (!mainPool || !mainPool->readStyles(zone, *this)) {
676     STOFF_DEBUG_MSG(("StarObject::readSfxStyleSheets: can not read a style pool\n"));
677     input->seek(pos, librevenge::RVNG_SEEK_SET);
678   }
679   if (!input->isEnd()) {
680     STOFF_DEBUG_MSG(("StarObject::readSfxStyleSheets: find extra data\n"));
681     ascFile.addPos(input->tell());
682     ascFile.addNote("Entries(SfxStyleSheets):###extra");
683   }
684   return true;
685 }
686 
readStarFrameworkConfigFile(STOFFInputStreamPtr input,libstoff::DebugFile & asciiFile)687 bool StarObject::readStarFrameworkConfigFile(STOFFInputStreamPtr input, libstoff::DebugFile &asciiFile)
688 {
689   input->seek(0, librevenge::RVNG_SEEK_SET);
690   libstoff::DebugStream f;
691   f << "Entries(StarFrameworkConfig):";
692   // see sfx2_cfgimex SfxConfigManagerImExport_Impl::Import
693   std::string header("");
694   for (int i=0; i<26; ++i) header+=char(input->readULong(1));
695   if (!input->checkPosition(33)||header!="Star Framework Config File") {
696     STOFF_DEBUG_MSG(("StarObject::readStarFrameworkConfigFile: the header seems bad\n"));
697     f << "###" << header;
698     asciiFile.addPos(0);
699     asciiFile.addNote(f.str().c_str());
700     return true;
701   }
702   uint8_t cC;
703   uint16_t fileVersion;
704   int32_t lDirPos;
705   *input >> cC >> fileVersion >> lDirPos;
706   if (cC!=26) f << "c=" << cC << ",";
707   if (fileVersion!=26) f << "vers=" << fileVersion << ",";
708   auto pos=long(lDirPos);
709   if (!input->checkPosition(pos+2)) {
710     STOFF_DEBUG_MSG(("StarObject::readStarFrameworkConfigFile: dir pos is bad\n"));
711     f << "###dirPos" << pos << ",";
712     asciiFile.addPos(0);
713     asciiFile.addNote(f.str().c_str());
714     return true;
715   }
716   if (input->tell()!=pos) asciiFile.addDelimiter(input->tell(),'|');
717   asciiFile.addPos(0);
718   asciiFile.addNote(f.str().c_str());
719 
720   input->seek(pos, librevenge::RVNG_SEEK_SET);
721   f.str("");
722   f << "StarFrameworkConfig:";
723   uint16_t N;
724   *input >> N;
725   f << "N=" << N << ",";
726   for (uint16_t i=0; i<N; ++i) {
727     if (input->isEnd()) {
728       STOFF_DEBUG_MSG(("StarObject::readStarFrameworkConfigFile: oops, end of file\n"));
729       f << "###";
730       break;
731     }
732     f << "item" << i << "=[";
733     uint16_t nType;
734     int32_t lPos, lLength;
735     *input >> nType >> lPos >> lLength;
736     if (nType) f << "nType=" << nType << ",";
737     if (lPos!=-1) {
738       long actPos=input->tell();
739       STOFFEntry entry;
740       entry.setId(int(nType));
741       entry.setBegin(lPos);
742       entry.setLength(lLength);
743       readStarFrameworkConfigItem(entry, input, asciiFile);
744       input->seek(actPos, librevenge::RVNG_SEEK_SET);
745       if (lLength) f << "len=" << lLength << ",";
746     }
747     auto strSz=int(input->readULong(2));
748     if (!input->checkPosition(input->tell()+strSz)) {
749       STOFF_DEBUG_MSG(("StarObject::readStarFrameworkConfigFile: a item seems bad\n"));
750       f << "###item,";
751       break;
752     }
753     std::string name("");
754     for (int c=0; c<strSz; ++c) name+=char(input->readULong(1));
755     f << name << ",";
756     f << "],";
757   }
758   asciiFile.addPos(pos);
759   asciiFile.addNote(f.str().c_str());
760 
761   return true;
762 }
763 
readStarFrameworkConfigItem(STOFFEntry & entry,STOFFInputStreamPtr input,libstoff::DebugFile & asciiFile)764 bool StarObject::readStarFrameworkConfigItem(STOFFEntry &entry, STOFFInputStreamPtr input, libstoff::DebugFile &asciiFile)
765 {
766   libstoff::DebugStream f;
767   f << "StarFrameworkConfig[Item]:";
768   // see sfx2_cfgimex SfxConfigManagerImExport_Impl::ImportItem
769   if (!entry.valid() || !input->checkPosition(long(entry.end()))) {
770     STOFF_DEBUG_MSG(("StarObject::readStarFrameworkConfigFile: a item position seems bad\n"));
771     f << "###";
772     asciiFile.addPos(entry.begin());
773     asciiFile.addNote(f.str().c_str());
774 
775     return true;
776   }
777   input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
778   uint16_t nType;
779   *input >> nType;
780   f << "type=" << nType << ",";
781   if (nType!=uint16_t(entry.id()) &&
782       !(1294 <= nType && nType <= 1301 && 1294 <= entry.id() && entry.id() <= 1301)) {
783     STOFF_DEBUG_MSG(("StarObject::readStarFrameworkConfigFile: find unexpected type\n"));
784     f << "###";
785     asciiFile.addPos(entry.begin());
786     asciiFile.addNote(f.str().c_str());
787 
788     return true;
789   }
790   f << "#";
791   // readme, some toolbar, ...
792   if (input->tell()!=entry.length())
793     asciiFile.addDelimiter(input->tell(),'|');
794 
795   asciiFile.addPos(entry.begin());
796   asciiFile.addNote(f.str().c_str());
797   return true;
798 }
799 
readSfxPreview(STOFFInputStreamPtr input,std::string const & name)800 bool StarObject::readSfxPreview(STOFFInputStreamPtr input, std::string const &name)
801 {
802   StarZone zone(input, name, "SfxPreview", m_password);
803   libstoff::DebugFile &ascii=zone.ascii();
804   ascii.open(name);
805   input->seek(0, librevenge::RVNG_SEEK_SET);
806   StarFileManager fileManager;
807   if (!fileManager.readSVGDI(zone)) {
808     STOFF_DEBUG_MSG(("StarObject::readSfxPreview: can not find the first image\n"));
809     input->seek(0, librevenge::RVNG_SEEK_SET);
810   }
811   if (input->isEnd()) return true;
812 
813   long pos=input->tell();
814   libstoff::DebugStream f;
815   STOFF_DEBUG_MSG(("StarObject::readSfxPreview: find extra data\n"));
816   f << "Entries(SfxPreview):###extra";
817 
818   ascii.addPos(pos);
819   ascii.addNote(f.str().c_str());
820 
821   return true;
822 }
823 
readSfxWindows(STOFFInputStreamPtr input,libstoff::DebugFile & ascii)824 bool StarObject::readSfxWindows(STOFFInputStreamPtr input, libstoff::DebugFile &ascii)
825 {
826   input->seek(0, librevenge::RVNG_SEEK_SET);
827   libstoff::DebugStream f;
828   f << "Entries(SfWindows):";
829   // see sc_docsh.cxx
830   ascii.addPos(0);
831   ascii.addNote(f.str().c_str());
832   while (!input->isEnd()) {
833     long pos=input->tell();
834     if (!input->checkPosition(pos+2))
835       break;
836     auto dSz=int(input->readULong(2));
837     if (!input->checkPosition(pos+2+dSz)) {
838       input->seek(pos, librevenge::RVNG_SEEK_SET);
839       break;
840     }
841     f.str("");
842     f << "SfWindows:";
843     std::string text("");
844     for (int i=0; i<dSz; ++i) text+=char(input->readULong(1));
845     f << text;
846     ascii.addPos(pos);
847     ascii.addNote(f.str().c_str());
848   }
849   if (!input->isEnd()) {
850     STOFF_DEBUG_MSG(("StarObject::readSfxWindows: find extra data\n"));
851     ascii.addPos(input->tell());
852     ascii.addNote("SfWindows:extra###");
853   }
854   return true;
855 }
856 
857 // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab:
858