/* -*- 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 <string.h>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include <librevenge/librevenge.h>
#include "MWAWCell.hxx"
#include "MWAWTextListener.hxx"
#include "MWAWFont.hxx"
#include "MWAWFontConverter.hxx"
#include "MWAWHeader.hxx"
#include "MWAWList.hxx"
#include "MWAWParagraph.hxx"
#include "MWAWPosition.hxx"
#include "MWAWPictMac.hxx"
#include "MWAWPrinter.hxx"
#include "MWAWSection.hxx"
#include "MWAWSubDocument.hxx"
#include "MarinerWrtGraph.hxx"
#include "MarinerWrtText.hxx"
#include "MarinerWrtParser.hxx"
/** Internal: the structures of a MarinerWrtParser */
namespace MarinerWrtParserInternal
{
////////////////////////////////////////
//! Internal: the struct used to store the zone of a MarinerWrtParser
struct Zone {
//! a enum to define the diffent zone type
enum Type { Z_Main, Z_Footnote, Z_Header, Z_Footer, Z_Unknown };
//! constructor
Zone()
: m_id(-1)
, m_fileId(0)
, m_type(Z_Unknown)
, m_endNote(false)
, m_height(0)
, m_RBpos(0,0)
, m_dim()
, m_pageDim()
, m_pageTextDim()
, m_section()
, m_backgroundColor(MWAWColor::white())
, m_extra("")
{
}
//! operator<<
friend std::ostream &operator<<(std::ostream &o, Zone const &zone);
//! the zone id
int m_id;
//! the file zone id
uint32_t m_fileId;
//! the zone type
Type m_type;
//! a flag to know if this an endnote
bool m_endNote;
//! height of the zone
long m_height;
//! right/bottom position
MWAWVec2l m_RBpos;
//! the zone total position
MWAWBox2l m_dim;
//! the page dimension (?)
MWAWBox2i m_pageDim;
//! the zone of text dimension ( ie page less margins)
MWAWBox2i m_pageTextDim;
//! the section
MWAWSection m_section;
//! the background color
MWAWColor m_backgroundColor;
//! extra data
std::string m_extra;
};
std::ostream &operator<<(std::ostream &o, Zone const &zone)
{
switch (zone.m_type) {
case Zone::Z_Main:
o << "main,";
break;
case Zone::Z_Footnote:
if (zone.m_endNote)
o << "endnote,";
else
o << "footnote,";
break;
case Zone::Z_Header:
o << "header,";
break;
case Zone::Z_Footer:
o << "footer,";
break;
case Zone::Z_Unknown:
#if !defined(__clang__)
default:
#endif
break;
}
if (zone.m_type==Zone::Z_Header || zone.m_type==Zone::Z_Footer) {
switch (zone.m_fileId) {
case 0:
break; // main
case 1:
o << "left,";
break;
case 2:
o << "right,";
break;
case 3:
o << "firstpage,";
break;
default:
o << "#fileId" << zone.m_fileId << ",";
break;
}
}
else if (zone.m_fileId & 0xFFFFFF)
o << "fileId=" << std::hex << (zone.m_fileId&0xFFFFFF) << std::dec << ",";
if (zone.m_RBpos[0] || zone.m_RBpos[1])
o << "RBpos=" << zone.m_RBpos << ",";
if (zone.m_height)
o << "height=" << zone.m_height << ",";
if (zone.m_dim.size()[0] || zone.m_dim.size()[1])
o << "dim=" << zone.m_dim << ",";
if (!zone.m_backgroundColor.isWhite())
o << "background=" << zone.m_backgroundColor << ",";
o << zone.m_extra;
return o;
}
////////////////////////////////////////
//! Internal: the state of a MarinerWrtParser
struct State {
//! constructor
State()
: m_zonesList()
, m_fileToZoneMap()
, m_actPage(0)
, m_numPages(0)
, m_firstPageFooter(false)
, m_hasOddEvenHeaderFooter(false)
{
}
//! the list of zone
std::vector<Zone> m_zonesList;
//! a map fileZoneId -> localZoneId
std::map<uint32_t,int> m_fileToZoneMap;
int m_actPage /** the actual page */, m_numPages /** the number of page of the final document */;
/** a flag to know if we have a first page footer */
bool m_firstPageFooter;
/** a flag to know if we have odd/even header footer */
bool m_hasOddEvenHeaderFooter;
};
////////////////////////////////////////
//! Internal: the subdocument of a MarinerWrtParser
class SubDocument final : public MWAWSubDocument
{
public:
SubDocument(MarinerWrtParser &pars, MWAWInputStreamPtr const &input, int zoneId)
: MWAWSubDocument(&pars, input, MWAWEntry())
, m_id(zoneId)
{
}
//! destructor
~SubDocument() final {}
//! operator!=
bool operator!=(MWAWSubDocument const &doc) const final
{
if (MWAWSubDocument::operator!=(doc)) return true;
auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
if (!sDoc) return true;
if (m_id != sDoc->m_id) return true;
return false;
}
//! the parser function
void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
protected:
//! the subdocument id
int m_id;
};
void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/)
{
if (!listener.get()) {
MWAW_DEBUG_MSG(("MarinerWrtParserInternal::SubDocument::parse: no listener\n"));
return;
}
auto *parser=dynamic_cast<MarinerWrtParser *>(m_parser);
if (!parser) {
MWAW_DEBUG_MSG(("MarinerWrtParserInternal::SubDocument::parse: no parser\n"));
return;
}
long pos = m_input->tell();
parser->sendText(m_id);
m_input->seek(pos, librevenge::RVNG_SEEK_SET);
}
}
////////////////////////////////////////////////////////////
// constructor/destructor + basic interface ...
////////////////////////////////////////////////////////////
MarinerWrtParser::MarinerWrtParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header)
: MWAWTextParser(input, rsrcParser, header)
, m_state()
, m_pageMarginsSpanSet(false)
, m_graphParser()
, m_textParser()
{
init();
}
MarinerWrtParser::~MarinerWrtParser()
{
}
void MarinerWrtParser::init()
{
resetTextListener();
setAsciiName("main-1");
m_state.reset(new MarinerWrtParserInternal::State);
// reduce the margin (in case, the page is not defined)
getPageSpan().setMargins(0.1);
m_graphParser.reset(new MarinerWrtGraph(*this));
m_textParser.reset(new MarinerWrtText(*this));
}
////////////////////////////////////////////////////////////
// position and height
////////////////////////////////////////////////////////////
MWAWVec2f MarinerWrtParser::getPageLeftTop() const
{
return MWAWVec2f(float(getPageSpan().getMarginLeft()),
float(getPageSpan().getMarginTop()));
}
MWAWSection MarinerWrtParser::getSection(int zId) const
{
if (zId >= 0 && zId < int(m_state->m_zonesList.size()))
return m_state->m_zonesList[size_t(zId)].m_section;
return MWAWSection();
}
////////////////////////////////////////////////////////////
// new page
////////////////////////////////////////////////////////////
void MarinerWrtParser::newPage(int number)
{
if (number <= m_state->m_actPage || number > m_state->m_numPages)
return;
while (m_state->m_actPage < number) {
m_state->m_actPage++;
if (!getTextListener() || m_state->m_actPage == 1)
continue;
getTextListener()->insertBreak(MWAWTextListener::PageBreak);
}
}
////////////////////////////////////////////////////////////
// interface
////////////////////////////////////////////////////////////
int MarinerWrtParser::getZoneId(uint32_t fileId, bool &endNote)
{
if (m_state->m_fileToZoneMap.find(fileId)==m_state->m_fileToZoneMap.end()) {
MWAW_DEBUG_MSG(("MarinerWrtParser::getZoneId: can not find zone for %x\n", fileId));
return -1;
}
int id=m_state->m_fileToZoneMap.find(fileId)->second;
endNote=false;
if (id>=0 && id < int(m_state->m_zonesList.size()))
endNote = m_state->m_zonesList[size_t(id)].m_endNote;
return id;
}
void MarinerWrtParser::sendText(int zoneId)
{
MWAWInputStreamPtr input = getInput();
long actPos = input->tell();
m_textParser->send(zoneId);
input->seek(actPos, librevenge::RVNG_SEEK_SET);
}
float MarinerWrtParser::getPatternPercent(int id) const
{
return m_graphParser->getPatternPercent(id);
}
void MarinerWrtParser::sendToken(int zoneId, long tokenId)
{
MWAWInputStreamPtr input = getInput();
long actPos = input->tell();
m_graphParser->sendToken(zoneId, tokenId);
input->seek(actPos, librevenge::RVNG_SEEK_SET);
}
////////////////////////////////////////////////////////////
// the parser
////////////////////////////////////////////////////////////
void MarinerWrtParser::parse(librevenge::RVNGTextInterface *docInterface)
{
if (!getInput().get() || !checkHeader(nullptr)) throw(libmwaw::ParseException());
bool ok = true;
try {
// create the asciiFile
ascii().setStream(getInput());
ascii().open(asciiName());
checkHeader(nullptr);
ok = createZones();
if (ok) {
createDocument(docInterface);
m_graphParser->sendPageGraphics();
m_textParser->send(0);
#ifdef DEBUG
m_textParser->flushExtra();
m_graphParser->flushExtra();
#endif
}
ascii().reset();
}
catch (...) {
MWAW_DEBUG_MSG(("MarinerWrtParser::parse: exception catched when parsing\n"));
ok = false;
}
resetTextListener();
if (!ok) throw(libmwaw::ParseException());
}
////////////////////////////////////////////////////////////
// create the document
////////////////////////////////////////////////////////////
void MarinerWrtParser::createDocument(librevenge::RVNGTextInterface *documentInterface)
{
if (!documentInterface) return;
if (getTextListener()) {
MWAW_DEBUG_MSG(("MarinerWrtParser::createDocument: listener already exist\n"));
return;
}
// update the page
m_state->m_actPage = 0;
int numPage = m_textParser->numPages();
if (m_graphParser->numPages() > numPage)
numPage = m_graphParser->numPages();
m_state->m_numPages = numPage;
// create the page list
MWAWPageSpan ps(getPageSpan());
if (m_state->m_zonesList.size())
ps.setBackgroundColor(m_state->m_zonesList[0].m_backgroundColor);
// look for an header/footer
int headerId[4] = { -1, -1, -1, -1}, footerId[4] = { -1, -1, -1, -1};
for (size_t z = 0; z < m_state->m_zonesList.size(); z++) {
auto const &zone=m_state->m_zonesList[z];
if (zone.m_type==MarinerWrtParserInternal::Zone::Z_Header) {
if (zone.m_fileId < 4)
headerId[zone.m_fileId]=int(z);
}
else if (zone.m_type==MarinerWrtParserInternal::Zone::Z_Footer) {
if (zone.m_fileId < 4)
footerId[zone.m_fileId]=int(z);
}
}
MWAWPageSpan firstPs(ps);
if (m_state->m_firstPageFooter) {
if (headerId[3]>0) {
MWAWHeaderFooter header(MWAWHeaderFooter::HEADER, MWAWHeaderFooter::ALL);
header.m_subDocument.reset(new MarinerWrtParserInternal::SubDocument(*this, getInput(), int(headerId[3])));
firstPs.setHeaderFooter(header);
}
if (footerId[3]>0) {
MWAWHeaderFooter footer(MWAWHeaderFooter::FOOTER, MWAWHeaderFooter::ALL);
footer.m_subDocument.reset(new MarinerWrtParserInternal::SubDocument(*this, getInput(), int(footerId[3])));
firstPs.setHeaderFooter(footer);
}
}
for (int st = 0; st < 2; st++) {
MWAWHeaderFooter::Occurrence what=
!m_state->m_hasOddEvenHeaderFooter ? MWAWHeaderFooter::ALL : st==0 ? MWAWHeaderFooter::ODD : MWAWHeaderFooter::EVEN;
int which= !m_state->m_hasOddEvenHeaderFooter ? 0 : 1+st;
if (headerId[which]>0) {
MWAWHeaderFooter header(MWAWHeaderFooter::HEADER, what);
header.m_subDocument.reset(new MarinerWrtParserInternal::SubDocument(*this, getInput(), int(headerId[which])));
ps.setHeaderFooter(header);
}
if (footerId[which]>0) {
MWAWHeaderFooter footer(MWAWHeaderFooter::FOOTER, what);
footer.m_subDocument.reset(new MarinerWrtParserInternal::SubDocument(*this, getInput(), int(footerId[which])));
ps.setHeaderFooter(footer);
}
if (!m_state->m_hasOddEvenHeaderFooter)
break;
}
std::vector<MWAWPageSpan> pageList;
if (m_state->m_firstPageFooter) {
pageList.push_back(firstPs);
ps.setPageSpan(m_state->m_numPages);
}
else
ps.setPageSpan(m_state->m_numPages+1);
if (ps.getPageSpan())
pageList.push_back(ps);
//
MWAWTextListenerPtr listen(new MWAWTextListener(*getParserState(), pageList, documentInterface));
setTextListener(listen);
listen->startDocument();
}
////////////////////////////////////////////////////////////
//
// Intermediate level
//
////////////////////////////////////////////////////////////
// ------ read the different zones ---------
bool MarinerWrtParser::createZones()
{
MWAWInputStreamPtr input = getInput();
long pos = input->tell();
int actZone=-1;
while (readZone(actZone))
pos = input->tell();
ascii().addPos(pos);
ascii().addNote("Entries(Loose)");
return m_state->m_zonesList.size();
}
bool MarinerWrtParser::readZone(int &actZone, bool onlyTest)
{
MWAWInputStreamPtr input = getInput();
if (input->isEnd())
return false;
long pos = input->tell();
MarinerWrtEntry zone;
if (!readEntryHeader(zone)) {
input->seek(pos, librevenge::RVNG_SEEK_SET);
return false;
}
libmwaw::DebugStream f;
f << "Entries(" << zone.name() << "):" << zone;
bool done = false;
switch (zone.m_fileType) {
case -1: // separator
case -2: // last file
done = readSeparator(zone);
if (onlyTest)
break;
actZone++;
break;
case 0:
done = readZoneHeader(zone, actZone, onlyTest);
break;
case 1:
done = m_textParser->readTextStruct(zone, actZone);
break;
case 2:
done = m_textParser->readZone(zone, actZone);
break;
case 4:
case 5:
done = m_textParser->readPLCZone(zone, actZone);
break;
case 6:
done = m_textParser->readFonts(zone, actZone);
break;
case 7:
done = m_textParser->readRulers(zone, actZone);
break;
case 8:
done = m_textParser->readFontNames(zone, actZone);
break;
case 9: // zone size
done = readZoneDim(zone, actZone);
break;
case 0xa: // zone size with margins removal
done = readZoneDim(zone, actZone);
break;
case 0xb: // border dim?
done = readZoneb(zone, actZone);
break;
case 0xc:
done = readZonec(zone, actZone);
break;
case 0xf:
done = readDocInfo(zone, actZone);
break;
case 0x13:
done = readZone13(zone, actZone);
break;
case 0x14:
done = m_graphParser->readToken(zone, actZone);
break;
case 0x1a:
done = m_textParser->readStyleNames(zone, actZone);
break;
case 0x1f:
done = readPrintInfo(zone);
break;
case 0x24:
done = readCPRT(zone);
break;
/* 0x41a: docInfo */
case 0x420:
done = m_graphParser->readPostscript(zone, actZone);
break;
default:
break;
}
if (done) {
ascii().addPos(pos);
ascii().addNote(f.str().c_str());
input->seek(zone.end(), librevenge::RVNG_SEEK_SET);
return true;
}
if (onlyTest)
return false;
input->seek(zone.begin(), librevenge::RVNG_SEEK_SET);
input->pushLimit(zone.end());
std::vector<MarinerWrtStruct> dataList;
decodeZone(dataList);
input->popLimit();
size_t numData = dataList.size();
f << "numData=" << numData << ",";
ascii().addPos(pos);
ascii().addNote(f.str().c_str());
int numDataByField = zone.m_fileType==1 ? 22 : 10;
for (size_t d = 0; d < numData; d++) {
MarinerWrtStruct const &dt = dataList[d];
if ((int(d)%numDataByField)==0) {
if (d)
ascii().addNote(f.str().c_str());
f.str("");
f << zone.name() << "-" << d << ":";
ascii().addPos(dt.m_filePos);
}
f << dt << ",";
}
if (numData)
ascii().addNote(f.str().c_str());
if (input->tell() != zone.end()) {
f.str("");
if (input->tell() == zone.end()-1)
f << "_";
else
f << zone.name() << ":###";
ascii().addPos(input->tell());
ascii().addNote(f.str().c_str());
}
input->seek(zone.end(), librevenge::RVNG_SEEK_SET);
return true;
}
// --------- zone separator ----------
// read the zone separator
bool MarinerWrtParser::readSeparator(MarinerWrtEntry const &entry)
{
if (entry.length() < 0x3) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readSeparator: data seems to short\n"));
return false;
}
MWAWInputStreamPtr input = getInput();
input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
input->pushLimit(entry.end());
std::vector<MarinerWrtStruct> dataList;
decodeZone(dataList);
input->popLimit();
if (dataList.size() != 1) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readSeparator: can find my data\n"));
return false;
}
MarinerWrtStruct const &data = dataList[0]; // always 0x77aa
libmwaw::DebugStream f;
f << entry.name() << "[data]:";
if (data.m_data.size() != 1 || data.m_data[0] != 0x77aa)
f << "#" << data;
ascii().addPos(entry.begin());
ascii().addNote(f.str().c_str());
return true;
}
bool MarinerWrtParser::readZoneHeader(MarinerWrtEntry const &entry, int actId, bool onlyTest)
{
if (entry.length() < 3) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readZoneHeader: data seems to short\n"));
return false;
}
MWAWInputStreamPtr input = getInput();
input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
input->pushLimit(entry.end());
std::vector<MarinerWrtStruct> dataList;
decodeZone(dataList);
input->popLimit();
size_t numData = dataList.size();
if (numData < 47) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readZoneHeader: find unexpected number of data\n"));
return false;
}
if (onlyTest)
return true;
size_t d = 0;
long val;
libmwaw::DebugStream f;
MarinerWrtParserInternal::Zone zone;
for (int j = 0; j < 47; j++) {
MarinerWrtStruct const &data = dataList[d++];
if (!data.isBasic()) {
f << "###f" << j << "=" << data << ",";
continue;
}
long sel[4]= {0,0,0,0};
int dim[4]= {0,0,0,0};
unsigned char color[3];
switch (j) {
case 0: // version?
val = data.value(0);
if ((val>>16)==1) // checkme v1.6 -> 1[29] while v3.5->1[33]
setVersion((val&0xFFFF)<30 ? 1 : 2);
f << "vers?=" << (val>>16) << "[" << (val&0xFFFF) << "],";
break;
case 1:
val = data.value(0);
if (val>>16) // 0 or 1000
f << "f1[high]=" << std::hex << (val>>16) << std::dec << ",";
if ((val&0xFFFF)!=1)
f << "f1[low]=" << (val& 0xFFFF) << ",";
break;
case 2: { // find 8[01]0[0145]8120 or a0808120
uint32_t high = uint32_t(data.value(0))>>16;
// high&4: no odd/even header/footer ?
if (high) f << "fl2[high]=" << std::hex << high << std::dec << ",";
uint32_t low = uint32_t(data.value(0))&0xFFFF;
if (low) f << "fl2[low]=" << std::hex << low << std::dec << ",";
break;
}
case 3: { // 80000[01] or 800000[01]
auto value=uint32_t(data.value(0));
if (value&0x2000000) {
zone.m_endNote=true;
value &= ~uint32_t(0x2000000);
}
// value&1: firstPage[header/footer] ?
if (value)
f << "fl3=" << std::hex << value << std::dec << ",";
break;
}
case 4: {
auto v = uint32_t(data.value(0));
switch (v>>28) {
case 0: // main
zone.m_type = MarinerWrtParserInternal::Zone::Z_Main;
break;
case 0xc:
zone.m_type = MarinerWrtParserInternal::Zone::Z_Header;
break;
case 0xd:
zone.m_type = MarinerWrtParserInternal::Zone::Z_Footer;
break;
case 0xe:
zone.m_type = MarinerWrtParserInternal::Zone::Z_Footnote;
break;
default:
f << "#type=" << (v>>28) << ",";
break;
}
zone.m_fileId=(v&0xFFFFFFF);
m_state->m_fileToZoneMap[v]=actId;
break;
}
case 9: // real bottom margin
if (data.value(0))
f << "y[bottom+footer?]=" << data.value(0) << ",";
break;
case 10:
zone.m_height = data.value(0);
break;
case 13: // right margin
case 14: // bottom margin
zone.m_RBpos[j-13] = data.value(0);
break;
case 21:
if (data.value(0))
f << "h[act]=" << data.value(0) << ",";
break;
case 5: // 0|14|90
case 6: // 0|11-14
case 15: // -2: main?|-1
case 16: // -2: main?|-1
case 25: // 0|43
case 41: // 0|5|26
if (data.value(0))
f << "f" << j << "=" << data.value(0) << ",";
break;
case 7: // two units ?
if (data.value(0) != 0x480048)
f << "f" << j << "=" << std::hex << data.value(0) << std::dec << ",";
break;
case 8: // always -2?
if (data.value(0) != -2)
f << "#f" << j << "=" << data.value(0) << ",";
break;
case 12: // always 16
if (data.value(0) != 16)
f << "#f" << j << "=" << data.value(0) << ",";
break;
case 17:
case 18:
case 19:
case 20:
sel[j-17] = data.value(0);
while (j<20)
sel[++j-17] = dataList[d++].value(0);
if (sel[0]||sel[1])
f << "sel0=" << std::hex << sel[0] << "x" << sel[1] << std::dec << ",";
if (sel[2]||sel[3])
f << "sel1=" << std::hex << sel[2] << "x" << sel[3] << std::dec << ",";
break;
case 28: // left margin
case 29: // top margin
case 30:
case 31:
dim[j-28] = static_cast<int>(data.value(0));
while (j<31)
dim[++j-28] = static_cast<int>(dataList[d++].value(0));
zone.m_dim = MWAWBox2l(MWAWVec2l(dim[1],dim[0]), MWAWVec2l(dim[3],dim[2]));
break;
case 32:
case 33:
case 34: { // 35,36,37: front color?
color[0]=color[1]=color[2]=0xFF;
color[j-32]=static_cast<unsigned char>(data.value(0)>>8);
while (j < 34)
color[++j-32] = static_cast<unsigned char>(dataList[d++].value(0)>>8);
zone.m_backgroundColor = MWAWColor(color[0],color[1],color[2]);
break;
}
case 38:
if (data.value(0)!=1)
f << "#f" << j << "=" << data.value(0) << ",";
break;
case 39:
if (data.value(0) && data.value(0)!=0x4d4d4242) // MMBB: creator
f << "#creator=" << std::hex << uint32_t(data.value(0)) << std::dec << ",";
break;
case 40: // normally 0 or pretty small, but can also be very very big
if (data.value(0))
f << "f" << j << "=" << std::hex << data.value(0) << std::dec << ",";
break;
case 42:
if (data.value(0)!=43)
f << "#f" << j << "=" << data.value(0) << ",";
break;
case 44:
if (data.value(0))
f << "sel[pt]=" << std::hex << data.value(0) << std::dec << ",";
break;
case 45:
if (data.value(0)!=72)
f << "#f" << j << "=" << data.value(0) << ",";
break;
default:
if (data.value(0))
f << "#f" << j << "=" << data.value(0) << ",";
break;
}
}
while (d < numData) {
f << "#f" << d << "=" << dataList[d] << ",";
d++;
}
zone.m_extra = f.str();
if (actId < 0) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readZoneHeader: called with negative id\n"));
}
else {
if (actId >= int(m_state->m_zonesList.size()))
m_state->m_zonesList.resize(size_t(actId)+1);
m_state->m_zonesList[size_t(actId)] = zone;
}
f.str("");
f << entry.name() << ":" << zone;
ascii().addPos(entry.begin());
ascii().addNote(f.str().c_str());
return true;
}
bool MarinerWrtParser::readZoneDim(MarinerWrtEntry const &entry, int zoneId)
{
if (entry.length() < entry.m_N) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readZoneDim: data seems to short\n"));
return false;
}
MWAWInputStreamPtr input = getInput();
input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
input->pushLimit(entry.end());
std::vector<MarinerWrtStruct> dataList;
decodeZone(dataList, 1+4*entry.m_N);
input->popLimit();
if (int(dataList.size()) != 4*entry.m_N) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readZoneDim: find unexpected number of data\n"));
return false;
}
libmwaw::DebugStream f;
size_t d = 0;
std::vector<int> colPos;
for (int i = 0; i < entry.m_N; i++) {
f.str("");
f << entry.name() << "-" << i << ":";
ascii().addPos(dataList[d].m_filePos);
int dim[4] = { 0, 0, 0, 0 };
for (int j = 0; j < 4; j++) {
MarinerWrtStruct const &data = dataList[d++];
if (!data.isBasic()) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readZoneDim: find unexpected dim data type\n"));
f << "###dim" << j << "=" << data << ",";
}
else
dim[j] = static_cast<int>(data.value(0));
}
// checkme
MWAWBox2i dimension(MWAWVec2i(dim[1],dim[0]), MWAWVec2i(dim[3],dim[2]));
f << "pos=" << dimension << ",";
bool dimOk=dim[0] >= 0 && dim[0] < dim[2] && dim[1] >= 0 && dim[1] < dim[3];
if (i==0 && dimOk) {
if (zoneId < 0 || zoneId >= int(m_state->m_zonesList.size())) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readZoneDim: can not find the zone storage\n"));
}
else if (entry.m_fileType == 9)
m_state->m_zonesList[size_t(zoneId)].m_pageDim = dimension;
else if (entry.m_fileType == 0xa)
m_state->m_zonesList[size_t(zoneId)].m_pageTextDim = dimension;
else {
MWAW_DEBUG_MSG(("MarinerWrtParser::readZoneDim: unknown zone type\n"));
}
}
else if (i && dimOk) {
if (!colPos.size() || colPos.back() <= dim[1]) {
colPos.push_back(dim[1]);
colPos.push_back(dim[3]);
}
else
f << "###";
}
ascii().addNote(f.str().c_str());
}
if (entry.m_fileType == 0xa && zoneId >= 0 &&
zoneId < int(m_state->m_zonesList.size()) &&
colPos.size() > 2 && int(colPos.size())==2*(entry.m_N-1)) {
auto numCols=size_t(entry.m_N-1);
MWAWSection &sec=m_state->m_zonesList[size_t(zoneId)].m_section;
sec.m_columns.resize(numCols);
for (size_t c=0; c < numCols; c++) {
MWAWSection::Column &col = sec.m_columns[c];
int prevPos= c==0 ? colPos[0] : (colPos[2*c-1]+colPos[2*c])/2;
int nextPos= c+1==numCols ? colPos[2*c+1] :
(colPos[2*c+1]+colPos[2*c+2])/2;
col.m_width=double(nextPos-prevPos);
col.m_widthUnit=librevenge::RVNG_POINT;
col.m_margins[libmwaw::Left]=double(colPos[2*c]-prevPos)/72.;
col.m_margins[libmwaw::Right]=double(nextPos-colPos[2*c+1])/72.;
}
}
input->seek(entry.end(), librevenge::RVNG_SEEK_SET);
return true;
}
bool MarinerWrtParser::readDocInfo(MarinerWrtEntry const &entry, int zoneId)
{
if (entry.length() < 3) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readDocInfo: data seems to short\n"));
return false;
}
MWAWInputStreamPtr input = getInput();
input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
input->pushLimit(entry.end());
std::vector<MarinerWrtStruct> dataList;
decodeZone(dataList);
input->popLimit();
auto numDatas = int(dataList.size());
if (numDatas < 60) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readDocInfo: find unexpected number of data\n"));
return false;
}
libmwaw::DebugStream f;
f << entry.name() << ":";
int dim[2], margins[4]= {0,0,0,0};
unsigned char color[3];
size_t d=0;
for (int j=0; j < numDatas; j++, d++) {
MarinerWrtStruct const &dt = dataList[d];
if (!dt.isBasic()) {
f << "#f" << d << "=" << dt << ",";
static bool first=true;
if (first) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readDocInfo: find some struct block\n"));
first = false;
}
continue;
}
switch (j) {
case 0: { // 15|40
auto val=uint32_t(dt.value(0));
if (val&0x4000) {
if (zoneId==0)
m_state->m_hasOddEvenHeaderFooter=true;
f << "hasOddEven[header/footer],";
val &= ~uint32_t(0x4000);
}
if (val&0x20000) {
if (zoneId==0 && m_state->m_zonesList.size()) {
MWAWSection &sec=m_state->m_zonesList[0].m_section;
sec.m_columnSeparator = MWAWBorder();
}
f << "colSep,";
val &= ~uint32_t(0x20000);
}
if (val)
f << "f0=" << std::hex << val << std::dec << ",";
break;
}
case 2: // small number between 108 and 297
case 3: // f3=f2-24?
case 5: // small number between -18 and 57
case 6: // f6~=f5 ?
case 13: // a small number 1|2|3|4|58|61|283
case 35: // 1|2|31|60|283
case 44: // 0 or 1
case 46: // 0 or 1
case 47: // 0 or 1
case 48: // 0 or 1
case 51: // always 1
if (dt.value(0))
f << "f" << j << "=" << dt.value(0) << ",";
break;
case 1: // 1
if (dt.value(0)!=1)
f << "f" << j << "=" << dt.value(0) << ",";
break;
case 7:
case 8: // a dim?
dim[0] = dim[1] = 0;
dim[j-7]= static_cast<int>(dt.value(0));
if (j!=8)
dim[++j-7] = static_cast<int>(dataList[++d].value(0));
f << "dim?=" << dim[1] << "x" << dim[0] << ",";
break;
case 9:
case 10:
case 11:
case 12:
margins[j-9]=static_cast<int>(dt.value(0));
while (j<12)
margins[++j-9]= static_cast<int>(dataList[++d].value(0));
f << "margins=" << margins[1] << "x" << margins[0]
<< "<->" << margins[3] << "x" << margins[2] << ",";
break;
case 14: // a very big number
if (dt.value(0))
f << "id?=" << std::hex << dt.value(0) << std::dec << ",";
break;
case 15: { // border type?
long val = dt.value(0);
if (!val) break;
int depl = 24;
f << "border?=[";
for (int b = 0; b < 4; b++) {
if ((val>>depl)&0xFF)
f << ((val>>depl)&0xFF) << ",";
else
f << "_";
depl -= 8;
}
f << "],";
break;
}
case 16:
case 17:
case 18: {
color[0]=color[1]=color[2]=0;
color[j-16]=static_cast<unsigned char>(dt.value(0)>>8);
while (j < 18)
color[++j-16] = static_cast<unsigned char>(dataList[++d].value(0)>>8);
MWAWColor col(color[0],color[1],color[2]);
if (!col.isBlack()) f << "color=" << col << ",";
break;
}
case 76: // a very big number
case 79:
if (dt.value(0))
f << "f" << j << "=" << std::hex << uint32_t(dt.value(0)) << std::dec << ",";
break;
default:
if (dt.value(0))
f << "#f" << j << "=" << dt.value(0) << ",";
break;
}
}
if (zoneId==0 && margins[0] > 0 && margins[1] > 0 &&
margins[2] > 0 && margins[3] > 0) {
m_pageMarginsSpanSet= true;
getPageSpan().setMarginTop(double(margins[0])/72.0);
if (margins[2]>80)
getPageSpan().setMarginBottom(double(margins[2]-40)/72.0);
else
getPageSpan().setMarginBottom(double(margins[2]/2)/72.0);
getPageSpan().setMarginLeft(double(margins[1])/72.0);
getPageSpan().setMarginRight(double(margins[3])/72.0);
}
ascii().addPos(entry.begin());
ascii().addNote(f.str().c_str());
return true;
}
bool MarinerWrtParser::readZoneb(MarinerWrtEntry const &entry, int)
{
if (entry.length() < entry.m_N) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readZoneb: data seems to short\n"));
return false;
}
MWAWInputStreamPtr input = getInput();
input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
input->pushLimit(entry.end());
std::vector<MarinerWrtStruct> dataList;
decodeZone(dataList, 1+4*entry.m_N);
input->popLimit();
if (int(dataList.size()) != 4*entry.m_N) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readZoneb: find unexpected number of data\n"));
return false;
}
libmwaw::DebugStream f;
size_t d = 0;
for (int i = 0; i < entry.m_N; i++) {
f.str("");
f << entry.name() << "-" << i << ":";
ascii().addPos(dataList[d].m_filePos);
for (int j = 0; j < 4; j++) { // always 0, 0, 0, 0?
MarinerWrtStruct const &data = dataList[d++];
if (!data.isBasic()) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readZoneb: find unexpected dim data type\n"));
f << "###dim" << j << "=" << data << ",";
}
else if (data.value(0))
f << "f" << j << "=" << data.value(0) << ",";
}
ascii().addNote(f.str().c_str());
}
input->seek(entry.end(), librevenge::RVNG_SEEK_SET);
return true;
}
bool MarinerWrtParser::readZonec(MarinerWrtEntry const &entry, int zoneId)
{
if (entry.length() < entry.m_N) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readZonec: data seems to short\n"));
return false;
}
MWAWInputStreamPtr input = getInput();
input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
input->pushLimit(entry.end());
std::vector<MarinerWrtStruct> dataList;
decodeZone(dataList, 1+9*entry.m_N);
input->popLimit();
if (int(dataList.size()) != 9*entry.m_N) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readZonec: find unexpected number of data\n"));
return false;
}
libmwaw::DebugStream f;
size_t d = 0;
for (int i = 0; i < entry.m_N; i++) {
f.str("");
f << entry.name() << "-" << i << ":";
ascii().addPos(dataList[d].m_filePos);
for (int j = 0; j < 9; j++) {
MarinerWrtStruct const &data = dataList[d++];
if (!data.isBasic()) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readZonec: find unexpected dim data type\n"));
f << "###dim" << j << "=" << data << ",";
}
else if (j==8) {
if (!data.value(0)) {
f << "firstPage[header/footer],";
if (zoneId==0)
m_state->m_firstPageFooter=true;
}
else if (data.value(0)!=1)
f << "#f8=" << "=" << data.value(0) << ",";
}
else if (data.value(0))
f << "f" << j << "=" << data.value(0) << ",";
}
ascii().addNote(f.str().c_str());
}
input->seek(entry.end(), librevenge::RVNG_SEEK_SET);
return true;
}
bool MarinerWrtParser::readZone13(MarinerWrtEntry const &entry, int)
{
if (entry.length() < 3) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readZone13: data seems to short\n"));
return false;
}
MWAWInputStreamPtr input = getInput();
input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
input->pushLimit(entry.end());
std::vector<MarinerWrtStruct> dataList;
decodeZone(dataList, 1+23);
input->popLimit();
if (int(dataList.size()) != 23) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readZone13: find unexpected number of data\n"));
return false;
}
libmwaw::DebugStream f;
size_t d = 0;
f << entry.name() << ":";
ascii().addPos(dataList[d].m_filePos);
int val;
for (int j = 0; j < 23; j++) {
MarinerWrtStruct const &data = dataList[d++];
if ((j!=14 && !data.isBasic()) || (j==14 && data.m_type)) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readZone13: find unexpected struct data type\n"));
f << "#f" << j << "=" << data << ",";
continue;
}
if (j < 14) {
int const expectedValues[]= {13,10,9,31,8,12,14,28,29,30,31,0x7f,27,0};
if (static_cast<int>(data.value(0)) != expectedValues[j])
f << "f" << j << "=" << data.value(0) << ",";
continue;
}
if (j == 14) {
if (!data.m_pos.valid())
f << "#f" << j << "=" << data << ",";
else {
/* find v_{2i}=0 and v_{2i+1}=
{301,302,422,450,454,422,421,418,302,295,290,468,469,466,467,457,448}
*/
f << "bl=[";
input->seek(data.m_pos.begin(), librevenge::RVNG_SEEK_SET);
auto N = int(data.m_pos.length()/2);
for (int k = 0; k < N; k++) {
val = static_cast<int>(input->readLong(2));
if (val) f << val << ",";
else f << "_,";
}
f << "],";
}
continue;
}
unsigned char color[3];
MWAWColor col;
switch (j) {
case 15:
case 16:
case 17:
color[0]=color[1]=color[2]=0xFF;
color[j-15]=static_cast<unsigned char>(data.value(0)>>8);
while (j < 17)
color[++j-15] = static_cast<unsigned char>(dataList[d++].value(0)>>8);
col = MWAWColor(color[0],color[1],color[2]);
if (!col.isWhite())
f << "col0=" << col << ",";
break;
case 19:
case 20:
case 21:
color[0]=color[1]=color[2]=0xFF;
color[j-19]=static_cast<unsigned char>(data.value(0)>>8);
while (j < 21)
color[++j-19] = static_cast<unsigned char>(dataList[d++].value(0)>>8);
col = MWAWColor(color[0],color[1],color[2]);
if (!col.isWhite())
f << "col1=" << col << ",";
break;
default:
if (data.value(0))
f << "#f" << j << "=" << data.value(0) << ",";
}
}
ascii().addNote(f.str().c_str());
input->seek(entry.end(), librevenge::RVNG_SEEK_SET);
return true;
}
// --------- print info ----------
// read the print info xml data
bool MarinerWrtParser::readCPRT(MarinerWrtEntry const &entry)
{
if (entry.length() < 0x10) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readCPRT: data seems to short\n"));
return false;
}
MWAWInputStreamPtr input = getInput();
input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
#ifdef DEBUG_WITH_FILES
librevenge::RVNGBinaryData file;
input->readDataBlock(entry.length(), file);
static int volatile cprtName = 0;
libmwaw::DebugStream f;
f << "CPRT" << ++cprtName << ".plist";
libmwaw::Debug::dumpFile(file, f.str().c_str());
ascii().skipZone(entry.begin(),entry.end()-1);
#endif
input->seek(entry.end(), librevenge::RVNG_SEEK_SET);
return true;
}
// read the print info data
bool MarinerWrtParser::readPrintInfo(MarinerWrtEntry const &entry)
{
if (entry.length() < 0x77) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readPrintInfo: data seems to short\n"));
return false;
}
MWAWInputStreamPtr input = getInput();
input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
libmwaw::PrinterInfo info;
if (!info.read(input))
return false;
libmwaw::DebugStream f;
f << "PrintInfo:"<< info;
MWAWVec2i paperSize = info.paper().size();
MWAWVec2i pageSize = info.page().size();
if (pageSize.x() <= 0 || pageSize.y() <= 0 ||
paperSize.x() <= 0 || paperSize.y() <= 0) return false;
if (!m_pageMarginsSpanSet) {
// 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.);
getPageSpan().checkMargins();
ascii().addPos(entry.begin());
ascii().addNote(f.str().c_str());
input->seek(entry.end(), librevenge::RVNG_SEEK_SET);
return true;
}
////////////////////////////////////////////////////////////
// low level
////////////////////////////////////////////////////////////
// ---- field decoder ---------
bool MarinerWrtParser::readEntryHeader(MarinerWrtEntry &entry)
{
MWAWInputStreamPtr input = getInput();
long pos = input->tell();
std::vector<long> dataList;
if (!readNumbersString(4,dataList)||dataList.size()<5) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readEntryHeader: oops can not find header entry\n"));
input->seek(pos, librevenge::RVNG_SEEK_SET);
return false;
}
long length = dataList[1] >= 0 ? (dataList[1]<<16)+dataList[2] : -1;
if (length < 0 || !input->checkPosition(input->tell()+length)) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readEntryHeader: the header data seems to short\n"));
input->seek(pos, librevenge::RVNG_SEEK_SET);
return false;
}
entry.setBegin(input->tell());
entry.setLength(length);
entry.m_fileType = static_cast<int>(int16_t(dataList[0]));
entry.m_N = static_cast<int>(dataList[4]);
entry.m_value = static_cast<int>(dataList[3]);
return true;
}
bool MarinerWrtParser::readNumbersString(int num, std::vector<long> &res)
{
res.resize(0);
// first read the string
MWAWInputStreamPtr input = getInput();
std::string str("");
while (!input->isEnd()) {
auto ch = int(input->readULong(1));
if (ch=='-' || (ch >= 'A' && ch <= 'F') || (ch >= '0' && ch <= '9')) {
str += char(ch);
continue;
}
input->seek(-1, librevenge::RVNG_SEEK_CUR);
break;
}
if (!str.length()) return false;
// ok we have the string, let decodes it
size_t sz = str.length(), i = sz;
int nBytes = 0;
long val=0;
while (1) {
if (i==0) {
if (nBytes)
res.insert(res.begin(),val);
break;
}
char c = str[--i];
if (c=='-') {
if (!nBytes) {
MWAW_DEBUG_MSG(("MarinerWrtParser::readNumbersString find '-' with no val\n"));
break;
}
res.insert(res.begin(),-val);
val = 0;
nBytes = 0;
continue;
}
if (nBytes==num) {
res.insert(res.begin(),val);
val = 0;
nBytes = 0;
}
if (c >= '0' && c <= '9')
val += (long(c-'0')<<(4*nBytes));
else if (c >= 'A' && c <= 'F')
val += (long(c+10-'A')<<(4*nBytes));
else {
MWAW_DEBUG_MSG(("MarinerWrtParser::readNumbersString find odd char %x\n", static_cast<unsigned int>(c)));
break;
}
nBytes++;
}
return true;
}
bool MarinerWrtParser::decodeZone(std::vector<MarinerWrtStruct> &dataList, long numData)
{
dataList.clear();
MWAWInputStreamPtr input = getInput();
long pos = input->tell();
while (!input->isEnd()) {
size_t numVal = dataList.size();
if (numVal >= size_t(numData))
break;
MarinerWrtStruct data;
data.m_filePos = pos;
auto type = int(input->readULong(1));
data.m_type = (type&3);
if (type == 3)
return true;
if ((type & 0x3c) || (type && !(type&0x3)))
break;
if ((type>>4)==0xc) {
if (input->isEnd()) break;
auto num = int(input->readULong(1));
if (!num) break;
if (numVal==0) {
MWAW_DEBUG_MSG(("MarinerWrtParser::decodeZone: no previous data to copy\n"));
}
else // checkme
data = dataList[numVal-1];
for (int j = 0; j < num; j++)
dataList.push_back(data);
pos = input->tell();
continue;
}
if ((type>>4)==0x8) {
if (numVal==0) {
MWAW_DEBUG_MSG(("MarinerWrtParser::decodeZone: no previous data to copy(II)\n"));
dataList.push_back(data);
}
else
dataList.push_back(dataList[numVal-1]);
pos = input->tell();
continue;
}
std::vector<long> &numbers = data.m_data;
if (!readNumbersString(data.m_type==1 ? 4: 8, numbers))
break;
if (type==0) {
if (numbers.size() != 1 || numbers[0] < 0 || input->readULong(1) != 0x2c)
break;
data.m_pos.setBegin(input->tell());
data.m_pos.setLength(numbers[0]);
if (!input->checkPosition(data.m_pos.end()))
break;
input->seek(data.m_pos.end(), librevenge::RVNG_SEEK_SET);
numbers.resize(0);
}
dataList.push_back(data);
pos = input->tell();
}
input->seek(pos, librevenge::RVNG_SEEK_SET);
return dataList.size();
}
////////////////////////////////////////////////////////////
// read the header
////////////////////////////////////////////////////////////
bool MarinerWrtParser::checkHeader(MWAWHeader *header, bool strict)
{
*m_state = MarinerWrtParserInternal::State();
MWAWInputStreamPtr input = getInput();
if (!input || !input->hasDataFork())
return false;
long const headerSize=0x2e;
if (!input->checkPosition(headerSize)) {
MWAW_DEBUG_MSG(("MarinerWrtParser::checkHeader: file is too short\n"));
return false;
}
input->seek(0,librevenge::RVNG_SEEK_SET);
int actZone = -1;
if (!readZone(actZone, true))
return false;
if (strict && !readZone(actZone, true))
return false;
input->seek(0, librevenge::RVNG_SEEK_SET);
if (header)
header->reset(MWAWDocument::MWAW_T_MARINERWRITE, 1);
return true;
}
////////////////////////////////////////////////////////////
// MarinerWrtEntry/MarinerWrtStruct function
////////////////////////////////////////////////////////////
MarinerWrtEntry::~MarinerWrtEntry()
{
}
std::string MarinerWrtEntry::name() const
{
switch (m_fileType) {
case -1:
return "Separator";
case -2:
return "EndZone";
case 0:
return "ZoneHeader";
case 1:
return "TextStruct";
case 2:
return "TEXT";
case 4:
return "CharPLC";
case 5:
return "ParagPLC";
case 6:
return "Fonts";
case 7:
return "Paragraphs";
case 8:
return "FontNames";
case 9:
return "PaperSize";
case 0xa:
return "ColDim";
case 0xf:
return "DocInfo";
case 0x14: // token, picture, ...
return "Token";
case 0x1a:
return "StyleNames";
case 0x1f:
return "PrintInfo";
case 0x24:
return "CPRT";
case 0x41a:
return "DocInf2";
case 0x420:
return "PSFile";
default:
break;
}
std::stringstream s;
if (m_fileType >= 0)
s << "Zone" << std::hex << std::setfill('0') << std::setw(2) << m_fileType << std::dec;
else
s << "Zone-" << std::hex << std::setfill('0') << std::setw(2) << -m_fileType << std::dec;
return s.str();
}
long MarinerWrtStruct::value(int i) const
{
if (i < 0 || i >= int(m_data.size())) {
if (i) {
MWAW_DEBUG_MSG(("MarinerWrtStruct::value: can not find value %d\n", i));
}
return 0;
}
return m_data[size_t(i)];
}
std::ostream &operator<<(std::ostream &o, MarinerWrtStruct const &dt)
{
switch (dt.m_type) {
case 0: // data
o << "sz=" << std::hex << dt.m_pos.length() << std::dec;
return o;
case 3: // end of data
return o;
case 1: // int?
case 2: // long?
break;
default:
if (dt.m_type) o << ":" << dt.m_type;
break;
}
size_t numData = dt.m_data.size();
if (!numData) {
o << "_";
return o;
}
if (numData > 1) o << "[";
for (size_t d = 0; d < numData; d++) {
long val = dt.m_data[d];
if (val > -100 && val < 100)
o << val;
else if (val > 0)
o << "0x" << std::hex << val << std::dec;
else
o << "-0x" << std::hex << -val << std::dec;
if (d+1 != numData) o << ",";
}
if (numData > 1) o << "]";
return o;
}
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: