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 <memory>
39 #include <sstream>
40 
41 #include <librevenge/librevenge.h>
42 
43 #include "StarZone.hxx"
44 
45 #include "StarAttribute.hxx"
46 #include "StarBitmap.hxx"
47 #include "StarGraphicStruct.hxx"
48 #include "StarObject.hxx"
49 #include "StarObjectChart.hxx"
50 #include "StarObjectDraw.hxx"
51 #include "StarObjectMath.hxx"
52 #include "StarObjectSpreadsheet.hxx"
53 #include "StarObjectText.hxx"
54 #include "StarItemPool.hxx"
55 #include "STOFFGraphicEncoder.hxx"
56 #include "STOFFGraphicListener.hxx"
57 #include "STOFFPageSpan.hxx"
58 #include "STOFFSpreadsheetEncoder.hxx"
59 #include "STOFFSpreadsheetListener.hxx"
60 
61 #include "StarFileManager.hxx"
62 
63 /** Internal: the structures of a StarFileManager */
64 namespace StarFileManagerInternal
65 {
66 ////////////////////////////////////////
67 //! Internal: a structure use to read SfxMultiRecord zone of a StarFileManager
68 struct SfxMultiRecord {
69   //! constructor
SfxMultiRecordStarFileManagerInternal::SfxMultiRecord70   explicit SfxMultiRecord(StarZone &zone)
71     : m_zone(zone)
72     , m_zoneType(0)
73     , m_zoneOpened(false)
74     , m_headerType(0)
75     , m_headerVersion(0)
76     , m_headerTag(0)
77     , m_actualRecord(0)
78     , m_numRecord(0)
79     , m_contentSize(0)
80     , m_startPos(0)
81     , m_endPos(0)
82     , m_offsetList()
83     , m_extra("")
84   {
85   }
86   //! try to open a zone
openStarFileManagerInternal::SfxMultiRecord87   bool open()
88   {
89     if (m_zoneOpened) {
90       STOFF_DEBUG_MSG(("StarFileManagerInternal::SfxMultiRecord: oops a record has been opened\n"));
91       return false;
92     }
93     m_actualRecord=m_numRecord=0;
94     m_headerType=m_headerVersion=0;
95     m_headerTag=0;
96     m_contentSize=0;
97     m_offsetList.clear();
98 
99     STOFFInputStreamPtr input=m_zone.input();
100     long pos=input->tell();
101     if (!m_zone.openSfxRecord(m_zoneType)) {
102       input->seek(pos, librevenge::RVNG_SEEK_SET);
103       return false;
104     }
105     if (m_zoneType==static_cast<unsigned char>(0xff)) {
106       STOFF_DEBUG_MSG(("StarFileManagerInternal::SfxMultiRecord: oops end header\n"));
107       m_extra="###emptyZone,";
108       return true; /* empty zone*/
109     }
110     if (m_zoneType!=0) {
111       STOFF_DEBUG_MSG(("StarFileManagerInternal::SfxMultiRecord: find unknown header\n"));
112       m_extra="###badZoneType,";
113       return true;
114     }
115 
116     m_zoneOpened=true;
117     m_endPos=m_zone.getRecordLastPosition();
118     // filerec.cxx: SfxSingleRecordReader::FindHeader_Impl
119     if (input->tell()+10>m_endPos) {
120       STOFF_DEBUG_MSG(("StarFileManagerInternal::SfxMultiRecord::open: oops the zone seems too short\n"));
121       m_extra="###zoneShort,";
122       return true;
123     }
124     *input >> m_headerType >> m_headerVersion >> m_headerTag;
125     // filerec.cxx: SfxMultiRecordReader::ReadHeader_Impl
126     *input >> m_numRecord >> m_contentSize;
127     m_startPos=input->tell();
128     std::stringstream s;
129     if (m_headerType==2) {
130       // fixed size
131       if (m_startPos+long(m_numRecord)*long(m_contentSize) > m_endPos) {
132         STOFF_DEBUG_MSG(("StarFileManagerInternal::SfxMultiRecord::open: oops the number of record seems bad\n"));
133         s << "##numRecord=" << m_numRecord << ",";
134         if (m_contentSize && m_endPos>m_startPos)
135           m_numRecord=uint16_t((m_endPos-m_startPos)/long(m_contentSize));
136         else
137           m_numRecord=0;
138       }
139       m_extra=s.str();
140       return true;
141     }
142 
143     long debOffsetList=((m_headerType==3 || m_headerType==7) ? m_startPos : 0) + long(m_contentSize);
144     if (debOffsetList<m_startPos || debOffsetList+4*m_numRecord > m_endPos) {
145       STOFF_DEBUG_MSG(("StarFileManagerInternal::SfxMultiRecord::open: can not find the version map offset\n"));
146       s << "###contentCount";
147       m_numRecord=0;
148       m_extra=s.str();
149       return true;
150     }
151     m_endPos=debOffsetList;
152     input->seek(debOffsetList, librevenge::RVNG_SEEK_SET);
153     for (uint16_t i=0; i<m_numRecord; ++i) {
154       uint32_t offset;
155       *input >> offset;
156       m_offsetList.push_back(offset);
157     }
158     input->seek(m_startPos, librevenge::RVNG_SEEK_SET);
159     return true;
160   }
161   //! try to close a zone
closeStarFileManagerInternal::SfxMultiRecord162   void close(std::string const &wh)
163   {
164     if (!m_zoneOpened) {
165       STOFF_DEBUG_MSG(("StarFileManagerInternal::SfxMultiRecord::close: can not find any opened zone\n"));
166       return;
167     }
168     m_zoneOpened=false;
169     STOFFInputStreamPtr input=m_zone.input();
170     if (input->tell()<m_endPos && input->tell()+4>=m_endPos) { // small diff is possible
171       m_zone.ascii().addDelimiter(input->tell(),'|');
172       input->seek(m_zone.getRecordLastPosition(), librevenge::RVNG_SEEK_SET);
173     }
174     else if (input->tell()==m_endPos)
175       input->seek(m_zone.getRecordLastPosition(), librevenge::RVNG_SEEK_SET);
176     m_zone.closeSfxRecord(m_zoneType, wh);
177   }
178   //! returns the header tag or -1
getHeaderTagStarFileManagerInternal::SfxMultiRecord179   int getHeaderTag() const
180   {
181     return !m_zoneOpened ? -1 : int(m_headerTag);
182   }
183   //! try to go to the new content positon
getNewContentStarFileManagerInternal::SfxMultiRecord184   bool getNewContent(std::string const &wh)
185   {
186     // SfxMultiRecordReader::GetContent
187     long newPos=getLastContentPosition();
188     if (newPos>=m_endPos) return false;
189     STOFFInputStreamPtr input=m_zone.input();
190     ++m_actualRecord;
191     if (input->tell()<newPos && input->tell()+4>=newPos) { // small diff is possible
192       m_zone.ascii().addDelimiter(input->tell(),'|');
193       input->seek(newPos, librevenge::RVNG_SEEK_SET);
194     }
195     else if (input->tell()!=newPos) {
196       STOFF_DEBUG_MSG(("StarFileManagerInternal::SfxMultiRecord::getNewContent: find extra data\n"));
197       m_zone.ascii().addPos(input->tell());
198       libstoff::DebugStream f;
199       f << wh << ":###extra";
200       m_zone.ascii().addNote(f.str().c_str());
201       input->seek(newPos, librevenge::RVNG_SEEK_SET);
202     }
203     if (m_headerType==7 || m_headerType==8) {
204       // TODO: readtag
205       input->seek(2, librevenge::RVNG_SEEK_CUR);
206     }
207     return true;
208   }
209   //! returns the last content position
getLastContentPositionStarFileManagerInternal::SfxMultiRecord210   long getLastContentPosition() const
211   {
212     if (m_actualRecord >= m_numRecord) return m_endPos;
213     if (m_headerType==2) return m_startPos+m_actualRecord*long(m_contentSize);
214     if (m_actualRecord >= uint16_t(m_offsetList.size())) {
215       STOFF_DEBUG_MSG(("StarFileManagerInternal::SfxMultiRecord::getLastContentPosition: argh, find unexpected index\n"));
216       return m_endPos;
217     }
218     return m_startPos+long(m_offsetList[size_t(m_actualRecord)]>>8)-14;
219   }
220 
221   //! basic operator<< ; print header data
operator <<(std::ostream & o,SfxMultiRecord const & r)222   friend std::ostream &operator<<(std::ostream &o, SfxMultiRecord const &r)
223   {
224     if (!r.m_zoneOpened) {
225       o << r.m_extra;
226       return o;
227     }
228     if (r.m_headerType) o << "type=" << int(r.m_headerType) << ",";
229     if (r.m_headerVersion) o << "version=" << int(r.m_headerVersion) << ",";
230     if (r.m_headerTag) o << "tag=" << r.m_headerTag << ",";
231     if (r.m_numRecord) o << "num[record]=" << r.m_numRecord << ",";
232     if (r.m_contentSize) o << "content[size/pos]=" << r.m_contentSize << ",";
233     if (!r.m_offsetList.empty()) {
234       o << "offset=[";
235       for (unsigned int off : r.m_offsetList) {
236         if (off&0xff)
237           o << (off>>8) << ":" << (off&0xff) << ",";
238         else
239           o << (off>>8) << ",";
240       }
241       o << "],";
242     }
243     o << r.m_extra;
244     return o;
245   }
246 protected:
247   //! the main zone
248   StarZone &m_zone;
249   //! the zone type
250   unsigned char m_zoneType;
251   //! true if a SfxRecord has been opened
252   bool m_zoneOpened;
253   //! the record type
254   uint8_t m_headerType;
255   //! the header version
256   uint8_t m_headerVersion;
257   //! the header tag
258   uint16_t m_headerTag;
259   //! the actual record
260   uint16_t m_actualRecord;
261   //! the number of record
262   uint16_t m_numRecord;
263   //! the record/content/pos size
264   uint32_t m_contentSize;
265   //! the start of data position
266   long m_startPos;
267   //! the end of data position
268   long m_endPos;
269   //! the list of (offset + type)
270   std::vector<uint32_t> m_offsetList;
271   //! extra data
272   std::string m_extra;
273 private:
274   SfxMultiRecord(SfxMultiRecord const &orig);
275   SfxMultiRecord &operator=(SfxMultiRecord const &orig);
276 };
277 
278 ////////////////////////////////////////
279 //! Internal: the state of a StarFileManager
280 struct State {
281   //! constructor
StateStarFileManagerInternal::State282   State()
283   {
284   }
285 };
286 
287 }
288 
289 ////////////////////////////////////////////////////////////
290 // constructor/destructor, ...
291 ////////////////////////////////////////////////////////////
StarFileManager()292 StarFileManager::StarFileManager()
293   : m_state(new StarFileManagerInternal::State)
294 {
295 }
296 
~StarFileManager()297 StarFileManager::~StarFileManager()
298 {
299 }
300 
readOLEDirectory(std::shared_ptr<STOFFOLEParser> oleParser,std::shared_ptr<STOFFOLEParser::OleDirectory> ole,STOFFEmbeddedObject & image,std::shared_ptr<StarObject> & res)301 bool StarFileManager::readOLEDirectory(std::shared_ptr<STOFFOLEParser> oleParser, std::shared_ptr<STOFFOLEParser::OleDirectory> ole, STOFFEmbeddedObject &image, std::shared_ptr<StarObject> &res)
302 {
303   image=STOFFEmbeddedObject();
304   if (!oleParser || !ole || ole->m_inUse) {
305     STOFF_DEBUG_MSG(("StarFileManager::readOLEDirectory: can not read an ole\n"));
306     return false;
307   }
308   ole->m_inUse=true;
309   StarObject object(nullptr, oleParser, ole); // do we need password here ?
310   if (object.getDocumentKind()==STOFFDocument::STOFF_K_CHART) {
311     auto chart=std::make_shared<StarObjectChart>(object, false);
312     ole->m_parsed=true;
313     if (chart->parse())
314       res=chart;
315   }
316   else if (object.getDocumentKind()==STOFFDocument::STOFF_K_DRAW) {
317     StarObjectDraw draw(object, false);
318     ole->m_parsed=true;
319     if (draw.parse()) {
320       STOFFGraphicEncoder graphicEncoder;
321       std::vector<STOFFPageSpan> pageList;
322       int numPages;
323       if (!draw.updatePageSpans(pageList, numPages)) {
324         STOFFPageSpan ps;
325         ps.m_pageSpan=1;
326         pageList.push_back(ps);
327       }
328       STOFFGraphicListenerPtr graphicListener(new STOFFGraphicListener(STOFFListManagerPtr(), pageList, &graphicEncoder));
329       graphicListener->startDocument();
330       draw.sendPages(graphicListener);
331       graphicListener->endDocument();
332       graphicEncoder.getBinaryResult(image);
333     }
334   }
335   else if (object.getDocumentKind()==STOFFDocument::STOFF_K_MATH) {
336     auto math=std::make_shared<StarObjectMath>(object, false);
337     ole->m_parsed=true;
338     if (math->parse())
339       res=math;
340   }
341   else if (object.getDocumentKind()==STOFFDocument::STOFF_K_SPREADSHEET) {
342     StarObjectSpreadsheet spreadsheet(object, false);
343     ole->m_parsed=true;
344     if (spreadsheet.parse()) {
345       STOFFSpreadsheetEncoder spreadsheetEncoder;
346       std::vector<STOFFPageSpan> pageList;
347       int numPages;
348       if (!spreadsheet.updatePageSpans(pageList, numPages)) {
349         STOFFPageSpan ps;
350         ps.m_pageSpan=1;
351         pageList.push_back(ps);
352       }
353       STOFFListManagerPtr listManager;
354       STOFFSpreadsheetListenerPtr spreadsheetListener(new STOFFSpreadsheetListener(listManager, pageList, &spreadsheetEncoder));
355       spreadsheetListener->startDocument();
356       spreadsheet.send(spreadsheetListener);
357       spreadsheetListener->endDocument();
358       spreadsheetEncoder.getBinaryResult(image);
359     }
360   }
361   else if (object.getDocumentKind()==STOFFDocument::STOFF_K_TEXT) {
362     auto text=std::make_shared<StarObjectText>(object, false);
363     ole->m_parsed=true;
364     if (text->parse())
365       res=text;
366   }
367   else {
368     ole->m_parsed=true;
369     // Ole-Object has persist elements, so...
370     if (ole->m_hasCompObj) object.parse();
371     STOFFOLEParser::OleDirectory &direct=*ole;
372     std::vector<std::string> unparsedOLEs=direct.getUnparsedOles();
373     size_t numUnparsed = unparsedOLEs.size();
374     for (size_t i = 0; i < numUnparsed; i++) {
375       std::string const &name = unparsedOLEs[i];
376       STOFFInputStreamPtr stream = ole->m_input->getSubStreamByName(name.c_str());
377       if (!stream.get()) {
378         STOFF_DEBUG_MSG(("StarFileManager::readOLEDirectory: error: can not find OLE part: \"%s\"\n", name.c_str()));
379         continue;
380       }
381 
382       std::string::size_type pos = name.find_last_of('/');
383       std::string base;
384       if (pos == std::string::npos) base = name;
385       else
386         base = name.substr(pos+1);
387       stream->setReadInverted(true);
388       if (base=="SfxStyleSheets") {
389         object.readSfxStyleSheets(stream,name);
390         continue;
391       }
392 
393       if (base=="StarImageDocument" || base=="StarImageDocument 4.0") {
394         librevenge::RVNGBinaryData data;
395         if (readImageDocument(stream,data,name) && !data.empty())
396           image.add(data);
397         continue;
398       }
399       // other
400       if (base=="Ole-Object") {
401         librevenge::RVNGBinaryData data;
402         if (readOleObject(stream,data,name))
403           image.add(data,"object/ole");
404         continue;
405       }
406       libstoff::DebugFile asciiFile(stream);
407       asciiFile.open(name);
408 
409       bool ok=false;
410       if (base=="OutPlace Object")
411         ok=readOutPlaceObject(stream, asciiFile);
412       if (!ok) {
413         libstoff::DebugStream f;
414         if (base=="Standard") // can be Standard or STANDARD
415           f << "Entries(STANDARD):";
416         else
417           f << "Entries(" << base << "):";
418         asciiFile.addPos(0);
419         asciiFile.addNote(f.str().c_str());
420       }
421       asciiFile.reset();
422     }
423   }
424   // finally look if some content have image
425   for (auto &content : ole->m_contentList) {
426     librevenge::RVNGBinaryData data;
427     std::string type;
428     if (content.getImageData(data,type))
429       image.add(data, type);
430   }
431   ole->m_inUse=false;
432   return !image.isEmpty();
433 }
434 
checkUnparsed(STOFFInputStreamPtr input,std::shared_ptr<STOFFOLEParser> oleParser,char const * password)435 void StarFileManager::checkUnparsed(STOFFInputStreamPtr input, std::shared_ptr<STOFFOLEParser> oleParser, char const *password)
436 {
437   if (!input || !oleParser) {
438     STOFF_DEBUG_MSG(("StarFileManager::readOLEDirectory: can not find the input/ole parser\n"));
439     return;
440   }
441   auto listDir=oleParser->getDirectoryList();
442   for (auto &dir : listDir) {
443     if (!dir || dir->m_parsed) continue;
444     dir->m_parsed=true;
445     StarObject object(password, oleParser, dir);
446     if (object.getDocumentKind()==STOFFDocument::STOFF_K_CHART) {
447       StarObjectChart chart(object, false);
448       chart.parse();
449       continue;
450     }
451     if (object.getDocumentKind()==STOFFDocument::STOFF_K_DRAW) {
452       StarObjectDraw draw(object, false);
453       draw.parse();
454       continue;
455     }
456     if (object.getDocumentKind()==STOFFDocument::STOFF_K_MATH) {
457       StarObjectMath math(object, false);
458       math.parse();
459       continue;
460     }
461     if (object.getDocumentKind()==STOFFDocument::STOFF_K_SPREADSHEET) {
462       StarObjectSpreadsheet spreadsheet(object, false);
463       spreadsheet.parse();
464       continue;
465     }
466     if (object.getDocumentKind()==STOFFDocument::STOFF_K_TEXT) {
467       StarObjectText text(object, false);
468       text.parse();
469       continue;
470     }
471     // Ole-Object has persist elements, so...
472     if (dir->m_hasCompObj) object.parse();
473     auto unparsedOLEs=dir->getUnparsedOles();
474     for (auto const &name : unparsedOLEs) {
475       auto ole = input->getSubStreamByName(name.c_str());
476       if (!ole.get()) {
477         STOFF_DEBUG_MSG(("SDWParser::createZones: error: can not find OLE part: \"%s\"\n", name.c_str()));
478         continue;
479       }
480 
481       auto pos = name.find_last_of('/');
482       std::string base;
483       if (pos == std::string::npos) base = name;
484       else base = name.substr(pos+1);
485       ole->setReadInverted(true);
486       if (base=="SfxStyleSheets") {
487         object.readSfxStyleSheets(ole,name);
488         continue;
489       }
490 
491       if (base=="StarImageDocument" || base=="StarImageDocument 4.0") {
492         librevenge::RVNGBinaryData data;
493         readImageDocument(ole,data,name);
494         continue;
495       }
496       if (base.compare(0,3,"Pic")==0) {
497         librevenge::RVNGBinaryData data;
498         std::string type;
499         readEmbeddedPicture(ole,data,type,name);
500         continue;
501       }
502       // other
503       if (base=="Ole-Object") {
504         librevenge::RVNGBinaryData data;
505         readOleObject(ole,data,name);
506         continue;
507       }
508       libstoff::DebugFile asciiFile(ole);
509       asciiFile.open(name);
510 
511       bool ok=false;
512       if (base=="OutPlace Object")
513         ok=readOutPlaceObject(ole, asciiFile);
514       if (!ok) {
515         libstoff::DebugStream f;
516         if (base=="Standard") // can be Standard or STANDARD
517           f << "Entries(STANDARD):";
518         else
519           f << "Entries(" << base << "):";
520         asciiFile.addPos(0);
521         asciiFile.addNote(f.str().c_str());
522       }
523       asciiFile.reset();
524     }
525   }
526 }
527 
readImageDocument(STOFFInputStreamPtr input,librevenge::RVNGBinaryData & data,std::string const & fileName)528 bool StarFileManager::readImageDocument(STOFFInputStreamPtr input, librevenge::RVNGBinaryData &data, std::string const &fileName)
529 {
530   // see this Ole with classic bitmap format
531   libstoff::DebugFile ascii(input);
532   ascii.open(fileName);
533   ascii.skipZone(0, input->size());
534 
535   input->seek(0, librevenge::RVNG_SEEK_SET);
536   data.clear();
537   if (!input->readEndDataBlock(data)) {
538     STOFF_DEBUG_MSG(("StarFileManager::readImageDocument: can not read image content\n"));
539     return false;
540   }
541 #ifdef DEBUG_WITH_FILES
542   libstoff::Debug::dumpFile(data, (fileName+".ppm").c_str());
543 #endif
544   return true;
545 }
546 
readEmbeddedPicture(std::shared_ptr<STOFFOLEParser> oleParser,std::string const & fileName,STOFFEmbeddedObject & image)547 bool StarFileManager::readEmbeddedPicture(std::shared_ptr<STOFFOLEParser> oleParser, std::string const &fileName, STOFFEmbeddedObject &image)
548 {
549   if (!oleParser) {
550     STOFF_DEBUG_MSG(("StarFileManager::readEmbeddedPicture: called without OLE parser\n"));
551     return false;
552   }
553   auto dir=oleParser->getDirectory("EmbeddedPictures");
554   if (!dir || !dir->m_input || !dir->m_input->isStructured()) {
555     STOFF_DEBUG_MSG(("StarFileManager::readEmbeddedPicture: can not find the embedded picture directory\n"));
556     return false;
557   }
558   std::string name("EmbeddedPictures/");
559   name+=fileName;
560   auto ole= dir->m_input->getSubStreamByName(name.c_str());
561   if (!ole) {
562     STOFF_DEBUG_MSG(("StarFileManager::readEmbeddedPicture: can not find the picture %s\n", name.c_str()));
563     return false;
564   }
565   librevenge::RVNGBinaryData data;
566   std::string type;
567   if (!readEmbeddedPicture(ole,data,type,name))
568     return false;
569   image.add(data, type);
570   return true;
571 }
572 
readEmbeddedPicture(STOFFInputStreamPtr input,librevenge::RVNGBinaryData & data,std::string & dataType,std::string const & fileName)573 bool StarFileManager::readEmbeddedPicture(STOFFInputStreamPtr input, librevenge::RVNGBinaryData &data, std::string &dataType, std::string const &fileName)
574 try
575 {
576   // see this Ole with classic bitmap format
577   StarZone zone(input, fileName, "EmbeddedPicture", nullptr);
578 
579   libstoff::DebugFile &ascii=zone.ascii();
580   ascii.open(fileName);
581   data.clear();
582   dataType="";
583   // impgraph.cxx: ImpGraphic::ImplReadEmbedded
584 
585   input->seek(0, librevenge::RVNG_SEEK_SET);
586   libstoff::DebugStream f;
587   f << "Entries(EmbeddedPicture):";
588   uint32_t nId;
589   int32_t nLen;
590 
591   *input>>nId;
592   if (nId==0x35465247 || nId==0x47524635) {
593     if (nId==0x47524635)
594       input->setReadInverted(!input->readInverted());
595     if (!zone.openVersionCompatHeader()) {
596       f << "###";
597       STOFF_DEBUG_MSG(("StarFileManager::readEmbeddedPicture: can not open the header\n"));
598       ascii.addPos(0);
599       ascii.addNote(f.str().c_str());
600       return false;
601     }
602     int32_t nType;
603     int32_t sizeX, sizeY;
604     *input >> nType >> nLen >> sizeX>> sizeY;
605     if (nType)
606       f << "type=" << nType << ",";
607     f << "size=" << sizeX << "x" << sizeY << ",";
608     // mapmod.cxx: operator>>(..., ImplMapMode& )
609     if (!zone.openVersionCompatHeader()) {
610       f << "###";
611       STOFF_DEBUG_MSG(("StarFileManager::readEmbeddedPicture: can not open the mapmod header\n"));
612     }
613     else {
614       uint16_t nMapMode;
615       int32_t nOffsX, nOffsY, nScaleNumX, nScaleDenomX, nScaleNumY, nScaleDenomY;
616       bool mbSimple;
617       *input >> nMapMode >> nOffsX>> nOffsY;
618       if (nMapMode) f << "mapMode=" << nMapMode << ",";
619       if (nOffsX || nOffsY)
620         f << "offs=" << nOffsX << "x" << nOffsY << ",";
621       *input >> nScaleNumX >> nScaleDenomX >> nScaleNumY >> nScaleDenomY >> mbSimple;
622       f << "scaleX=" << nScaleNumX << "/" << nScaleDenomX << ",";
623       f << "scaleY=" << nScaleNumY << "/" << nScaleDenomY << ",";
624       if (mbSimple) f << "simple,";
625       zone.closeVersionCompatHeader("StarFileManager");
626     }
627     zone.closeVersionCompatHeader("StarFileManager");
628   }
629   else {
630     if (nId>0x100) {
631       input->seek(0, librevenge::RVNG_SEEK_SET);
632       input->setReadInverted(!input->readInverted());
633       *input>>nId;
634     }
635     if (nId)
636       f << "type=" << nId << ",";
637     int32_t nWidth, nHeight, nMapMode, nScaleNumX, nScaleDenomX, nScaleNumY, nScaleDenomY, nOffsX, nOffsY;
638     *input >> nLen >> nWidth >> nHeight >> nMapMode;
639     f << "size=" << nWidth << "x" << nHeight << ",";
640     if (nMapMode) f << "mapMode=" << nMapMode << ",";
641     *input >> nScaleNumX >> nScaleDenomX >> nScaleNumY >> nScaleDenomY;
642     f << "scaleX=" << nScaleNumX << "/" << nScaleDenomX << ",";
643     f << "scaleY=" << nScaleNumY << "/" << nScaleDenomY << ",";
644     *input >> nOffsX >> nOffsY;
645     f << "offset=" << nOffsX << "x" << nOffsY << ",";
646   }
647   if (nLen<10 || input->size()!=input->tell()+nLen) {
648     f << "###";
649     STOFF_DEBUG_MSG(("StarFileManager::readEmbeddedPicture: the length seems bad\n"));
650     ascii.addPos(0);
651     ascii.addNote(f.str().c_str());
652     return false;
653   }
654   long pictPos=input->tell();
655   auto header=int(input->readULong(2));
656   input->seek(pictPos, librevenge::RVNG_SEEK_SET);
657   std::string extension("pict");
658   if (header==0x4142 || header==0x4d42) {
659     dataType="image/bm";
660     extension="bm";
661 #ifdef DEBUG_WITH_FILES
662     StarBitmap bitmap;
663     bitmap.readBitmap(zone, true, input->size(), data, dataType);
664 #endif
665   }
666   else if (header==0x5653) {
667 #ifdef DEBUG_WITH_FILES
668     readSVGDI(zone);
669 #endif
670     dataType="image/svg";
671     extension="svgdi";
672   }
673   else if (header==0xcdd7) {
674     dataType="image/wmf";
675     extension="wmf";
676   }
677   else if (header==0x414e) {
678     bool nat5=input->readULong(4)==0x3554414e;
679     input->seek(pictPos, librevenge::RVNG_SEEK_SET);
680     StarGraphicStruct::StarGraphic graphic;
681     if (nat5 && graphic.read(zone,input->size())) {
682       ascii.addPos(0);
683       ascii.addNote(f.str().c_str());
684       dataType=graphic.m_object.m_typeList.empty() ? "image/pict" : graphic.m_object.m_typeList[0];
685       if (!graphic.m_object.m_dataList.empty())
686         data=graphic.m_object.m_dataList[0];
687       return true;
688     }
689     dataType="image/pict";
690     f << "###unknown";
691     STOFF_DEBUG_MSG(("StarFileManager::readEmbeddedPicture: find unknown format\n"));
692   }
693   else if (header==0x4356) { // VLCMTF
694     dataType="image/pict";
695     extension="pict";
696   }
697   else {
698     dataType="image/pict";
699     f << "###unknown";
700     STOFF_DEBUG_MSG(("StarFileManager::readEmbeddedPicture: find unknown format\n"));
701   }
702   f << extension << ",";
703   if (input->tell()==pictPos) ascii.addDelimiter(input->tell(),'|');
704   ascii.addPos(0);
705   ascii.addNote(f.str().c_str());
706   ascii.skipZone(pictPos+4, input->size());
707 
708   input->seek(pictPos, librevenge::RVNG_SEEK_SET);
709   if (!input->readEndDataBlock(data)) {
710     data.clear();
711     STOFF_DEBUG_MSG(("StarFileManager::readEmbeddedPicture: can not read image content\n"));
712     return true;
713   }
714 #ifdef DEBUG_WITH_FILES
715   libstoff::Debug::dumpFile(data, (fileName+"."+extension).c_str());
716 #endif
717   return true;
718 }
719 catch (...)
720 {
721   return false;
722 }
723 
readOleObject(STOFFInputStreamPtr input,librevenge::RVNGBinaryData & data,std::string const & fileName)724 bool StarFileManager::readOleObject(STOFFInputStreamPtr input, librevenge::RVNGBinaryData &data, std::string const &fileName)
725 {
726   // see this Ole only once with PaintBrush data ?
727   libstoff::DebugFile ascii(input);
728   ascii.open(fileName);
729   ascii.skipZone(0, input->size());
730 
731   input->seek(0, librevenge::RVNG_SEEK_SET);
732   if (!input->readEndDataBlock(data)) {
733     STOFF_DEBUG_MSG(("StarFileManager::readOleObject: can not read image content\n"));
734     data.clear();
735     return false;
736   }
737 #ifdef DEBUG_WITH_FILES
738   libstoff::Debug::dumpFile(data, (fileName+".ole").c_str());
739 #endif
740   return true;
741 }
742 
readOutPlaceObject(STOFFInputStreamPtr input,libstoff::DebugFile & ascii)743 bool StarFileManager::readOutPlaceObject(STOFFInputStreamPtr input, libstoff::DebugFile &ascii)
744 {
745   input->seek(0, librevenge::RVNG_SEEK_SET);
746   libstoff::DebugStream f;
747   f << "Entries(OutPlaceObject):";
748   // see outplace.cxx SvOutPlaceObject::SaveCompleted
749   if (input->size()<7) {
750     STOFF_DEBUG_MSG(("StarFileManager::readOutPlaceObject: file is too short\n"));
751     f << "###";
752   }
753   else {
754     uint16_t len;
755     uint32_t dwAspect;
756     bool setExtent;
757     *input>>len >> dwAspect >> setExtent;
758     if (len!=7) f << "length=" << len << ",";
759     if (dwAspect) f << "dwAspect=" << dwAspect << ",";
760     if (setExtent) f << setExtent << ",";
761     if (!input->isEnd()) {
762       STOFF_DEBUG_MSG(("StarFileManager::readOutPlaceObject: find extra data\n"));
763       f << "###extra";
764       ascii.addDelimiter(input->tell(),'|');
765     }
766   }
767   ascii.addPos(0);
768   ascii.addNote(f.str().c_str());
769   return true;
770 }
771 
772 ////////////////////////////////////////////////////////////
773 // small zone
774 ////////////////////////////////////////////////////////////
readFont(StarZone & zone)775 bool StarFileManager::readFont(StarZone &zone)
776 {
777   STOFFInputStreamPtr input=zone.input();
778   libstoff::DebugFile &ascFile=zone.ascii();
779   long pos=input->tell();
780   // font.cxx:  operator>>( ..., Impl_Font& )
781   libstoff::DebugStream f;
782   f << "Entries(StarFont)[" << zone.getRecordLevel() << "]:";
783   if (!zone.openVersionCompatHeader()) {
784     STOFF_DEBUG_MSG(("StarFileManager::readFont: can not read the header\n"));
785     f << "###header";
786     ascFile.addPos(pos);
787     ascFile.addNote(f.str().c_str());
788     return false;
789   }
790   long lastPos=zone.getRecordLastPosition();
791   for (int i=0; i<2; ++i) {
792     std::vector<uint32_t> string;
793     if (!zone.readString(string)||input->tell()>lastPos) {
794       STOFF_DEBUG_MSG(("StarFileManager::readFont: can not read a string\n"));
795       f << "###string";
796       ascFile.addPos(pos);
797       ascFile.addNote(f.str().c_str());
798       zone.closeVersionCompatHeader("StarFont");
799       return true;
800     }
801     if (!string.empty()) f << (i==0 ? "name" : "style") << "=" << libstoff::getString(string).cstr() << ",";
802   }
803   f << "size=" << input->readLong(4) << "x" << input->readLong(4) << ",";
804   uint16_t eCharSet, eFamily, ePitch, eWeight, eUnderline, eStrikeOut, eItalic, eLanguage, eWidthType;
805   int16_t orientation;
806   *input >> eCharSet >> eFamily >> ePitch >> eWeight >> eUnderline >> eStrikeOut
807          >> eItalic >> eLanguage >> eWidthType >> orientation;
808   if (eCharSet) f << "eCharSet=" << eCharSet << ",";
809   if (eFamily) f << "eFamily=" << eFamily << ",";
810   if (ePitch) f << "ePitch=" << ePitch << ",";
811   if (eWeight) f << "eWeight=" << eWeight << ",";
812   if (eUnderline) f << "eUnderline=" << eUnderline << ",";
813   if (eStrikeOut) f << "eStrikeOut=" << eStrikeOut << ",";
814   if (eItalic) f << "eItalic=" << eItalic << ",";
815   if (eLanguage) f << "eLanguage=" << eLanguage << ",";
816   if (eWidthType) f << "eWidthType=" << eWidthType << ",";
817   if (orientation) f << "orientation=" << orientation << ",";
818   bool wordline, outline, shadow;
819   uint8_t kerning;
820   *input >> wordline >> outline >> shadow >> kerning;
821   if (wordline) f << "wordline,";
822   if (outline) f << "outline,";
823   if (shadow) f << "shadow,";
824   if (kerning) f << "kerning=" << int(kerning) << ",";
825   if (zone.getHeaderVersion() >= 2) {
826     bool vertical;
827     int8_t relief;
828     uint16_t cjkLanguage, emphasisMark;
829     *input >> relief >> cjkLanguage >> vertical >> emphasisMark;
830     if (relief) f << "relief=" << int(relief) << ",";
831     if (cjkLanguage) f << "cjkLanguage=" << cjkLanguage << ",";
832     if (vertical) f << "vertical,";
833     if (emphasisMark) f << "emphasisMark=" << emphasisMark << ",";
834   }
835   if (zone.getHeaderVersion() >= 3) {
836     int16_t overline;
837     *input>>overline;
838     if (overline) f << "overline=" << overline << ",";
839   }
840   ascFile.addPos(pos);
841   ascFile.addNote(f.str().c_str());
842 
843   zone.closeVersionCompatHeader("StarFont");
844   return true;
845 }
846 
readJobSetUp(StarZone & zone,bool useJobLen)847 bool StarFileManager::readJobSetUp(StarZone &zone, bool useJobLen)
848 {
849   STOFFInputStreamPtr input=zone.input();
850   libstoff::DebugFile &ascFile=zone.ascii();
851   long pos=input->tell();
852   // sw_sw3misc.cxx: InJobSetup
853   libstoff::DebugStream f;
854   f << "Entries(JobSetUp)[" << zone.getRecordLevel() << "]:";
855   // sfx2_printer.cxx: SfxPrinter::Create
856   // jobset.cxx: JobSetup operator>>
857   long lastPos=zone.getRecordLastPosition();
858   auto len=int(input->readULong(2));
859   f << "nLen=" << len << ",";
860   if (len==0) {
861     ascFile.addPos(pos);
862     ascFile.addNote(f.str().c_str());
863     return true;
864   }
865   if (useJobLen) {
866     if (pos+len>lastPos) {
867       STOFF_DEBUG_MSG(("StarFileManager::readJobSetUp: the jobs len seems bad\n"));
868       input->seek(pos, librevenge::RVNG_SEEK_SET);
869       return false;
870     }
871     else
872       lastPos=pos+len;
873   }
874   bool ok=false;
875   int nSystem=0;
876   if (input->tell()+2+64+3*32<=lastPos) {
877     nSystem=int(input->readULong(2));
878     f << "system=" << nSystem << ",";
879     for (int i=0; i<4; ++i) {
880       long actPos=input->tell();
881       int const length=(i==0 ? 64 : 32);
882       std::string name("");
883       for (int c=0; c<length; ++c) {
884         auto ch=char(input->readULong(1));
885         if (ch==0) break;
886         name+=ch;
887       }
888       if (!name.empty()) {
889         static char const *wh[]= { "printerName", "deviceName", "portName", "driverName" };
890         f << wh[i] << "=" << name << ",";
891       }
892       input->seek(actPos+length, librevenge::RVNG_SEEK_SET);
893     }
894     ok=true;
895   }
896   if (ok && nSystem<0xfffe) {
897     ascFile.addPos(pos);
898     ascFile.addNote(f.str().c_str());
899 
900     pos=input->tell();
901     f.str("");
902     f << "JobSetUp:driverData,";
903     input->seek(lastPos, librevenge::RVNG_SEEK_SET);
904   }
905   else if (ok && input->tell()+22<=lastPos) {
906     int driverDataLen=0;
907     f << "nSize2=" << input->readULong(2) << ",";
908     f << "nSystem2=" << input->readULong(2) << ",";
909     driverDataLen=int(input->readULong(4));
910     f << "nOrientation=" << input->readULong(2) << ",";
911     f << "nPaperBin=" << input->readULong(2) << ",";
912     f << "nPaperFormat=" << input->readULong(2) << ",";
913     f << "nPaperWidth=" << input->readULong(4) << ",";
914     f << "nPaperHeight=" << input->readULong(4) << ",";
915 
916     if (driverDataLen && input->tell()+driverDataLen<=lastPos) {
917       ascFile.addPos(input->tell());
918       ascFile.addNote("JobSetUp:driverData");
919       input->seek(driverDataLen, librevenge::RVNG_SEEK_CUR);
920     }
921     else if (driverDataLen)
922       ok=false;
923     if (ok) {
924       ascFile.addPos(pos);
925       ascFile.addNote(f.str().c_str());
926       pos=input->tell();
927       f.str("");
928       f << "JobSetUp[values]:";
929       if (nSystem==0xfffe) {
930         std::vector<uint32_t> text;
931         while (input->tell()<lastPos) {
932           for (int i=0; i<2; ++i) {
933             if (!zone.readString(text)) {
934               f << "###string,";
935               ok=false;
936               break;
937             }
938             f << libstoff::getString(text).cstr() << (i==0 ? ':' : ',');
939           }
940           if (!ok)
941             break;
942         }
943       }
944       else if (input->tell()<lastPos) {
945         ascFile.addPos(input->tell());
946         ascFile.addNote("JobSetUp:driverData");
947         input->seek(lastPos, librevenge::RVNG_SEEK_SET);
948       }
949     }
950   }
951   if (pos!=lastPos) {
952     ascFile.addPos(pos);
953     ascFile.addNote(f.str().c_str());
954   }
955   return true;
956 }
957 
readSVGDI(StarZone & zone)958 bool StarFileManager::readSVGDI(StarZone &zone)
959 {
960   STOFFInputStreamPtr input=zone.input();
961   libstoff::DebugFile &ascFile=zone.ascii();
962   long pos=input->tell();
963   long lastPos=zone.getRecordLevel()==0 ? input->size() : zone.getRecordLastPosition();
964   // cvtsvm.cxx: SVMConverter::ImplConvertFromSVM1
965   libstoff::DebugStream f;
966   f << "Entries(ImageSVGDI)[" << zone.getRecordLevel() << "]:";
967   std::string code;
968   for (int i=0; i<5; ++i) code+=char(input->readULong(1));
969   if (code!="SVGDI") {
970     input->seek(0, librevenge::RVNG_SEEK_SET);
971     return false;
972   }
973   uint16_t sz;
974   int16_t version;
975   int32_t width, height;
976   *input >> sz >> version >> width >> height;
977   long endPos=pos+5+sz;
978   if (version!=200 || sz<42 || endPos>lastPos) {
979     STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: find unknown version\n"));
980     f << "###";
981     ascFile.addPos(pos);
982     ascFile.addNote(f.str().c_str());
983     return false;
984   }
985   f << "size=" << width << "x" << height << ",";
986   // map mode
987   int16_t unit;
988   int32_t orgX, orgY, nXNum, nXDenom, nYNum, nYDenom;
989   *input >> unit >> orgX >> orgY >> nXNum >> nXDenom >> nYNum >> nYDenom;
990   if (unit) f << "unit=" << unit << ",";
991   f << "orig=" << orgX << "x" << orgY << ",";
992   f << "x=" << nXNum << "/" << nXDenom << ",";
993   f << "y=" << nYNum << "/" << nYDenom << ",";
994 
995   int32_t nActions;
996   *input >> nActions;
997   f << "actions=" << nActions << ",";
998   if (input->tell()!=endPos)
999     ascFile.addDelimiter(input->tell(),'|');
1000   ascFile.addPos(pos);
1001   ascFile.addNote(f.str().c_str());
1002   input->seek(endPos, librevenge::RVNG_SEEK_SET);
1003   uint32_t nUnicodeCommentActionNumber=0;
1004   for (int32_t i=0; i<nActions; ++i) {
1005     pos=input->tell();
1006     f.str("");
1007     f << "ImageSVGDI[" << i << "]:";
1008     int16_t type;
1009     int32_t nActionSize;
1010     *input>>type>>nActionSize;
1011     long endDataPos=pos+2+nActionSize;
1012     if (nActionSize<4 || (lastPos-pos-2)<nActionSize || endDataPos>lastPos) {
1013       STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: bad size\n"));
1014       f << "###";
1015       ascFile.addPos(pos);
1016       ascFile.addNote(f.str().c_str());
1017       input->seek(pos, librevenge::RVNG_SEEK_SET);
1018       break;
1019     }
1020     unsigned char col[3];
1021     STOFFColor color;
1022     int32_t nTmp, nTmp1;
1023     std::vector<uint32_t> text;
1024     switch (type) {
1025     case 1:
1026       f << "pixel=" << input->readLong(4) << "x" << input->readLong(4) << ",";
1027       for (unsigned char &c : col) c=static_cast<unsigned char>(input->readULong(2)>>8);
1028       f << "col=" << STOFFColor(col[0],col[1],col[2]) << ",";
1029       break;
1030     case 2:
1031       f << "point=" << input->readLong(4) << "x" << input->readLong(4) << ",";
1032       break;
1033     case 3:
1034       f << "line=" << input->readLong(4) << "x" << input->readLong(4) << "<->"
1035         << input->readLong(4) << "x" << input->readLong(4) << ",";
1036       break;
1037     case 4:
1038       f << "rect=" << input->readLong(4) << "x" << input->readLong(4) << "<->"
1039         << input->readLong(4) << "x" << input->readLong(4) << ",";
1040       *input >> nTmp >> nTmp1;
1041       if (nTmp || nTmp1) f << "round=" << nTmp << "x" << nTmp1 << ",";
1042       break;
1043     case 5:
1044       f << "ellipse=" << input->readLong(4) << "x" << input->readLong(4) << "<->"
1045         << input->readLong(4) << "x" << input->readLong(4) << ",";
1046       break;
1047     case 6:
1048     case 7:
1049       f << (type==6 ? "arc" : "pie")<< "=" << input->readLong(4) << "x" << input->readLong(4) << "<->"
1050         << input->readLong(4) << "x" << input->readLong(4) << ",";
1051       f << "pt1=" << input->readLong(4) << "x" << input->readLong(4) << ",";
1052       f << "pt2=" << input->readLong(4) << "x" << input->readLong(4) << ",";
1053       break;
1054     case 8:
1055     case 9:
1056       f << (type==8 ? "rect[invert]" : "rect[highlight") << "="
1057         << input->readLong(4) << "x" << input->readLong(4) << "<->"
1058         << input->readLong(4) << "x" << input->readLong(4) << ",";
1059       break;
1060     case 10:
1061     case 11:
1062       f << (type==10 ? "polyline" : "polygon") << ",";
1063       *input >> nTmp;
1064       if (nTmp<0 || nTmp>(endDataPos-input->tell())/8) {
1065         STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: bad number of points\n"));
1066         f << "###nPts=" << nTmp << ",";
1067         break;
1068       }
1069       f << "pts=[";
1070       for (int pt=0; pt<int(nTmp); ++pt) f << input->readLong(4) << "x" << input->readLong(4) << ",";
1071       f << "],";
1072       break;
1073     case 12:
1074     case 1024:
1075     case 1025:
1076     case 1030:
1077       f << (type==12 ? "polypoly" : type==1024 ? "transparent[comment]" :
1078             type==1025 ? "hatch[comment]" : "gradient[comment]") << ",";
1079       *input >> nTmp;
1080       for (int poly=0; poly<int(nTmp) && !input->isEnd(); ++poly) {
1081         *input >> nTmp1;
1082         if (nTmp1<0 || nTmp1>(endDataPos-input->tell())/8) {
1083           STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: bad number of points\n"));
1084           f << "###poly[nPts=" << nTmp1 << "],";
1085           break;
1086         }
1087         f << "poly" << poly << "=[";
1088         for (int pt=0; pt<int(nTmp1); ++pt) f << input->readLong(4) << "x" << input->readLong(4) << ",";
1089         f << "],";
1090       }
1091       if (type==1024) {
1092         f << "nTrans=" << input->readULong(2) << ",";
1093         f << "nComment=" << input->readULong(4) << ",";
1094       }
1095       if (type==1025) {
1096         f << "style=" << input->readULong(2) << ",";
1097         for (unsigned char &c : col) c=static_cast<unsigned char>(input->readULong(2)>>8);
1098         f << "col=" << STOFFColor(col[0],col[1],col[2]) << ",";
1099         f << "distance=" << input->readLong(4) << ",";
1100         f << "nComment=" << input->readULong(4) << ",";
1101       }
1102       if (type==1030) {
1103         STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: reading gradient is not implemented\n"));
1104         f << "###gradient+following";
1105         input->seek(endDataPos, librevenge::RVNG_SEEK_SET);
1106       }
1107       break;
1108     case 13:
1109     case 15: {
1110       f << (type==13 ? "text" : "stretch") << ",";
1111       f << "pos=" << input->readLong(4) << "x" << input->readLong(4) << ",";
1112       int32_t nIndex, nLen;
1113       *input>>nIndex>>nLen >> nTmp;
1114       if (nIndex) f << "index=" << nIndex << ",";
1115       if (nLen) f << "len=" << nLen << ",";
1116       if (type==15) f << "nWidth=" << input->readLong(4) << ",";
1117       if (nTmp<0 || input->tell()+nTmp>endDataPos) {
1118         STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: bad string\n"));
1119         f << "###string";
1120         break;
1121       }
1122       text.clear();
1123       for (int c=0; c<int(nTmp); ++c) text.push_back(static_cast<uint32_t>(input->readULong(1)));
1124       input->seek(1, librevenge::RVNG_SEEK_CUR);
1125       f << libstoff::getString(text).cstr() << ",";
1126       if (nUnicodeCommentActionNumber!=static_cast<uint32_t>(i)) break;
1127       uint16_t type1;
1128       uint32_t len;
1129       *input >> type1 >> len;
1130       if (long(len)<4 || input->tell()+long(len)>endDataPos) {
1131         STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: bad string\n"));
1132         f << "###unicode";
1133         break;
1134       }
1135       if (type1==1032) {
1136         text.clear();
1137         int nUnicode=int(len-4)/2;
1138         for (int c=0; c<nUnicode; ++c) text.push_back(static_cast<uint32_t>(input->readULong(2)));
1139         f << libstoff::getString(text).cstr() << ",";
1140       }
1141       else {
1142         STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: unknown data\n"));
1143         f << "###unknown";
1144         input->seek(long(len)-4, librevenge::RVNG_SEEK_CUR);
1145       }
1146       break;
1147     }
1148     case 14: {
1149       f << "text[array],";
1150       f << "pos=" << input->readLong(4) << "x" << input->readLong(4) << ",";
1151       int32_t nIndex, nLen, nAryLen;
1152       *input>>nIndex>>nLen >> nTmp >> nAryLen;
1153       if (nTmp<0 || nAryLen<0 || nAryLen>(endDataPos-input->tell()-nTmp)/4) {
1154         STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: bad string\n"));
1155         f << "###string";
1156         break;
1157       }
1158       text.clear();
1159       for (int c=0; c<int(nTmp); ++c) text.push_back(static_cast<uint32_t>(input->readULong(1)));
1160       input->seek(1, librevenge::RVNG_SEEK_CUR);
1161       f << libstoff::getString(text).cstr() << ",";
1162       f << "ary=[";
1163       for (int ary=0; ary<int(nAryLen); ++ary) f << input->readLong(4) << ",";
1164       f << "],";
1165       if (nUnicodeCommentActionNumber!=static_cast<uint32_t>(i)) break;
1166       uint16_t type1;
1167       uint32_t len;
1168       *input >> type1 >> len;
1169       if (long(len)<4 || input->tell()+long(len)>endDataPos) {
1170         STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: bad string\n"));
1171         f << "###unicode";
1172         break;
1173       }
1174       if (type1==1032) {
1175         text.clear();
1176         int nUnicode=int(len-4)/2;
1177         for (int c=0; c<nUnicode; ++c) text.push_back(static_cast<uint32_t>(input->readULong(2)));
1178         f << libstoff::getString(text).cstr() << ",";
1179       }
1180       else {
1181         STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: unknown data\n"));
1182         f << "###unknown";
1183         input->seek(long(len)-4, librevenge::RVNG_SEEK_CUR);
1184       }
1185 
1186       break;
1187     }
1188     case 16:
1189       STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: reading icon is not implemented\n"));
1190       f << "###icon";
1191       break;
1192     case 17:
1193     case 18:
1194     case 32: {
1195       f << (type==17 ? "bitmap" : type==18 ? "bitmap[scale]" : "bitmap[scale2]");
1196       f << "pos=" << input->readLong(4) << "x" << input->readLong(4) << ",";
1197       if (type>=17) f << "scale=" << input->readLong(4) << "x" << input->readLong(4) << ",";
1198       if (type==32) {
1199         f << "pos2=" << input->readLong(4) << "x" << input->readLong(4) << ",";
1200         f << "scale2=" << input->readLong(4) << "x" << input->readLong(4) << ",";
1201       }
1202       StarBitmap bitmap;
1203       librevenge::RVNGBinaryData data;
1204       std::string dataType;
1205       if (!bitmap.readBitmap(zone, false, endDataPos, data, dataType))
1206         f << "###bitmap,";
1207       break;
1208     }
1209     case 19:
1210       f << "pen,";
1211       for (unsigned char &c : col) c=static_cast<unsigned char>(input->readULong(2)>>8);
1212       color=STOFFColor(col[0],col[1],col[2]);
1213       if (!color.isBlack()) f << "col=" << color << ",";
1214       f << "penWidth=" << input->readULong(4) << ",";
1215       f << "penStyle=" << input->readULong(2) << ",";
1216       break;
1217     case 20: {
1218       f << "font,";
1219       for (int c=0; c<2; ++c) {
1220         for (unsigned char &j : col) j=static_cast<unsigned char>(input->readULong(2)>>8);
1221         color=STOFFColor(col[0],col[1],col[2]);
1222         if ((c==1&&!color.isWhite()) || (c==0&&!color.isBlack()))
1223           f << (c==0 ? "col" : "col[fill]") << "=" << color << ",";
1224       }
1225       long actPos=input->tell();
1226       if (actPos+62>endDataPos) {
1227         STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: the zone seems too short\n"));
1228         f << "###short";
1229         break;
1230       }
1231       std::string name("");
1232       for (int c=0; c<32; ++c) {
1233         auto ch=char(input->readULong(1));
1234         if (!ch) break;
1235         name+=ch;
1236       }
1237       f << name << ",";
1238       input->seek(actPos+32, librevenge::RVNG_SEEK_SET);
1239       f << "size=" << input->readLong(4) << "x" << input->readLong(4) << ",";
1240       int16_t nCharSet, nFamily, nPitch, nAlign, nWeight, nUnderline, nStrikeout, nCharOrient, nLineOrient;
1241       bool bItalic, bOutline, bShadow, bTransparent;
1242       *input >> nCharSet >> nFamily >> nPitch >> nAlign >> nWeight >> nUnderline >> nStrikeout >> nCharOrient >> nLineOrient;
1243       if (nCharSet) f << "char[set]=" << nCharSet << ",";
1244       if (nFamily) f << "family=" << nFamily << ",";
1245       if (nPitch) f << "pitch=" << nPitch << ",";
1246       if (nAlign) f << "align=" << nAlign << ",";
1247       if (nWeight) f << "weight=" << nWeight << ",";
1248       if (nUnderline) f << "underline=" << nUnderline << ",";
1249       if (nStrikeout) f << "strikeout=" << nStrikeout << ",";
1250       if (nCharOrient) f << "charOrient=" << nCharOrient << ",";
1251       if (nLineOrient) f << "lineOrient=" << nLineOrient << ",";
1252       *input >> bItalic >> bOutline >> bShadow >> bTransparent;
1253       if (bItalic) f << "italic,";
1254       if (bOutline) f << "outline,";
1255       if (bShadow) f << "shadow,";
1256       if (bTransparent) f << "transparent,";
1257       break;
1258     }
1259     case 21: // unsure
1260     case 22:
1261       f << (type==21 ? "brush[back]" : "brush[fill]") << ",";
1262       for (unsigned char &j : col) j=static_cast<unsigned char>(input->readULong(2)>>8);
1263       f << STOFFColor(col[0],col[1],col[2]) << ",";
1264       input->seek(6, librevenge::RVNG_SEEK_CUR); // unknown
1265       f << "style=" << input->readLong(2) << ",";
1266       input->seek(2, librevenge::RVNG_SEEK_CUR); // unknown
1267       break;
1268     case 23:
1269       f << "map[mode],";
1270       *input >> unit >> orgX >> orgY >> nXNum >> nXDenom >> nYNum >> nYDenom;
1271       if (unit) f << "unit=" << unit << ",";
1272       f << "orig=" << orgX << "x" << orgY << ",";
1273       f << "x=" << nXNum << "/" << nXDenom << ",";
1274       f << "y=" << nYNum << "/" << nYDenom << ",";
1275       break;
1276     case 24: {
1277       f << "clip[region],";
1278       int16_t clipType, bIntersect;
1279       *input >> clipType >> bIntersect;
1280       f << "rect=" << input->readLong(4) << "x" << input->readLong(4) << "<->"
1281         << input->readLong(4) << "x" << input->readLong(4) << ",";
1282       if (bIntersect) f << "intersect,";
1283       switch (clipType) {
1284       case 0:
1285         break;
1286       case 1:
1287         f << "rect2=" << input->readLong(4) << "x" << input->readLong(4) << "<->"
1288           << input->readLong(4) << "x" << input->readLong(4) << ",";
1289         break;
1290       case 2:
1291         *input >> nTmp;
1292         if (nTmp<0 || nTmp>(endDataPos-input->tell())/8) {
1293           STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: bad number of points\n"));
1294           f << "###nPts=" << nTmp << ",";
1295           break;
1296         }
1297         f << "poly=[";
1298         for (int pt=0; pt<int(nTmp); ++pt) f << input->readLong(4) << "x" << input->readLong(4) << ",";
1299         f << "],";
1300         break;
1301       case 3:
1302         *input >> nTmp;
1303         for (int poly=0; poly<int(nTmp) && !input->isEnd(); ++poly) {
1304           *input >> nTmp1;
1305           if (nTmp1<0 || nTmp1>(endDataPos-input->tell())/8) {
1306             STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: bad number of points\n"));
1307             f << "###poly[nPts=" << nTmp1 << "],";
1308             break;
1309           }
1310           f << "poly" << poly << "=[";
1311           for (int pt=0; pt<int(nTmp1); ++pt) f << input->readLong(4) << "x" << input->readLong(4) << ",";
1312           f << "],";
1313         }
1314         break;
1315       default:
1316         STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: find unknown clip type\n"));
1317         f << "###type=" << clipType << ",";
1318         break;
1319       }
1320       break;
1321     }
1322     case 25:
1323       f << "raster=" << input->readULong(2) << ","; // 1 invert, 4,5: xor other paint
1324       break;
1325     case 26:
1326       f << "push,";
1327       break;
1328     case 27:
1329       f << "pop,";
1330       break;
1331     case 28:
1332       f << "clip[move]=" << input->readLong(4) << "x" << input->readLong(4) << ",";
1333       break;
1334     case 29:
1335       f << "clip[rect]=" << input->readLong(4) << "x" << input->readLong(4) << "<->"
1336         << input->readLong(4) << "x" << input->readLong(4) << ",";
1337       break;
1338     case 30: // checkme
1339     case 1029: {
1340       f << (type==30 ? "mtf" : "floatComment") << ",";;
1341       // gdimtf.cxx operator>>(... GDIMetaFile )
1342       std::string name("");
1343       for (int c=0; c<6; ++c) name+=char(input->readULong(1));
1344       if (name!="VCLMTF") {
1345         STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: find unexpected header\n"));
1346         f << "###name=" << name << ",";
1347         break;
1348       }
1349       if (!zone.openVersionCompatHeader()) {
1350         STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: can not open compat header\n"));
1351         f << "###compat,";
1352         break;
1353       }
1354       f << "compress=" << input->readULong(4) << ",";
1355       // map mode
1356       *input >> unit >> orgX >> orgY >> nXNum >> nXDenom >> nYNum >> nYDenom;
1357       f << "map=[";
1358       if (unit) f << "unit=" << unit << ",";
1359       f << "orig=" << orgX << "x" << orgY << ",";
1360       f << "x=" << nXNum << "/" << nXDenom << ",";
1361       f << "y=" << nYNum << "/" << nYDenom << ",";
1362       f << "],";
1363       f << "size=" << input->readULong(4) << ",";
1364       uint32_t nCount;
1365       *input >> nCount;
1366       if (nCount) f << "nCount=" << nCount << ",";
1367       if (input->tell()!=zone.getRecordLastPosition()) {
1368         // for (int act=0; act<nCount; ++act) MetaAction::ReadMetaAction();
1369         STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: reading mtf action zones is not implemented\n"));
1370         ascFile.addPos(input->tell());
1371         ascFile.addNote("ImageSVGDI:###listMeta");
1372         input->seek(zone.getRecordLastPosition(), librevenge::RVNG_SEEK_SET);
1373       }
1374       zone.closeVersionCompatHeader("ImageSVGDI");
1375       if (type!=30) {
1376         f << "orig=" << input->readLong(4) << "x" << input->readLong(4) << ",";
1377         f << "sz=" << input->readULong(4) << ",";
1378         STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: reading gradient is not implemented\n"));
1379         f << "###gradient+following";
1380         input->seek(endDataPos, librevenge::RVNG_SEEK_SET);
1381       }
1382       break;
1383     }
1384     case 33: {
1385       f << "gradient,";
1386       f << "rect=" << input->readLong(4) << "x" << input->readLong(4) << "<->"
1387         << input->readLong(4) << "x" << input->readLong(4) << ",";
1388       f << "style=" << input->readULong(2) << ",";
1389       for (int c=0; c<2; ++c) {
1390         for (unsigned char &j : col) j=static_cast<unsigned char>(input->readULong(2)>>8);
1391         color=STOFFColor(col[0],col[1],col[2]);
1392         f << "col" << c << "=" << color << ",";
1393       }
1394       f << "angle=" << input->readLong(2) << ",";
1395       f << "border=" << input->readLong(2) << ",";
1396       f << "offs=" << input->readLong(2) << "x" << input->readLong(2) << ",";
1397       f << "intensity=" << input->readLong(2) << "<->" << input->readLong(2) << ",";
1398       break;
1399     }
1400     case 1026:
1401       f << "refpoint[comment],";
1402       f << "pt=" << input->readLong(4) << "x" << input->readLong(4) << ",";
1403       f << "set=" << input->readULong(1) << ",";
1404       f << "nComments=" << input->readULong(4) << ",";
1405       break;
1406     case 1027:
1407       f << "textline[color,comment],";
1408       for (unsigned char &j : col) j=static_cast<unsigned char>(input->readULong(2)>>8);
1409       f << "col=" << STOFFColor(col[0],col[1],col[2]) << ",";
1410       f << "set=" << input->readULong(1) << ",";
1411       f << "nComments=" << input->readULong(4) << ",";
1412       break;
1413     case 1028:
1414       f << "textline[comment],";
1415       f << "pt=" << input->readLong(4) << "x" << input->readLong(4) << ",";
1416       f << "width=" << input->readLong(4) << ",";
1417       f << "strikeOut=" << input->readULong(4) << ",";
1418       f << "underline=" << input->readULong(4) << ",";
1419       f << "nComments=" << input->readULong(4) << ",";
1420       break;
1421     case 1031: {
1422       f << "comment[comment],";
1423       if (!zone.readString(text)) {
1424         STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: can not read the text\n"));
1425         f << "###text,";
1426         break;
1427       }
1428       f << libstoff::getString(text).cstr() << ",";
1429       f << "value=" << input->readULong(4) << ",";
1430       long size=input->readLong(4);
1431       if (size<0 || input->tell()+size+4>endDataPos) {
1432         STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: size seems bad\n"));
1433         f << "###size=" << size << ",";
1434         break;
1435       }
1436       if (size) {
1437         f << "###unknown,";
1438         ascFile.addDelimiter(input->tell(),'|');
1439         input->seek(size, librevenge::RVNG_SEEK_CUR);
1440       }
1441       f << "nComments=" << input->readULong(4) << ",";
1442       break;
1443     }
1444     case 1032:
1445       f << "unicode[next],";
1446       nUnicodeCommentActionNumber=uint32_t(i)+1;
1447       break;
1448     default:
1449       STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: find unimplement type\n"));
1450       f << "###type=" << type << ",";
1451       input->seek(endDataPos, librevenge::RVNG_SEEK_SET);
1452       break;
1453     }
1454     if (input->tell()!=endDataPos) {
1455       STOFF_DEBUG_MSG(("StarFileManager::readSVGDI: find extra data\n"));
1456       f << "###extra,";
1457       ascFile.addDelimiter(input->tell(),'|');
1458     }
1459     ascFile.addPos(pos);
1460     ascFile.addNote(f.str().c_str());
1461     input->seek(endDataPos, librevenge::RVNG_SEEK_SET);
1462   }
1463 
1464   return true;
1465 }
1466 
1467 // vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab:
1468