/* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */
/* libmwaw
* Version: MPL 2.0 / LGPLv2+
*
* The contents of this file are subject to the Mozilla Public License Version
* 2.0 (the "License"); you may not use this file except in compliance with
* the License or as specified alternatively below. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* Major Contributor(s):
* Copyright (C) 2002 William Lachance (wrlach@gmail.com)
* Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net)
* Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
* Copyright (C) 2006, 2007 Andrew Ziem
* Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr)
*
*
* All Rights Reserved.
*
* For minor contributions see the git repository.
*
* Alternatively, the contents of this file may be used under the terms of
* the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
* in which case the provisions of the LGPLv2+ are applicable
* instead of those above.
*/
#include <cmath>
#include <iomanip>
#include <iostream>
#include <limits>
#include <sstream>
#include <librevenge/librevenge.h>
#include "MWAWFontConverter.hxx"
#include "MWAWGraphicListener.hxx"
#include "MWAWGraphicShape.hxx"
#include "MWAWGraphicStyle.hxx"
#include "MWAWHeader.hxx"
#include "MWAWParagraph.hxx"
#include "MWAWPictBitmap.hxx"
#include "MWAWPictData.hxx"
#include "MWAWPrinter.hxx"
#include "MWAWPosition.hxx"
#include "MWAWSubDocument.hxx"
#include "ClarisDrawStyleManager.hxx"
#include "ClarisDrawGraph.hxx"
#include "ClarisDrawText.hxx"
#include "ClarisWksStruct.hxx"
#include "ClarisDrawParser.hxx"
/** Internal: the structures of a ClarisDrawParser */
namespace ClarisDrawParserInternal
{
// generic class used to defined a layer
struct Layer {
//! constructor
Layer()
: m_groupId(0)
, m_isHidden(false)
, m_name("")
{
}
//! the first group id
int m_groupId;
//! true if the layer is hidden
bool m_isHidden;
//! the layer name
librevenge::RVNGString m_name;
};
////////////////////////////////////////////
//! Internal: the state of a ClarisDrawParser
struct State {
//! constructor
State()
: m_version(0)
, m_isLibrary(false)
, m_numDSET(0)
, m_EOF(-1)
, m_actualLayer(1)
, m_numLayers(1)
, m_createMasterPage(false)
, m_displayAsSlide(false)
, m_layerList()
, m_pageSpanSet(false)
, m_headerId(0)
, m_footerId(0)
, m_pages(1,1)
, m_zonesMap()
, m_zoneIdToFileTypeMap()
{
}
//! the file version
int m_version;
//! flag to know if the file is a library or not
bool m_isLibrary;
//! the number of DSET+FNTM
int m_numDSET;
//! the last data zone size
long m_EOF;
//! the actual layer
int m_actualLayer;
//! the number of layer
int m_numLayers;
//! flag to know if we need or not to create a master
bool m_createMasterPage;
//! flag to know if we need to display data as slide
bool m_displayAsSlide;
//! the layer list
std::vector<Layer> m_layerList;
//! flag to know if the page has been set
bool m_pageSpanSet;
//! header id
int m_headerId;
//! footer id
int m_footerId;
//! the number of pages
MWAWVec2i m_pages;
/** the map of zone*/
std::map<int, std::shared_ptr<ClarisWksStruct::DSET> > m_zonesMap;
/** map zone id to file type */
std::map<int, int> m_zoneIdToFileTypeMap;
};
}
////////////////////////////////////////////////////////////
// constructor/destructor, ...
////////////////////////////////////////////////////////////
ClarisDrawParser::ClarisDrawParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header)
: MWAWGraphicParser(input, rsrcParser, header)
, m_state()
, m_styleManager()
, m_graphParser()
, m_textParser()
{
init();
}
ClarisDrawParser::~ClarisDrawParser()
{
}
void ClarisDrawParser::init()
{
resetGraphicListener();
setAsciiName("main-1");
m_state.reset(new ClarisDrawParserInternal::State);
m_styleManager.reset(new ClarisDrawStyleManager(*this));
m_graphParser.reset(new ClarisDrawGraph(*this));
m_textParser.reset(new ClarisDrawText(*this));
getPageSpan().setMargins(0.1);
}
int ClarisDrawParser::getFileType(int zoneId) const
{
if (m_state->m_zoneIdToFileTypeMap.find(zoneId) == m_state->m_zoneIdToFileTypeMap.end()) {
MWAW_DEBUG_MSG(("ClarisDrawParser::getFileType: zone %d does not exists!!!!\n", zoneId));
return -1;
}
return m_state->m_zoneIdToFileTypeMap.find(zoneId)->second;
}
bool ClarisDrawParser::sendTextZone(int number, int subZone)
{
return m_textParser->sendZone(number, subZone);
}
MWAWVec2f ClarisDrawParser::getPageLeftTop()
{
return MWAWVec2f(float(getParserState()->m_pageSpan.getMarginLeft()),
float(getParserState()->m_pageSpan.getMarginTop()));
}
////////////////////////////////////////////////////////////
// the parser
////////////////////////////////////////////////////////////
void ClarisDrawParser::parse(librevenge::RVNGDrawingInterface *docInterface)
{
if (!getInput().get() || !checkHeader(nullptr)) throw(libmwaw::ParseException());
bool ok = false;
try {
// create the asciiFile
ascii().setStream(getInput());
ascii().open(asciiName());
checkHeader(nullptr);
ok = createZones();
if (ok) {
createDocument(docInterface);
MWAWVec2f leftTop=72.0f*getPageLeftTop();
MWAWPosition pos(leftTop,MWAWVec2f(0,0),librevenge::RVNG_POINT);
pos.setRelativePosition(MWAWPosition::Page);
MWAWGraphicListenerPtr listener=getGraphicListener();
if (m_state->m_isLibrary) {
for (size_t i=0; i<m_state->m_layerList.size(); ++i) {
if (i>0)
listener->insertBreak(MWAWListener::PageBreak);
m_graphParser->sendMainGroupChild(int(i), pos);
}
}
else if (m_state->m_displayAsSlide) {
bool first=true;
for (size_t i=1; i< m_state->m_layerList.size(); ++i) {
if (m_graphParser->isEmptyGroup(m_state->m_layerList[i].m_groupId))
continue;
if (!first)
listener->insertBreak(MWAWListener::PageBreak);
first=false;
m_graphParser->sendGroup(m_state->m_layerList[i].m_groupId, pos);
}
}
else {
for (size_t i=1; i< m_state->m_layerList.size(); ++i) {
if (m_graphParser->isEmptyGroup(m_state->m_layerList[i].m_groupId))
continue;
bool openLayer=false;
if (!m_state->m_layerList[i].m_name.empty())
openLayer=listener->openLayer(m_state->m_layerList[i].m_name);
m_graphParser->sendGroup(m_state->m_layerList[i].m_groupId, pos);
if (openLayer)
listener->closeLayer();
}
}
#ifdef DEBUG
m_graphParser->flushExtra();
#endif
}
ascii().reset();
}
catch (...) {
MWAW_DEBUG_MSG(("ClarisDrawParser::parse: exception catched when parsing\n"));
ok = false;
}
resetGraphicListener();
if (!ok) throw(libmwaw::ParseException());
}
////////////////////////////////////////////////////////////
// create the document
////////////////////////////////////////////////////////////
void ClarisDrawParser::createDocument(librevenge::RVNGDrawingInterface *documentInterface)
{
if (!documentInterface) return;
if (getGraphicListener()) {
MWAW_DEBUG_MSG(("ClarisDrawParser::createDocument: listener already exist\n"));
return;
}
m_graphParser->updateGroup(m_state->m_isLibrary);
// create the page list
int numPages=1;
MWAWPageSpan ps(getPageSpan());
ps.setPageSpan(1);
std::vector<librevenge::RVNGString> listNames;
if (m_state->m_isLibrary) {
numPages=static_cast<int>(m_state->m_layerList.size());
if (numPages<1) numPages=1;
}
else {
m_state->m_createMasterPage=!m_state->m_layerList.empty() &&
!m_graphParser->isEmptyGroup(m_state->m_layerList[0].m_groupId);
if (m_state->m_createMasterPage)
ps.setMasterPageName(librevenge::RVNGString("Master"));
for (size_t i=1; i<m_state->m_layerList.size(); ++i) {
if (!m_graphParser->isEmptyGroup(m_state->m_layerList[i].m_groupId))
listNames.push_back(m_state->m_layerList[i].m_name);
}
if (m_state->m_displayAsSlide && !listNames.empty())
numPages=static_cast<int>(listNames.size());
}
std::vector<MWAWPageSpan> pageList;
for (int i=0; i<numPages; ++i) {
MWAWPageSpan page(ps);
if (m_state->m_isLibrary && i<static_cast<int>(m_state->m_layerList.size()))
page.setPageName(m_state->m_layerList[size_t(i)].m_name);
else if (m_state->m_displayAsSlide && i<static_cast<int>(listNames.size()))
page.setPageName(listNames[size_t(i)]);
pageList.push_back(page);
}
MWAWGraphicListenerPtr listen(new MWAWGraphicListener(*getParserState(), pageList, documentInterface));
setGraphicListener(listen);
listen->startDocument();
if (!m_state->m_createMasterPage)
return;
// we need to send the master page
if (!listen->openMasterPage(ps)) {
MWAW_DEBUG_MSG(("ClarisDrawParser::createDocument: can not create the master page\n"));
m_state->m_createMasterPage=false;
return;
}
MWAWVec2f leftTop=72.0f*getPageLeftTop();
MWAWPosition pos(leftTop,MWAWVec2f(0,0),librevenge::RVNG_POINT);
pos.setRelativePosition(MWAWPosition::Page);
m_graphParser->sendGroup(m_state->m_layerList[0].m_groupId, pos);
listen->closeMasterPage();
}
////////////////////////////////////////////////////////////
//
// Intermediate level
//
////////////////////////////////////////////////////////////
bool ClarisDrawParser::createZones()
{
MWAWInputStreamPtr input = getInput();
if ((m_state->m_isLibrary && !readLibraryHeader()) ||
(!m_state->m_isLibrary && !readDocHeader()))
return false;
if (m_state->m_EOF>0)
input->pushLimit(m_state->m_EOF);
while (readZone());
if (!input->isEnd()) {
ascii().addPos(input->tell());
ascii().addNote("Entries(BAD)");
}
while (!input->isEnd()) {
long pos=input->tell();
if (input->readULong(4)!=0x44534554) {
input->seek(pos+1, librevenge::RVNG_SEEK_SET);
continue;
}
input->seek(pos, librevenge::RVNG_SEEK_SET);
long actPos=input->tell();
while (readZone())
actPos=input->tell();
if (actPos==pos) {
input->seek(actPos+4, librevenge::RVNG_SEEK_SET);
continue;
}
input->seek(actPos, librevenge::RVNG_SEEK_SET);
if (input->isEnd()) break;
MWAW_DEBUG_MSG(("ClarisDrawParser::createZones: oops loose tracks of zones\n"));
ascii().addPos(input->tell());
ascii().addNote("Entries(BAD):###");
}
if (m_state->m_EOF>0)
input->popLimit();
return true;
}
bool ClarisDrawParser::readZone()
{
MWAWInputStreamPtr input = getInput();
long pos=input->tell();
if (!input->checkPosition(pos+4))
return false;
auto zoneSz=long(input->readULong(4));
std::string what("Unknown");
if (zoneSz==0x44534554) {
input->seek(pos, librevenge::RVNG_SEEK_SET);
return readDSET().get()!=nullptr;
}
else if (zoneSz==0x464e544d) {
input->seek(pos, librevenge::RVNG_SEEK_SET);
return m_styleManager->readFontNames();
}
else if ((zoneSz>>16)>16) {
input->seek(pos, librevenge::RVNG_SEEK_SET);
return false;
}
else if ((zoneSz>>16)!=0) {
ascii().addPos(pos);
ascii().addNote("Entries(Short)");
input->seek(pos+2, librevenge::RVNG_SEEK_SET);
return true;
}
long endPos=input->tell()+zoneSz;
if (zoneSz<0 || ((zoneSz&1) && (zoneSz==0x4453 || zoneSz==0x464e)) || !input->checkPosition(endPos)) {
input->seek(pos, librevenge::RVNG_SEEK_SET);
return false;
}
libmwaw::DebugStream f;
if (zoneSz==0)
f << "_";
else
f << "Entries(" << what << ")";
ascii().addPos(pos);
ascii().addNote(f.str().c_str());
input->seek(endPos, librevenge::RVNG_SEEK_SET);
return true;
}
bool ClarisDrawParser::readDocHeader()
{
MWAWInputStreamPtr input = getInput();
if (!input->checkPosition(0x80A)) return false;
input->seek(8, librevenge::RVNG_SEEK_SET);
libmwaw::DebugStream f;
f << "Entries(DocHeader):";
auto val = static_cast<int>(input->readLong(2)); // always find 1
if (val != 1)
f << "#unkn=" << std::hex << val << std::dec << ",";
for (int i = 0; i < 4; i++) {
val = static_cast<int>(input->readULong(2));
if (val)
f << std::hex << "f" << i << "=" << std::hex << val << std::dec << ",";
}
int dim[2];
for (int &i : dim) i= static_cast<int>(input->readLong(2));
f << "dim?=" << dim[1] << "x" << dim[0] << ",";
int margin[6];
f << "margin?=[";
for (int &i : margin) {
i = static_cast<int>(input->readLong(2));
if (i)
f << i << ",";
else
f << "_,";
}
f << "],";
// seems a good indication that slide mode is choosen
if (dim[0] > 0 && dim[1] > 0 &&
margin[0] >= 0 && margin[1] >= 0 && margin[2] >= 0 && margin[3] >= 0 &&
dim[0] > margin[0]+margin[2] && dim[1] > margin[1]+margin[3]) {
MWAWVec2i paperSize(dim[1],dim[0]);
MWAWVec2i lTopMargin(margin[1], margin[0]);
MWAWVec2i rBotMargin(margin[3], margin[2]);
getPageSpan().setMarginTop(lTopMargin.y()/72.0);
getPageSpan().setMarginBottom(rBotMargin.y()/72.0);
getPageSpan().setMarginLeft(lTopMargin.x()/72.0);
getPageSpan().setMarginRight(rBotMargin.x()/72.0);
getPageSpan().setFormLength(paperSize.y()/72.);
getPageSpan().setFormWidth(paperSize.x()/72.);
m_state->m_pageSpanSet = true;
}
int dim2[2];
for (int &i : dim2) i = static_cast<int>(input->readLong(2));
f << "dim2?=" << dim2[1] << "x" << dim2[0] << ",";
int fl[4];
f << "fl?=[";
for (int &i : fl) {
i = static_cast<int>(input->readULong(1));
if (i)
f << i << ",";
else
f << "_,";
}
f << "],";
for (int i = 0; i < 9; i++) {
val = static_cast<int>(input->readLong(2));
if (val)
f << "g" << i << "=" << val << ",";
}
ascii().addDelimiter(input->tell(), '|');
ascii().addPos(8);
ascii().addNote(f.str().c_str());
input->seek(8+132, librevenge::RVNG_SEEK_SET);
/* zone 1 actual font, actul pos, .. */
if (!m_textParser->readParagraph())
return false;
long pos = input->tell();
f.str("");
f << "DocHeader:zone?=" << input->readULong(2) << ",";
ascii().addPos(pos);
ascii().addNote(f.str().c_str());
MWAWFont font;
int posChar;
if (!m_textParser->readFont(-1, posChar, font))
return false;
/* zone 2, type, unknown */
pos = input->tell();
f.str("");
f << "DocHeader-1:";
for (int i = 0; i < 6; i++) {
val = static_cast<int>(input->readULong(2));
if (val) f << "f" << i << "=" << val << ",";
}
ascii().addDelimiter(input->tell(), '|');
input->seek(pos+20, librevenge::RVNG_SEEK_SET);
ascii().addPos(pos);
ascii().addNote(f.str().c_str());
// the document font ?
if (!m_textParser->readFont(-1, posChar, font))
return false;
pos=input->tell();
f.str("");
f << "DocHeader-2:";
for (int i=0; i<5; ++i) {
val=static_cast<int>(input->readULong(2));
static int const expected[] = {0,1,2,2,0};
if (val!=expected[i])
f << "f" << i << "=" << val << ",";
}
for (int i=0; i<8; ++i) {
val=static_cast<int>(input->readULong(1));
static int const expected[] = {1/*or 16*/,0,0,0,0,1,1, 0};
if (val!=expected[i])
f << "f" << i+5 << "=" << val << ",";
}
for (int i=0; i<4; ++i) {
val=static_cast<int>(input->readULong(2));
static int const expected[] = {1,1,0x2d,0};
if (val!=expected[i])
f << "f" << i+13 << "=" << val << ",";
}
f << "fl=[";
for (int i=0; i<13; ++i) {
val=static_cast<int>(input->readULong(1));
if (val==1) f << "*,";
else if (val) f << val << ",";
else f << "_,";
}
f << "],";
for (int i=0; i<16; ++i) { // always 0
val=static_cast<int>(input->readULong(2));
if (val)
f << "g" << i << "=" << val << ",";
}
for (int i=0; i<5; ++i) {
val=static_cast<int>(input->readULong(2));
static int const expected[] = {0,1,0,0x600,0x504};
if (val!=expected[i])
f << "h" << i << "=" << std::hex << val << std::dec << ",";
}
val=static_cast<int>(input->readULong(1)); // always 0
if (val) f << "h5=" << val << ",";
int num[3];
for (int i=0; i<3; ++i) {
num[i]=static_cast<int>(input->readULong(2));
if (!num[i])
continue;
static char const *wh[]= {"color", "unkn1", "gradient"};
f << "num[" << wh[i] << "]=" << num[i] << ",";
}
m_styleManager->setDefaultNumbers(num[0], num[2]);
ascii().addDelimiter(input->tell(),'|');
ascii().addPos(pos);
ascii().addNote(f.str().c_str());
input->seek(pos+124, librevenge::RVNG_SEEK_SET);
pos=input->tell();
f.str("");
f << "DocHeader(Col):";
auto numCols = static_cast<int>(input->readLong(2));
if (numCols < 1 || numCols > 9) {
MWAW_DEBUG_MSG(("ClarisDrawParser::readDocHeader: pb reading number of columns\n"));
f << "###numCols=" << numCols;
numCols = 1;
}
if (numCols != 1)
f << "numCols=" << numCols << ",";
f << "colsW=[";
for (int i = 0; i < numCols; i++) {
val = static_cast<int>(input->readULong(2));
f << val << ",";
}
f << "],";
input->seek(pos+20, librevenge::RVNG_SEEK_SET);
if (numCols > 1) {
f << "colsS=[";
for (int i = 0; i < numCols-1; i++) {
val = static_cast<int>(input->readULong(2));
f << input->readULong(2);
if (val) f << ":" << val << ",";
}
f << "],";
}
input->seek(pos+36, librevenge::RVNG_SEEK_SET);
val = static_cast<int>(input->readLong(2));
if (val) f << "unkn=" << val << ",";
ascii().addPos(pos);
ascii().addNote(f.str().c_str());
pos=input->tell();
input->seek(pos+214, librevenge::RVNG_SEEK_SET);
ascii().addPos(pos);
ascii().addNote("DocHeader-3");
pos=input->tell(); // only 0?
input->seek(pos+256, librevenge::RVNG_SEEK_SET);
ascii().addPos(pos);
ascii().addNote("DocHeader-4");
pos=input->tell();
input->seek(pos+190, librevenge::RVNG_SEEK_SET);
ascii().addPos(pos);
ascii().addNote("DocHeader-5");
pos=input->tell(); // only 0?
input->seek(pos+256, librevenge::RVNG_SEEK_SET);
ascii().addPos(pos);
ascii().addNote("DocHeader-6");
pos=input->tell();
input->seek(pos+256+96, librevenge::RVNG_SEEK_SET);
ascii().addPos(pos);
ascii().addNote("DocHeader-7");
pos=input->tell();
f.str("");
f << "DocHeader-8:";
input->seek(pos+111, librevenge::RVNG_SEEK_SET);
val=static_cast<int>(input->readLong(1));
if (val==1) {
f << "slide,";
m_state->m_displayAsSlide=true;
}
else if (val) {
MWAW_DEBUG_MSG(("ClarisDrawParser::readDocHeader: pb reading the viewer style\n"));
f << "###slide=" << val << ",";
}
input->seek(pos+150, librevenge::RVNG_SEEK_SET);
ascii().addPos(pos);
ascii().addNote(f.str().c_str());
pos=input->tell();
input->seek(pos+130, librevenge::RVNG_SEEK_SET);
ascii().addPos(pos);
ascii().addNote("DocHeader-9");
pos=input->tell();
ascii().addPos(pos);
ascii().addNote("DocHeader-A");
input->seek(0x80A, librevenge::RVNG_SEEK_SET);
// now 25 zones
for (int i=0; i<25; ++i) {
if (input->isEnd())
return false;
pos=input->tell();
auto zoneSz=long(input->readULong(4));
if (!zoneSz) {
ascii().addPos(pos);
ascii().addNote("_");
continue;
}
if (!input->checkPosition(pos+4+zoneSz)) {
MWAW_DEBUG_MSG(("ClarisDrawParser::readDocHeader: can not find zone %d\n", i+1));
ascii().addPos(pos);
ascii().addNote("###");
input->seek(pos, librevenge::RVNG_SEEK_SET);
return true;
}
input->seek(pos, librevenge::RVNG_SEEK_SET);
bool done=false;
switch (i+1) {
case 1:
done=m_textParser->readParagraphs();
break;
case 2:
done=readPrintInfo();
break;
case 3:
done=m_styleManager->readPatternList();
break;
case 4:
done=m_styleManager->readGradientList();
break;
case 6:
done=m_styleManager->readFontStyles();
break;
case 8: // never seens data: fieldData=4, headerSize=14 (always 1,5,0,100,101,0,101,0,1,12710?)
done = ClarisWksStruct::readStructZone(*getParserState(), "Zone8A", false);
break;
case 9: // never seens data: fieldData=12, headerSize=4 (1,id)
done = ClarisWksStruct::readStructZone(*getParserState(), "Zone9A", false);
break;
case 10: // never seens data: fieldData=4, headerSize=4 (1,id)
done = ClarisWksStruct::readStructZone(*getParserState(), "Zone10A", false);
break;
// CHECKME
case 16: // Arrow
done=m_styleManager->readArrows();
break;
case 17: // Dash
done=m_styleManager->readDashs();
break;
case 18: // Ruler style
done=m_styleManager->readRulers();
break;
case 20:
done = m_graphParser->readTransformations();
break;
case 21: // fieldData=36
done = ClarisWksStruct::readStructZone(*getParserState(), "Zone21A", false);
break;
case 22: // fieldData=4, headerSize=4 (1, consecutive id)
done = ClarisWksStruct::readStructZone(*getParserState(), "Zone22A", false);
break;
default:
break;
}
if (done) continue;
f.str("");
f << "Entries(Zone" << i+1 << "A):";
ascii().addPos(pos);
ascii().addNote(f.str().c_str());
input->seek(pos+4+zoneSz, librevenge::RVNG_SEEK_SET);
}
pos=input->tell();
if (!readDocInfo()) {
input->seek(pos, librevenge::RVNG_SEEK_SET);
return true;
}
pos=input->tell();
if (!readLayouts()) {
MWAW_DEBUG_MSG(("ClarisDrawParser::readDocHeader: can not find layout zone\n"));
input->seek(pos, librevenge::RVNG_SEEK_SET);
return true;
}
pos=input->tell();
input->seek(pos+4, librevenge::RVNG_SEEK_SET);
if (input->readULong(2)!=0x100) {
MWAW_DEBUG_MSG(("ClarisDrawParser::readDocHeader: can not find UnknZone zone\n"));
input->seek(pos, librevenge::RVNG_SEEK_SET);
return true;
}
ascii().addPos(pos);
ascii().addNote("Entries(UnknZone0)");
input->seek(pos+832, librevenge::RVNG_SEEK_SET);
// now 12 zones
for (int i=0; i<12; ++i) {
if (input->isEnd())
return false;
pos=input->tell();
auto zoneSz=long(input->readULong(4));
if (!zoneSz) {
ascii().addPos(pos);
ascii().addNote("_");
continue;
}
if (!input->checkPosition(pos+4+zoneSz)) {
MWAW_DEBUG_MSG(("ClarisDrawParser::readDocHeader: can not find zone %d\n", i+1));
ascii().addPos(pos);
ascii().addNote("###");
input->seek(pos, librevenge::RVNG_SEEK_SET);
return true;
}
input->seek(pos, librevenge::RVNG_SEEK_SET);
bool done=false;
switch (i+1) {
case 1: // never seens data: fieldData=4, headerSize=4 (1,id)
done = ClarisWksStruct::readStructZone(*getParserState(), "ZoneB1A", false);
break;
case 3: // never seens data: fieldData=6, headerSize=0
done = ClarisWksStruct::readStructZone(*getParserState(), "ZoneB3A", false);
break;
case 4:// never seens data: fieldData=14, headerSize=0
done = ClarisWksStruct::readStructZone(*getParserState(), "ZoneB4A", false);
break;
case 5:// never seens data: fieldData=14, headerSize=0
done = ClarisWksStruct::readStructZone(*getParserState(), "ZoneB5A", false);
break;
case 6:// never seens data: fieldData=8, headerSize=80
done = ClarisWksStruct::readStructZone(*getParserState(), "ZoneB6A", false);
break;
case 7:// never seens data: fieldData=28, headerSize=80
done = ClarisWksStruct::readStructZone(*getParserState(), "ZoneB7A", false);
break;
case 8:// never seens data: fieldData=1e, headerSize=0
done = ClarisWksStruct::readStructZone(*getParserState(), "ZoneB8A", false);
break;
case 9:// TODO: fieldData=1c (2*double+), headerSize=0
done = ClarisWksStruct::readStructZone(*getParserState(), "ZoneB9A", false);
break;
case 10:
done = m_styleManager->readColorList();
break;
case 11:// never seens data: fieldData=c, headerSize=0
done = ClarisWksStruct::readStructZone(*getParserState(), "ZoneB11A", false);
break;
case 12:// never seens data: fieldData=32, headerSize=0
done = ClarisWksStruct::readStructZone(*getParserState(), "ZoneB12A", false);
break;
default:
break;
}
if (done) continue;
f.str("");
f << "Entries(ZoneB" << i+1 << "A):";
ascii().addPos(pos);
ascii().addNote(f.str().c_str());
input->seek(pos+4+zoneSz, librevenge::RVNG_SEEK_SET);
}
pos=input->tell();
f.str("");
f << "Entries(NDSET):";
m_state->m_numDSET=static_cast<int>(input->readLong(2));
if (m_state->m_numDSET) f << "num=" << m_state->m_numDSET << ",";
ascii().addPos(pos);
ascii().addNote(f.str().c_str());
return true;
}
bool ClarisDrawParser::readLibraryHeader()
{
MWAWInputStreamPtr input = getInput();
libmwaw::DebugStream f;
f << "Entries(LibHeader):";
if (!input->checkPosition(846)) return false;
input->seek(8, librevenge::RVNG_SEEK_SET);
long val=input->readLong(4); // always 0
if (val) f << "f0=" << val << ",";
f << "ID=" << std::hex << input->readULong(4) << std::dec << ","; // a big number
val=input->readLong(2); // always 0x100
if (val!=0x100) f << "f1=" << val << ",";
for (int i=0; i<5; ++i) { // always 0
val=input->readLong(2);
if (val) f << "f" << i+2 << "=" << val << ",";
}
auto N=static_cast<int>(input->readLong(2)); // checkme: the number of graphics ?
if (N) f << "N=" << N << ",";
for (long i=0; i<2; ++i) { // always 0,1
val=input->readLong(2);
if (val!=i) f << "f" << i+7 << "=" << val << ",";
}
f << "ID1=[";
for (int i=0; i<2; ++i) { // two big number
f << std::hex << input->readULong(4) << std::dec << ",";
}
f << "],";
val=input->readLong(2); // always 0x100
if (val!=0x100) f << "f9=" << val << ",";
val=input->readLong(2); // always 0
if (val) f << "f10=" << val << ",";
f << "ID2=" << std::hex << input->readULong(4) << std::dec << ","; // another big number
for (int i=0; i<56; ++i) { // always 0
val=input->readLong(2);
if (val) f << "g" << i << "=" << val << ",";
}
ascii().addPos(8);
ascii().addNote(f.str().c_str());
long pos=input->tell();
f.str("");
f << "LibHeader-A:";
for (int i=0; i<2; ++i) { // f1=54,5c|5d
val=input->readLong(2);
if (val) f << "f" << i << "=" << val << ",";
}
f << "IDs=[";
for (int i=0; i<9; ++i) { // 7 or 9 big number
val=long(input->readULong(4));
if (val)
f << std::hex << val << std::dec << ",";
else
f << "_,";
}
f << "],";
for (int i=0; i<6; ++i) { // always 0
val=input->readLong(2);
if (val) f << "f" << i+2 << "=" << val << ",";
}
for (int i=0; i<2; ++i) {
f << "unkn" << i << "=[";
for (int j=0; j<2; ++j) { // _, small number
val=input->readLong(2);
if (val)
f << val << ",";
else
f << "_,";
}
f << std::hex << input->readULong(4) << std::dec << ","; // big number or 0
f << "],";
}
for (int i=0; i<26; ++i) { // always 0
val=input->readLong(2);
if (val) f << "g" << i << "=" << val << ",";
}
ascii().addPos(pos);
ascii().addNote(f.str().c_str());
pos=input->tell();
f.str("");
f << "LibHeader-B:";
auto fSz=static_cast<int>(input->readULong(1));
if (fSz>63) {
MWAW_DEBUG_MSG(("ClarisDrawParser::readLibraryHeader: string size seems bad\n"));
f << "##fSz=" << fSz << ",";
fSz=0;
}
std::string text("");
for (int i=0; i<fSz; ++i) text+=char(input->readULong(1));
f << "filename=" << text << ",";
input->seek(pos+64, librevenge::RVNG_SEEK_SET);
for (int i=0; i<96; ++i) { // always 0
val=input->readLong(2);
if (val) f << "f" << i << "=" << val << ",";
}
val=static_cast<int>(input->readULong(1)); // always filename size ?
if (val!=fSz) f << "#fSz1=" << fSz << ",";
val=static_cast<int>(input->readULong(1)); // always 0?
if (val) f << "f96=" << val << ",";
f << "ID=" << std::hex << input->readULong(4) << std::dec << ","; // big number
val=static_cast<int>(input->readLong(2)); // 0 | 0fcc
if (val) f << "g0=" << val << ",";
val=static_cast<int>(input->readULong(2)); // 80[89]3
if (val) f << "fl=" << std::hex << val << std::dec << ",";
val=static_cast<int>(input->readLong(2)); // 0
if (val) f << "g1=" << val << ",";
val=static_cast<int>(input->readULong(1)); // always filename size ?
if (val!=fSz) f << "#fSz2=" << fSz << ",";
val=static_cast<int>(input->readULong(1)); // always 0?
if (val) f << "g2=" << val << ",";
ascii().addPos(pos);
ascii().addNote(f.str().c_str());
pos=input->tell();
f.str("");
f << "LibHeader-C:";
fSz=static_cast<int>(input->readULong(1));
if (fSz>63) {
MWAW_DEBUG_MSG(("ClarisDrawParser::readLibraryHeader: string size seems bad\n"));
f << "##fSz=" << fSz << ",";
fSz=0;
}
text="";
for (int i=0; i<fSz; ++i) text+=char(input->readULong(1));
f << "author?=" << text << ",";
input->seek(pos+64, librevenge::RVNG_SEEK_SET);
for (int i=0; i<96; ++i) { // always 0
val=input->readLong(2);
if (val) f << "f" << i << "=" << val << ",";
}
ascii().addPos(pos);
ascii().addNote(f.str().c_str());
pos=input->tell();
f.str("");
f << "LibHeader-D:";
for (int i=0; i<16; ++i) {
val=static_cast<int>(input->readLong(2));
static int const expected[]= {4,2,0/*35 or 3f*/,48, 9, 0/*78 or 8x*/, 0x42, 18,
3, 0xd4, 0/*7b or 8e*/, 0x57, 3, 0xc4, 0/*7b or 8f*/, 0
};
if (val!=expected[i])
f << "f" << i << "=" << val << ",";
}
int dim[2];
for (auto &i : dim) i=static_cast<int>(input->readLong(2));
f << "dim=" << MWAWVec2i(dim[0],dim[1]) << ","; // 64x64 or 72x72
m_state->m_numDSET=static_cast<int>(input->readLong(2));
if (m_state->m_numDSET) f << "num[DSET]=" << m_state->m_numDSET << ",";
ascii().addPos(pos);
ascii().addNote(f.str().c_str());
input->seek(846, librevenge::RVNG_SEEK_SET);
// the style are coded after the DSET zones, let try to find them
input->seek(-44, librevenge::RVNG_SEEK_END);
while (input->tell()>=846) {
pos=input->tell();
auto c=static_cast<int>(input->readULong(1));
bool find=false;
switch (c) {
case 0x44:
input->seek(pos, librevenge::RVNG_SEEK_SET);
if (readDSET(pos==846))
find=true;
else
input->seek(pos-4, librevenge::RVNG_SEEK_SET);
break;
case 0x53:
input->seek(pos-1, librevenge::RVNG_SEEK_SET);
break;
case 0x45:
input->seek(pos-2, librevenge::RVNG_SEEK_SET);
break;
case 0x54:
input->seek(pos-3, librevenge::RVNG_SEEK_SET);
break;
default:
input->seek(pos-4, librevenge::RVNG_SEEK_SET);
break;
}
if (!find)
continue;
m_state->m_EOF=input->tell();
// clean storage
m_graphParser->resetState();
m_textParser->resetState();
m_state->m_zonesMap.clear();
m_state->m_zoneIdToFileTypeMap.clear();
while (!input->isEnd()) {
pos=input->tell();
if (input->readULong(4)) {
input->seek(pos, librevenge::RVNG_SEEK_SET);
break;
}
ascii().addPos(pos);
ascii().addNote("_");
}
pos=input->tell();
bool ok=true;
if (!m_textParser->readParagraphs()) {
MWAW_DEBUG_MSG(("ClarisDrawParser::readLibraryHeader: can not read the paragraph style\n"));
ascii().addPos(pos);
ascii().addNote("Entries(RULR):###");
ok=false;
}
for (int i=0; ok && i<20; ++i) {
pos=input->tell();
auto dSz=long(input->readULong(4));
if (!dSz) {
ascii().addPos(pos);
ascii().addNote("_");
continue;
}
if (!input->checkPosition(pos+4+dSz)) {
MWAW_DEBUG_MSG(("ClarisDrawParser::readLibraryHeader: can not find style zone %d\n", i+1));
ascii().addPos(pos);
ascii().addNote("###");
break;
}
bool done=false;
input->seek(pos, librevenge::RVNG_SEEK_SET);
switch (i+1) {
case 1:
done=m_styleManager->readArrows();
break;
case 2:
done=m_styleManager->readDashs();
break;
case 3:
done=m_styleManager->readPatternList();
break;
case 4:
done=m_styleManager->readGradientList();
break;
case 5:
done = m_graphParser->readTransformations();
break;
case 6:
done = m_styleManager->readRulers();
break;
case 7: // two zones: pos and names
done = readLibraryNames();
break;
case 8:
done = m_styleManager->readColorList();
break;
case 9: // maybe zone 24
done = ClarisWksStruct::readStructZone(*getParserState(), "Style10A", false);
break;
case 10: // maybe zone 25
done = ClarisWksStruct::readStructZone(*getParserState(), "Style11A", false);
break;
case 11: // maybe readfontnames without header
done = ClarisWksStruct::readStructZone(*getParserState(), "Style12A", false);
break;
default:
break;
}
if (done) continue;
f.str("");
f << "Entries(Style" << i+1 << "A):";
ascii().addPos(pos);
ascii().addNote(f.str().c_str());
input->seek(pos+4+dSz, librevenge::RVNG_SEEK_SET);
}
break;
}
input->seek(846, librevenge::RVNG_SEEK_SET);
if (!readDSET(true)) {
MWAW_DEBUG_MSG(("ClarisDrawParser::readLibraryHeader:can not read main group\n"));
input->seek(846, librevenge::RVNG_SEEK_SET);
}
return true;
}
////////////////////////////////////////////////////////////
// read the header
////////////////////////////////////////////////////////////
bool ClarisDrawParser::checkHeader(MWAWHeader *header, bool /*strict*/)
{
*m_state = ClarisDrawParserInternal::State();
MWAWInputStreamPtr input = getInput();
if (!input || !input->hasDataFork() || !input->checkPosition(846))
return false;
libmwaw::DebugStream f;
f << "FileHeader:";
input->seek(0, librevenge::RVNG_SEEK_SET);
auto val=static_cast<int>(input->readULong(1));
if (val==0x2) {
m_state->m_isLibrary=true;
f << "lib,";
}
else if (val==0x1) {
if (!input->checkPosition(0x80A))
return false;
}
else
return false;
val=static_cast<int>(input->readULong(2)); // a3-b1
if (val) f << "f0=" << std::hex << val << std::dec << ",";
if (input->readULong(1) || input->readULong(4) != 0x45585057) return false;
int vers=1;
setVersion(vers);
m_state->m_version=vers;
if (header)
header->reset(MWAWDocument::MWAW_T_CLARISDRAW, vers, MWAWDocument::MWAW_K_DRAW);
input->seek(8,librevenge::RVNG_SEEK_SET);
ascii().addPos(0);
ascii().addNote(f.str().c_str());
return true;
}
////////////////////////////////////////////////////////////
// read the layout
////////////////////////////////////////////////////////////
bool ClarisDrawParser::readLayouts()
{
MWAWInputStreamPtr input = getInput();
long pos=input->tell();
libmwaw::DebugFile &ascFile = ascii();
libmwaw::DebugStream f;
f << "Entries(Layout):";
ClarisWksStruct::Struct header;
if (!header.readHeader(input,true)) {
MWAW_DEBUG_MSG(("ClarisDrawParser::readLayouts: the data size seems bad\n"));
f << "###";
ascFile.addPos(pos);
ascFile.addNote(f.str().c_str());
return false;
}
if (header.m_size==0) {
ascFile.addPos(pos);
ascFile.addNote("_");
return true;
}
long endPos = pos+4+header.m_size;
f << header;
if (header.m_headerSize) {
ascFile.addDelimiter(input->tell(),'|');
input->seek(header.m_headerSize, librevenge::RVNG_SEEK_CUR);
}
ascFile.addPos(pos);
ascFile.addNote(f.str().c_str());
pos=input->tell();
if (header.m_dataSize!=336) {
input->seek(endPos, librevenge::RVNG_SEEK_SET);
MWAW_DEBUG_MSG(("ClarisDrawParser::readLayouts: no sure how to read the data\n"));
ascFile.addPos(pos);
ascFile.addNote("Layout:###");
return true;
}
for (long i=0; i<header.m_numData; ++i) {
pos=input->tell();
ClarisDrawParserInternal::Layer layer;
f.str("");
f << "Layout-A" << i << ":";
auto cSz=static_cast<int>(input->readULong(1));
librevenge::RVNGString name("");
for (int c=0; c<cSz; ++c) {
auto ch=char(input->readULong(1));
if (!ch) continue;
f << ch;
int unicode= getParserState()->m_fontConverter->unicode(3, static_cast<unsigned char>(ch));
if (unicode==-1)
name.append(ch);
else
libmwaw::appendUnicode(static_cast<uint32_t>(unicode), name);
}
f << ",";
layer.m_name=name;
ascFile.addPos(pos);
ascFile.addNote(f.str().c_str());
input->seek(pos+256, librevenge::RVNG_SEEK_SET);
pos=input->tell();
f.str("");
f << "Layout-B" << i << ":";
auto val=static_cast<int>(input->readULong(1)); // always 40|80
if (val&0x80) {
f << "hidden,";
layer.m_isHidden=true;
}
val &=0x7F;
if (val!=0x40) f << "fl0=" << std::hex << val << std::dec << ",";
val=static_cast<int>(input->readULong(1)); // 0|1|2|6c|d8|fc|ff
if (val) f << "fl1=" << std::hex << val << std::dec << ",";
for (int j=0; j<2; ++j) { // always 0
val=static_cast<int>(input->readULong(2));
if (val) f << "f" << j << "=" << val << ",";
}
layer.m_groupId=static_cast<int>(input->readULong(2));
f << "id[group]=" << layer.m_groupId << ",";
val=static_cast<int>(input->readLong(4));
if (val==-1)
f << "locked,";
else if (val)
f << "#lock=" << val << ",";
for (int j=0; j<16; ++j) { // always 0
val=static_cast<int>(input->readULong(4));
if (val) f << "g" << j << "=" << val << ",";
}
val=static_cast<int>(input->readULong(4));
if (val) f << "ID=" << std::hex << val << std::dec << ",";
ascFile.addPos(pos);
ascFile.addNote(f.str().c_str());
input->seek(pos+80, librevenge::RVNG_SEEK_SET);
m_state->m_layerList.push_back(layer);
}
return true;
}
bool ClarisDrawParser::readLibraryNames()
{
MWAWInputStreamPtr input = getInput();
long pos=input->tell();
if (!input->checkPosition(pos+8)) return false;
libmwaw::DebugFile &ascFile = ascii();
libmwaw::DebugStream f;
f << "Entries(LibraryName):";
ClarisWksStruct::Struct header;
if (!header.readHeader(input,true)) {
MWAW_DEBUG_MSG(("ClarisDrawParser::readLibraryNames: the data size seems bad\n"));
f << "###";
ascFile.addPos(pos);
ascFile.addNote(f.str().c_str());
return false;
}
if (header.m_size==0) {
ascFile.addPos(pos);
ascFile.addNote("_");
pos=input->tell();
auto sz = long(input->readULong(4));
if (!input->checkPosition(pos+4+sz)) {
MWAW_DEBUG_MSG(("ClarisDrawParser::readLibraryNames: the name size seems bad\n"));
f << "###";
ascFile.addPos(pos);
ascFile.addNote(f.str().c_str());
return false;
}
if (!sz) {
ascFile.addPos(pos);
ascFile.addNote("_");
return true;
}
MWAW_DEBUG_MSG(("ClarisDrawParser::readLibraryNames: find a string but no position\n"));
f << "###";
ascFile.addPos(pos);
ascFile.addNote(f.str().c_str());
input->seek(pos+4+sz, librevenge::RVNG_SEEK_SET);
return true;
}
long endPos=pos+4+header.m_size;
f << header;
if (header.m_headerSize) {
ascFile.addDelimiter(input->tell(),'|');
input->seek(header.m_headerSize, librevenge::RVNG_SEEK_CUR);
}
ascFile.addPos(pos);
ascFile.addNote(f.str().c_str());
pos=input->tell();
if (header.m_dataSize!=4) {
input->seek(endPos, librevenge::RVNG_SEEK_SET);
MWAW_DEBUG_MSG(("ClarisDrawParser::readLibraryNames: no sure how to read the position\n"));
ascFile.addPos(pos);
ascFile.addNote("LibraryName:###");
return true;
}
pos=input->tell();
f.str("");
f << "LibraryName-pos:";
std::vector<int> positions, lengths;
for (long i=0; i<header.m_numData; ++i) {
auto sSz=static_cast<int>(input->readULong(2));
auto position=static_cast<int>(input->readULong(2));
f << position << ":" << sSz << ",";
positions.push_back(position);
lengths.push_back(sSz);
}
ascFile.addPos(pos);
ascFile.addNote(f.str().c_str());
pos=input->tell();
f.str("");
f << "LibraryName-name:";
auto sz = long(input->readULong(4));
if (sz==0 || !input->checkPosition(pos+4+sz)) {
MWAW_DEBUG_MSG(("ClarisDrawParser::readLibraryNames: can not find the name\n"));
f << "###";
ascFile.addPos(pos);
ascFile.addNote(f.str().c_str());
return false;
}
for (size_t i=0; i<positions.size(); ++i) {
ClarisDrawParserInternal::Layer layer;
if (positions[i]+lengths[i]>sz) {
MWAW_DEBUG_MSG(("ClarisDrawParser::readLibraryNames: the name %d seems bad\n", int(i)));
f << "###,";
m_state->m_layerList.push_back(layer);
continue;
}
input->seek(pos+4+positions[i], librevenge::RVNG_SEEK_SET);
librevenge::RVNGString name("");
for (int c=0; c<lengths[i]; ++c) {
auto ch=char(input->readULong(1));
if (!ch) continue;
f << ch;
int unicode= getParserState()->m_fontConverter->unicode(3, static_cast<unsigned char>(ch));
if (unicode==-1)
name.append(ch);
else
libmwaw::appendUnicode(static_cast<uint32_t>(unicode), name);
}
f << ",";
layer.m_name = name;
m_state->m_layerList.push_back(layer);
}
ascFile.addPos(pos);
ascFile.addNote(f.str().c_str());
input->seek(pos+4+sz, librevenge::RVNG_SEEK_SET);
return true;
}
////////////////////////////////////////////////////////////
// read the document information
////////////////////////////////////////////////////////////
bool ClarisDrawParser::readDocInfo()
{
MWAWInputStreamPtr input = getInput();
libmwaw::DebugStream f;
f << "Entries(DocInfo):";
long pos = input->tell();
long endPos=pos+428;
if (!input->checkPosition(endPos)) return false;
f << "ptr=" << std::hex << input->readULong(4) << std::dec << ",";
int val;
for (int i = 0; i < 6; i++) {
val = static_cast<int>(input->readULong(2));
if (val) f << "f" << i << "=" << std::hex << val << std::dec << ",";
}
m_state->m_headerId = static_cast<int>(input->readLong(2));
if (m_state->m_headerId) f << "headerId=" << m_state->m_headerId << ",";
val = static_cast<int>(input->readLong(2));
if (val) f << "unkn=" << val << ",";
m_state->m_footerId = static_cast<int>(input->readLong(2));
if (m_state->m_footerId) f << "footerId=" << m_state->m_footerId << ",";
for (int i=0; i < 4; ++i) {
val = static_cast<int>(input->readLong(2));
if (val) f << "g" << i << "=" << val << ",";
}
int pages[2];
for (auto &page : pages) page=static_cast<int>(input->readLong(2));
if (pages[1]>=1 && pages[1] < 1000 && pages[0]>=1 && pages[0]<100)
m_state->m_pages=MWAWVec2i(pages[0],pages[1]);
if (pages[0]!=1 || pages[1]!=1)
f << "pages[num]=" << pages[0] << "x" << pages[1] << ",";
ascii().addDelimiter(input->tell(), '|');
ascii().addPos(pos);
ascii().addNote(f.str().c_str());
ascii().addPos(pos+100);
ascii().addNote("DocInfo-2");
ascii().addPos(pos+200);
ascii().addNote("DocInfo-3");
ascii().addPos(pos+300);
ascii().addNote("DocInfo-4");
input->seek(endPos, librevenge::RVNG_SEEK_SET);
return true;
}
////////////////////////////////////////////////////////////
// try to read the print info zone
////////////////////////////////////////////////////////////
bool ClarisDrawParser::readPrintInfo()
{
MWAWInputStreamPtr input = getInput();
long pos=input->tell();
long endPos=pos+124;
if (input->readULong(4)!=120 || !input->checkPosition(endPos)) {
MWAW_DEBUG_MSG(("ClarisDrawParser::readPrintInfo: file seems too short\n"));
return false;
}
libmwaw::DebugStream f;
f << "Entries(PrintInfo):";
libmwaw::PrinterInfo info;
if (!info.read(input)) {
MWAW_DEBUG_MSG(("ClarisDrawParser::readPrintInfo: can not read print info\n"));
return false;
}
f << info;
MWAWVec2i paperSize = info.paper().size();
MWAWVec2i pageSize = info.page().size();
if (pageSize.x() <= 0 || pageSize.y() <= 0 ||
paperSize.x() <= 0 || paperSize.y() <= 0) {
ascii().addPos(pos);
ascii().addNote(f.str().c_str());
input->seek(endPos, librevenge::RVNG_SEEK_SET);
return true;
}
// define margin from print info
MWAWVec2i lTopMargin= -1 * info.paper().pos(0);
MWAWVec2i rBotMargin=info.paper().size() - info.page().size();
// move margin left | top
int decalX = lTopMargin.x() > 14 ? lTopMargin.x()-14 : 0;
int decalY = lTopMargin.y() > 14 ? lTopMargin.y()-14 : 0;
lTopMargin -= MWAWVec2i(decalX, decalY);
rBotMargin += MWAWVec2i(decalX, decalY);
// decrease right | bottom
int rightMarg = rBotMargin.x() -50;
if (rightMarg < 0) rightMarg=0;
int botMarg = rBotMargin.y() -50;
if (botMarg < 0) botMarg=0;
getPageSpan().setMarginTop(lTopMargin.y()/72.0);
getPageSpan().setMarginBottom(botMarg/72.0);
getPageSpan().setMarginLeft(lTopMargin.x()/72.0);
getPageSpan().setMarginRight(rightMarg/72.0);
getPageSpan().setFormLength(paperSize.y()/72.);
getPageSpan().setFormWidth(paperSize.x()/72.);
ascii().addPos(pos);
ascii().addNote(f.str().c_str());
input->seek(endPos, librevenge::RVNG_SEEK_SET);
return true;
}
////////////////////////////////////////////////////////////
// read the document main part
////////////////////////////////////////////////////////////
std::shared_ptr<ClarisWksStruct::DSET> ClarisDrawParser::readDSET(bool isLibHeader)
{
MWAWInputStreamPtr input = getInput();
long pos = input->tell();
libmwaw::DebugStream f;
libmwaw::DebugFile &ascFile=ascii();
if (input->readULong(4) != 0x44534554L)
return std::shared_ptr<ClarisWksStruct::DSET>();
auto sz = long(input->readULong(4));
MWAWEntry entry;
entry.setBegin(pos);
entry.setLength(sz+8);
long endPos = entry.end();
if (sz<16 || !input->checkPosition(entry.end())) {
MWAW_DEBUG_MSG(("ClarisDrawParser::readDSET: file is too short\n"));
return std::shared_ptr<ClarisWksStruct::DSET>();
}
ClarisWksStruct::DSET dset;
dset.m_size = sz;
dset.m_numData = static_cast<int>(input->readULong(2));
input->seek(10, librevenge::RVNG_SEEK_CUR);
dset.m_fileType = static_cast<int>(input->readULong(1));
input->seek(-11, librevenge::RVNG_SEEK_CUR);
int nFlags = 0;
switch (dset.m_fileType) {
case 1: // text
dset.m_beginSelection = static_cast<int>(input->readLong(4));
dset.m_endSelection = static_cast<int>(input->readLong(4));
dset.m_textType = static_cast<int>(input->readULong(1));
dset.m_flags[nFlags++] = static_cast<int>(input->readLong(1));
dset.m_headerSz = 44;
dset.m_dataSz = 28;
break;
default:
dset.m_flags[nFlags++] = static_cast<int>(input->readLong(2)); // normally -1
dset.m_flags[nFlags++] = static_cast<int>(input->readLong(2)); // the 0
dset.m_dataSz = static_cast<int>(input->readULong(2));
dset.m_headerSz = static_cast<int>(input->readULong(2));
dset.m_flags[nFlags++] = static_cast<int>(input->readLong(2));
break;
}
dset.m_flags[nFlags++] = static_cast<int>(input->readLong(2));
dset.m_id = static_cast<int>(input->readULong(2));
std::shared_ptr<ClarisWksStruct::DSET> zone;
switch (dset.m_fileType) {
case 0:
zone=m_graphParser->readGroupZone(dset, entry, isLibHeader);
break;
case 1:
zone=m_textParser->readDSETZone(dset, entry);
break;
case 4:
zone=m_graphParser->readBitmapZone(dset, entry);
break;
default:
break;
}
if (!zone) {
MWAW_DEBUG_MSG(("ClarisDrawParser::readDSET: find unexpected type\n"));
zone.reset(new ClarisWksStruct::DSET(dset));
f << "Entries(DSETU): " << *zone;
auto data0Length = static_cast<int>(zone->m_dataSz);
auto N = static_cast<int>(zone->m_numData);
ascFile.addDelimiter(input->tell(), '|');
ascFile.addPos(pos);
ascFile.addNote(f.str().c_str());
const long dataSz = sz-12-zone->m_headerSz;
if ((dataSz && (data0Length<=0 || (dataSz/data0Length)!=N || (dataSz%data0Length)!=0)) || (!dataSz && N)) {
MWAW_DEBUG_MSG(("ClarisDrawParser::readDSET: unexpected size for zone definition, try to continue\n"));
ascFile.addPos(pos);
ascFile.addNote("###");
input->seek(endPos, librevenge::RVNG_SEEK_SET);
return zone;
}
long debPos = endPos-N*data0Length;
for (int i = 0; i < zone->m_numData; i++) {
input->seek(debPos, librevenge::RVNG_SEEK_SET);
f.str("");
f << "DSETU-" << i << ":";
long actPos = input->tell();
if (actPos != debPos && actPos != debPos+data0Length)
ascFile.addDelimiter(input->tell(),'|');
ascFile.addPos(debPos);
ascFile.addNote(f.str().c_str());
debPos += data0Length;
}
input->seek(endPos, librevenge::RVNG_SEEK_SET);
}
if (!zone)
return zone;
if (m_state->m_zonesMap.find(zone->m_id) != m_state->m_zonesMap.end()) {
MWAW_DEBUG_MSG(("ClarisDrawParser::readDSET: zone %d already exists!!!!\n",
zone->m_id));
}
else {
m_state->m_zonesMap[zone->m_id] = zone;
m_state->m_zoneIdToFileTypeMap[zone->m_id] = dset.m_fileType;
}
return zone;
}
////////////////////////////////////////////////////////////
//
// send data
//
////////////////////////////////////////////////////////////
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: