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