/* -*- 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 <map>
#include <set>
#include <sstream>
#include <stack>
#include <librevenge/librevenge.h>
#include "MWAWFont.hxx"
#include "MWAWFontConverter.hxx"
#include "MWAWListener.hxx"
#include "MWAWParagraph.hxx"
#include "MWAWPosition.hxx"
#include "MWAWSubDocument.hxx"
#include "RagTime5ClusterManager.hxx"
#include "RagTime5Parser.hxx"
#include "RagTime5StructManager.hxx"
#include "RagTime5StyleManager.hxx"
#include "RagTime5Layout.hxx"
#include "libmwaw_internal.hxx"
/** Internal: the structures of a RagTime5Layout */
namespace RagTime5LayoutInternal
{
//! the layout cluster ( 4001 zone)
struct ClusterLayout final : public RagTime5ClusterManager::Cluster {
//! constructor
ClusterLayout()
: Cluster(C_Layout)
, m_zoneList()
, m_pipelineLink()
, m_listItemLink()
, m_childIdSet()
, m_numChild(0)
, m_numMasterChild(0)
{
}
//! destructor
~ClusterLayout() final;
//! a zone of in a layout
struct Zone {
//! constructor
Zone()
: m_mainId(0)
, m_masterId(0)
, m_dimension()
{
}
//! the main zone id
int m_mainId;
//! the master zone id or 0
int m_masterId;
//! the dimension
MWAWVec2f m_dimension;
};
//! list of zone's
std::vector<Zone> m_zoneList;
//! link to a pipeline cluster list
RagTime5ClusterManager::Link m_pipelineLink;
//! link to a zone of fieldSize 8(unknown)
RagTime5ClusterManager::Link m_listItemLink;
//! list of child id
std::set<int> m_childIdSet;
//! the number of classic child
int m_numChild;
//! the number of master child
int m_numMasterChild;
};
ClusterLayout::~ClusterLayout()
{
}
////////////////////////////////////////
//! Internal: the state of a RagTime5Layout
struct State {
//! constructor
State()
: m_numPages(-1)
, m_idLayoutMap()
, m_masterIdSet()
, m_layoutIdToSendList()
{
}
//! the number of pages
int m_numPages;
//! map data id to text zone
std::map<int, std::shared_ptr<ClusterLayout> > m_idLayoutMap;
//! the list of master id
std::set<int> m_masterIdSet;
//! the list of layout to send
std::vector<int> m_layoutIdToSendList;
};
}
////////////////////////////////////////////////////////////
// constructor/destructor, ...
////////////////////////////////////////////////////////////
RagTime5Layout::RagTime5Layout(RagTime5Parser &parser)
: m_mainParser(parser)
, m_structManager(m_mainParser.getStructManager())
, m_parserState(parser.getParserState())
, m_state(new RagTime5LayoutInternal::State)
{
}
RagTime5Layout::~RagTime5Layout()
{
}
int RagTime5Layout::version() const
{
return m_parserState->m_version;
}
int RagTime5Layout::numPages() const
{
if (m_state->m_numPages<0)
const_cast<RagTime5Layout *>(this)->updateLayouts();
return m_state->m_numPages;
}
bool RagTime5Layout::sendPageContents()
{
int page=0;
for (size_t i=0; i<m_state->m_layoutIdToSendList.size(); ++i) {
int lId=m_state->m_layoutIdToSendList[i];
if (m_state->m_idLayoutMap.find(lId)==m_state->m_idLayoutMap.end() || !m_state->m_idLayoutMap.find(lId)->second) {
MWAW_DEBUG_MSG(("RagTime5Layout::sendPageContents: can not find layout %d\n", lId));
continue;
}
auto &layout=*m_state->m_idLayoutMap.find(lId)->second;
layout.m_isSent=true;
for (auto &zone : layout.m_zoneList) {
MWAWPosition position(MWAWVec2f(0,0), MWAWVec2f(100,100), librevenge::RVNG_POINT);
position.m_anchorTo=MWAWPosition::Page;
position.setPage(++page);
if (zone.m_masterId) {
if (m_state->m_idLayoutMap.find(zone.m_masterId)==m_state->m_idLayoutMap.end() || !m_state->m_idLayoutMap.find(zone.m_masterId)->second) {
MWAW_DEBUG_MSG(("RagTime5Layout::sendPageContents: can not find layout %d\n", zone.m_masterId));
}
else {
auto &master=*m_state->m_idLayoutMap.find(zone.m_masterId)->second;
int cId=0;
size_t n=layout.m_zoneList.size();
if (master.m_zoneList.size()==1)
cId=master.m_zoneList[0].m_mainId;
else if (n<master.m_zoneList.size())
cId=master.m_zoneList[n].m_mainId;
if (cId)
m_mainParser.send(cId, MWAWListenerPtr(), position);
}
}
if (zone.m_mainId)
m_mainParser.send(zone.m_mainId, MWAWListenerPtr(), position);
}
}
return true;
}
////////////////////////////////////////////////////////////
//
// Intermediate level
//
////////////////////////////////////////////////////////////
void RagTime5Layout::updateLayouts()
{
for (auto it : m_state->m_idLayoutMap) {
if (!it.second) continue;
updateLayout(*it.second);
}
// look for no master layout
int nPages=0;
std::multimap<int,int> numZonesToLayout;
for (auto it : m_state->m_idLayoutMap) {
if (!it.second || it.second->m_zoneList.empty() || m_state->m_masterIdSet.find(it.first)!=m_state->m_masterIdSet.end()) {
if (it.second)
it.second->m_isSent=true;
continue;
}
numZonesToLayout.insert(std::multimap<int,int>::value_type(it.second->m_numChild,it.first));
nPages+=static_cast<int>(it.second->m_zoneList.size());
}
m_state->m_numPages=nPages;
for (auto lIt=numZonesToLayout.end(); lIt!=numZonesToLayout.begin();)
m_state->m_layoutIdToSendList.push_back((--lIt)->second);
}
void RagTime5Layout::updateLayout(RagTime5LayoutInternal::ClusterLayout &layout)
{
int numChild=0, numMasterChild=0;
for (auto &zone : layout.m_zoneList) {
if (zone.m_mainId) {
if (m_mainParser.getClusterType(zone.m_mainId)==RagTime5ClusterManager::Cluster::C_GraphicZone)
++numChild;
else {
MWAW_DEBUG_MSG(("RagTime5Layout::updateLayout: find unexpected type for cluster %d\n", zone.m_mainId));
zone.m_mainId=0;
}
}
if (zone.m_masterId) {
if (m_mainParser.getClusterType(zone.m_masterId)==RagTime5ClusterManager::Cluster::C_Layout) {
m_state->m_masterIdSet.insert(zone.m_masterId);
++numMasterChild;
}
else {
MWAW_DEBUG_MSG(("RagTime5Layout::updateLayout: find unexpected type for cluster %d\n", zone.m_masterId));
zone.m_masterId=0;
}
}
}
layout.m_numChild=numChild;
layout.m_numMasterChild=numMasterChild;
}
////////////////////////////////////////////////////////////
//
// Low level
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// interface send function
////////////////////////////////////////////////////////////
void RagTime5Layout::flushExtra()
{
MWAW_DEBUG_MSG(("RagTime5Layout::flushExtra: not implemented\n"));
}
bool RagTime5Layout::send(RagTime5LayoutInternal::ClusterLayout &/*cluster*/, MWAWListenerPtr listener, int /*page*/)
{
if (!listener)
listener=m_parserState->getMainListener();
if (!listener) {
MWAW_DEBUG_MSG(("RagTime5Layout::send: can not find the listener\n"));
return false;
}
static bool first=true;
if (first) {
first=false;
MWAW_DEBUG_MSG(("RagTime5Layout::send: sorry not implemented\n"));
}
return true;
}
////////////////////////////////////////////////////////////
// cluster parser
////////////////////////////////////////////////////////////
namespace RagTime5LayoutInternal
{
//! Internal: the helper to read a clustList
struct ClustListParser final : public RagTime5StructManager::DataParser {
//! constructor
ClustListParser(RagTime5ClusterManager &clusterManager, int fieldSize, std::string const &zoneName)
: RagTime5StructManager::DataParser(zoneName)
, m_fieldSize(fieldSize)
, m_linkList()
, m_clusterManager(clusterManager)
{
if (m_fieldSize<4) {
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::ClustListParser: bad field size\n"));
m_fieldSize=0;
}
}
//! destructor
~ClustListParser() final;
//! returns the not null list dataId list
std::vector<int> getIdList() const
{
std::vector<int> res;
for (auto const &lnk : m_linkList) {
if (lnk.m_dataId>0)
res.push_back(lnk.m_dataId);
}
return res;
}
//! return the cluster name
std::string getClusterName(int id) const
{
return m_clusterManager.getClusterName(id);
}
//! try to parse a data
bool parseData(MWAWInputStreamPtr &input, long endPos, RagTime5Zone &/*zone*/, int /*n*/, libmwaw::DebugStream &f) final
{
long pos=input->tell();
if (endPos-pos!=m_fieldSize) {
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::ClustListParser::parse: bad data size\n"));
return false;
}
std::vector<int> listIds;
if (!RagTime5StructManager::readDataIdList(input, 1, listIds)) {
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::ClustListParser::parse: can not read an cluster id\n"));
f << "##clusterIds,";
return false;
}
RagTime5StructManager::ZoneLink link;
link.m_dataId=listIds[0];
if (listIds[0])
f << getClusterName(listIds[0]) << ",";
f << link;
m_linkList.push_back(link);
return true;
}
//! the field size
int m_fieldSize;
//! the list of read cluster
std::vector<RagTime5StructManager::ZoneLink> m_linkList;
private:
//! the main zone manager
RagTime5ClusterManager &m_clusterManager;
//! copy constructor, not implemented
ClustListParser(ClustListParser &orig) = delete;
//! copy operator, not implemented
ClustListParser &operator=(ClustListParser &orig) = delete;
};
ClustListParser::~ClustListParser()
{
}
//
//! low level: parser of layout cluster
//
struct LayoutCParser final : public RagTime5ClusterManager::ClusterParser {
//! constructor
LayoutCParser(RagTime5ClusterManager &parser, int zoneType)
: ClusterParser(parser, zoneType, "ClustLayout"), m_cluster(new ClusterLayout)
, m_actualZoneId(0)
, m_numZones(0)
, m_what(-1)
, m_linkId(-1)
, m_fieldName("")
, m_actualZone()
{
}
//! destructor
~LayoutCParser() final;
//! return the current cluster
std::shared_ptr<RagTime5ClusterManager::Cluster> getCluster() final
{
return m_cluster;
}
//! return the current layout cluster
std::shared_ptr<ClusterLayout> getLayoutCluster()
{
return m_cluster;
}
//! start a new zone
void startZone() final
{
if (m_what<=0)
++m_what;
else if (m_what==1) {
if (++m_actualZoneId>=m_numZones)
++m_what;
m_actualZone=ClusterLayout::Zone();
}
}
//! end of a start zone call
void endZone() final
{
if (m_what==1)
m_cluster->m_zoneList.push_back(m_actualZone);
if (m_link.empty())
return;
switch (m_linkId) {
case 0:
m_cluster->m_listItemLink=m_link;
break;
case 1:
m_cluster->m_pipelineLink=m_link;
break;
case 2:
m_cluster->m_settingLinks.push_back(m_link);
break;
case 3:
if (m_cluster->m_nameLink.empty())
m_cluster->m_nameLink=m_link;
else {
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::endZone: oops the name link is already set\n"));
m_cluster->m_linksList.push_back(m_link);
}
break;
default:
m_cluster->m_linksList.push_back(m_link);
break;
}
}
//! parse a zone
bool parseZone(MWAWInputStreamPtr &input, long fSz, int N, int flag, libmwaw::DebugStream &f) final
{
m_fieldName="";
m_linkId=-1;
if (m_what==0)
return parseHeaderZone(input,fSz,N,flag,f);
if (m_what==1)
return parseZoneBlock(input,fSz,N,flag,f);
m_what=2;
if (N<0) {
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseZone: N value seems bad\n"));
f << "###N=" << N << ",";
return true;
}
int val;
m_link.m_N=N;
switch (fSz) {
case 28:
case 29:
case 30:
case 32: {
std::string mess;
long linkValues[4];
if (!readLinkHeader(input, fSz, m_link, linkValues, mess)) {
f << "###fType=" << std::hex << m_link.m_fileType[0] << std::dec << ",";
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseZone: the field fSz28... type seems bad\n"));
return true;
}
f << m_link << "," << mess;
long expectedFileType1=0;
if (m_link.m_fileType[0]==0x35800) { // fSz=28
m_what=4;
m_fieldName="zone:longs";
}
else if (m_link.m_fileType[0]==0x3e800) { // fSz=28
m_what=4;
m_fieldName="list:longs0";
}
else if (m_link.m_fileType[0]==0x3c052) {
m_what=4;
m_fieldName="list:longs2";
expectedFileType1=0x50;
}
else if (m_link.m_fileType[0]==0x14b9800) { // fSz=30
m_linkId=0;
m_what=3;
m_fieldName="data0";
expectedFileType1=0x10;
}
else if (m_link.m_fileType[0]==0x47040) {
m_what=4;
m_linkId=2;
m_link.m_name=m_fieldName="settings";
}
else if (m_link.m_fileType[0]==0 && fSz==30) { // fSz=30
m_linkId=1;
m_fieldName="pipeline";
}
else if (m_link.m_fileType[0]==0 && fSz==32) {
expectedFileType1=0x200;
m_linkId=3;
m_what=4;
m_link.m_type=RagTime5ClusterManager::Link::L_UnicodeList;
m_fieldName="unicodeList";
}
else {
f << "###fType=" << std::hex << m_link.m_fileType[0] << std::dec << ",";
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseZone: the field fSz%d... type seems bad\n", int(fSz)));
return true;
}
if (expectedFileType1>=0 && (m_link.m_fileType[1]&0xFFD7)!=expectedFileType1) {
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseZone: fileType1 seems odd[fSz=28...]\n"));
f << "###fileType1=" << std::hex << m_link.m_fileType[1] << std::dec << ",";
}
break;
}
case 36: // follow when it exists the fSz=30 zone, no auxilliar data
m_fieldName="unicode[def]";
for (int i=0; i<2; ++i) { // always 0
val=static_cast<int>(input->readLong(2));
if (val) f << "f" << i << "=" << val << ",";
}
val=static_cast<int>(input->readULong(4));
if (val!=0x7d01a) {
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseZone: find unexpected filetype[fSz=36]\n"));
f << "###fileType=" << std::hex << val << std::dec << ",";
}
val=static_cast<int>(input->readLong(4)); // 0 or small number
if (val) f << "id0=" << val << ",";
for (int i=0; i<3; ++i) { // f4=10
val=static_cast<int>(input->readLong(2));
if (val) f << "f" << i+2 << "=" << val << ",";
}
f << "ids=[";
for (int i=0; i<3; ++i) { // an increasing sequence
val=static_cast<int>(input->readLong(4));
if (val)
f << val << ",";
else
f << "_,";
}
f << "],";
break;
case 38: // in 1 or 2 exemplar, no auxilliar data
m_fieldName="settings[Def]";
val=static_cast<int>(input->readULong(4));
if (val!=0x47040) {
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseZone: find unexpected type[fSz=38]\n"));
f << "##fileType=" << std::hex << val << std::dec << ",";
}
val=static_cast<int>(input->readULong(4)); // 0|1c07007|1492042
if (val) f << "fileType1=" << std::hex << val << std::dec << ",";
for (int i=0; i<5; ++i) { // f1=0|8, f4=10
val=static_cast<int>(input->readLong(2));
if (val) f << "f" << i << "=" << val << ",";
}
f << "ids=[";
for (int i=0; i<3; ++i) { // small increasing sequence
val=static_cast<int>(input->readLong(4));
if (val) f << val << ",";
else f << "_,";
}
f << "],";
val=static_cast<int>(input->readLong(2)); // always 0
if (val) f << "f5=" << val << ",";
break;
case 54: { // can be in multiple exemplar ~ 1 by zone, no auxilliar data
m_fieldName="data1";
for (int i=0; i<2; ++i) { // always 0
val=static_cast<int>(input->readLong(2));
if (val) f << "f" << i << "=" << val << ",";
}
float dim[2];
for (auto &d : dim) d=float(input->readLong(4))/65536.f;
f << "sz=" << MWAWVec2f(dim[0],dim[1]) << ",";
std::vector<int> listIds;
long actPos=input->tell();
if (!RagTime5StructManager::readDataIdList(input, 1, listIds)) {
f << "###cluster1,";
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseZone: can not read cluster block[fSz=54]\n"));
input->seek(actPos+4, librevenge::RVNG_SEEK_SET);
}
else if (listIds[0]) { // link to the new cluster e zone ? (can be also 0)
m_cluster->m_clusterIdsList.push_back(listIds[0]);
f << "cluster0=" << getClusterName(listIds[0]) << ",";
}
for (int i=0; i<7; ++i) { // always 0
val=static_cast<int>(input->readLong(2));
if (val) f << "f" << i+2 << "=" << val << ",";
}
for (int i=0; i<9; ++i) { // g0=1, g1=1-7, g2=0-d, g3=0-1, g8=2-8
val=static_cast<int>(input->readLong(2));
if (val) f << "g" << i << "=" << val << ",";
}
break;
}
case 60: // unsure
m_fieldName="data2";
m_what=5;
for (int i=0; i<4; ++i) { // f3=1
val=static_cast<int>(input->readLong(2));
if (val) f << "f" << i << "=" << val << ",";
}
val=static_cast<int>(input->readLong(4)); // 0 or 72cc
if (val) f << "f4=" << std::hex << val << std::dec << ",";
val=static_cast<int>(input->readULong(4));
if (val!=0x14b6842) {
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseZone: find unexpected filetype[fSz=60]\n"));
f << "#fileType1=" << std::hex << val << std::dec << ",";
}
for (int i=0; i<7; ++i) { // g4=g6=1
val=static_cast<int>(input->readLong(2));
if (val) f << "g" << i << "=" << val << ",";
}
val=static_cast<int>(input->readULong(4));
if (val!=0x35800) { // maybe a link here
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseZone: find unexpected filetype2[fSz=60]\n"));
f << "#fileType2=" << std::hex << val << std::dec << ",";
}
for (int i=0; i<4; ++i) { // 0
val=static_cast<int>(input->readLong(2));
if (val) f << "h" << i << "=" << val << ",";
}
val=static_cast<int>(input->readULong(4));
if (val!=0x14b4817) {
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseZone: find unexpected filetype3[fSz=60]\n"));
f << "#fileType3=" << std::hex << val << std::dec << ",";
}
for (int i=0; i<4; ++i) { // h4=47
val=static_cast<int>(input->readLong(2));
if (val) f << "h" << i+4 << "=" << val << ",";
}
break;
default:
f << "###fSz=" << fSz << ",";
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseZone: find unexpected file size\n"));
break;
}
if (!m_fieldName.empty())
f << m_fieldName << ",";
return true;
}
//! parse a field
bool parseField(RagTime5StructManager::Field const &field, int /*m*/, libmwaw::DebugStream &f) final
{
if (!m_fieldName.empty())
f << m_fieldName << ",";
switch (m_what) {
case 0: // main
if (field.m_type==RagTime5StructManager::Field::T_FieldList && field.m_fileType==0x14b5815) {
for (auto const &child : field.m_fieldList) {
if (child.m_type==RagTime5StructManager::Field::T_LongList && child.m_fileType==0xcf042) {
// TODO: storeme
f << "ids=[";
for (auto val : child.m_longList) {
if (val==0)
f << "_,";
else
f << val << ",";
}
continue;
}
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseField: find unexpected main field\n"));
f << "###[" << child << "],";
}
break;
}
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseField: find unexpected main field\n"));
f << "###" << field;
break;
case 3: // data0
if (field.m_type==RagTime5StructManager::Field::T_Unstructured && field.m_fileType==0xce017) {
// rare, always 2
f << "unkn="<< field.m_extra << ",";
break;
}
if (field.m_type==RagTime5StructManager::Field::T_Long && field.m_fileType==0xcf817) {
// a small value between 2a and 61
f << "f0="<<field.m_longValue[0] << ",";
break;
}
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseField: find unexpected data0 field\n"));
f << "###" << field;
break;
case 4: // list
if (field.m_type==RagTime5StructManager::Field::T_LongList && field.m_fileType==0xce842) {
f << "pos=[";
for (auto val : field.m_longList) {
if (val==0)
f << "_,";
else if (val>1000)
f << std::hex << val << std::dec << ",";
else
f << val << ",";
}
f << "],";
m_link.m_longList=field.m_longList;
break;
}
if (field.m_type==RagTime5StructManager::Field::T_LongList && field.m_fileType==0xcf042) { // with 3c052
f << "unkn=[";
for (auto val : field.m_longList) {
if (val==0)
f << "_,";
else
f << val << ",";
}
break;
}
if (field.m_type==RagTime5StructManager::Field::T_Unstructured && field.m_fileType==0xce017) {
// a small value 2|4|a|1c|40
f << "unkn="<<field.m_extra << ",";
break;
}
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseField: find unexpected list field\n"));
f << "###" << field;
break;
case 5: // fSz=60
if (field.m_type==RagTime5StructManager::Field::T_FieldList && field.m_fileType==0x14b4815) {
for (auto const &child : field.m_fieldList) {
if (child.m_type==RagTime5StructManager::Field::T_LongList && child.m_fileType==0xce842) {
f << "unkn=[";
for (auto val : child.m_longList) {
if (val==0)
f << "_,";
else
f << val << ",";
}
continue;
}
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseField: find unexpected data2 field\n"));
f << "###[" << child << "],";
}
break;
}
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseField: find unexpected data2 field\n"));
f << "###" << field;
break;
default:
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseField: find unexpected sub field\n"));
f << "###" << field;
break;
}
return true;
}
protected:
//! parse a zone block
bool parseZoneBlock(MWAWInputStreamPtr &input, long fSz, int N, int flag, libmwaw::DebugStream &f)
{
if (N<0 || m_what!=1 || (fSz!=50 && fSz!=66)) {
f << "###N=" << N << ",fSz=" << fSz << ",";
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseZoneBlock: find unexpected main field\n"));
return false;
}
f << "block, fl=" << std::hex << flag << std::dec << ",";
m_fieldName="block";
if (N!=1) {
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseZoneBlock: zone N seems badA\n"));
f << "#N=" << N << ",";
}
int val;
for (int i=0; i<2; ++i) { // always 0
val=static_cast<int>(input->readLong(2));
if (val)
f << "f" << i << "=" << val << ",";
}
float dim[2];
for (auto &d : dim) d=float(input->readLong(4))/65536.f;
m_actualZone.m_dimension=MWAWVec2f(dim[0],dim[1]);
f << "sz=" << MWAWVec2f(dim[0],dim[1]) << ",";
std::vector<int> listIds;
long actPos=input->tell();
if (!RagTime5StructManager::readDataIdList(input, 1, listIds)) {
f << "###cluster0,";
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseZoneBlock: can not read first cluster block\n"));
input->seek(actPos+4, librevenge::RVNG_SEEK_SET);
}
else if (listIds[0]) { // link to a cluster main zone
m_actualZone.m_mainId=listIds[0];
m_cluster->m_childIdSet.insert(listIds[0]);
f << "cluster0=" << getClusterName(listIds[0]) << ",";
}
for (int i=0; i<2; ++i) { // always 0: another item?
val=static_cast<int>(input->readLong(2));
if (val)
f << "f" << i+2 << "=" << val << ",";
}
listIds.clear();
actPos=input->tell();
if (!RagTime5StructManager::readDataIdList(input, 1, listIds)) {
f << "###cluster1,";
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseZoneBlock: can not read second cluster block\n"));
input->seek(actPos+4, librevenge::RVNG_SEEK_SET);
}
else if (listIds[0]) { // link to the master layout
m_actualZone.m_masterId=listIds[0];
m_cluster->m_childIdSet.insert(listIds[0]);
f << "cluster1=" << getClusterName(listIds[0]) << ",";
}
for (int i=0; i<2; ++i) { // either 0,0 or 1,small number (but does not seems a data id )
val=static_cast<int>(input->readLong(2));
if (val)
f << "f" << i+4 << "=" << val << ",";
}
val=static_cast<int>(input->readLong(4)); // alwas 1?
if (val!=1) f << "f6=" << val << ",";
f << "unkn=[";
for (int i=0; i<4; ++i) { // small number
val=static_cast<int>(input->readLong(2));
if (val)
f << val << ",";
else
f << "_,";
}
f << "],";
for (int i=0; i<2; ++i) { // g1=0|4|5
val=static_cast<int>(input->readLong(2));
if (val)
f << "g" << i << "=" << val << ",";
}
if (fSz==66) {
for (int i=0; i<2; ++i) { // g2=0|7|8, g3=5-12
val=static_cast<int>(input->readLong(4));
if (val)
f << "g" << i+2 << "=" << val << ",";
}
for (int i=0; i<2; ++i) { // fl0=0|1
val=static_cast<int>(input->readLong(1));
if (val)
f << "fl" << i << "=" << val << ",";
}
for (int i=0; i<3; ++i) { // g4=0|1, g6=g4
val=static_cast<int>(input->readLong(2));
if (val)
f << "g" << i+4 << "=" << val << ",";
}
}
return true;
}
//! parse the header zone
bool parseHeaderZone(MWAWInputStreamPtr &input, long fSz, int N, int flag, libmwaw::DebugStream &f)
{
f << "header, fl=" << std::hex << flag << std::dec << ",";
m_fieldName="header";
if (N!=-5 || m_what!=0 || (fSz!=123 && fSz!=127 && fSz!=128 && fSz!=132)) {
f << "###N=" << N << ",fSz=" << fSz << ",";
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseHeaderZone: find unexpected main field\n"));
return false;
}
int val;
for (int i=0; i<2; ++i) { // always 0?
val=static_cast<int>(input->readLong(2));
if (val) f << "f" << i+1 << "=" << val << ",";
}
val=static_cast<int>(input->readLong(2));
f << "id=" << val << ",";
val=static_cast<int>(input->readULong(2));
if (val!=m_type) {
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseHeaderZone: unexpected zone type\n"));
f << "##zoneType=" << std::hex << val << std::dec << ",";
}
for (int i=0; i<2; ++i) { // f0=0, f1=4-6
val=static_cast<int>(input->readLong(4));
if (val)
f << "f" << i << "=" << val << ",";
}
val=static_cast<int>(input->readLong(2)); // always 16
if (val!=16)
f << "f2=" << val << ",";
m_numZones=static_cast<int>(input->readLong(4));
if (m_numZones!=1)
f << "num[zone1]=" << m_numZones << ",";
auto fileType=long(input->readULong(4));
if (fileType!=0x14b6052) {
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseHeaderZone: find unexpected filetype\n"));
f << "#fileType0=" << std::hex << fileType << std::dec << ",";
}
for (int i=0; i<9; ++i) { // f11=0x60,
val=static_cast<int>(input->readLong(2));
if (val)
f << "f" << i+5 << "=" << val << ",";
}
val=static_cast<int>(input->readLong(1));
if (val!=1) f << "fl=" << val << ",";
if (fSz==128 || fSz==132) {
for (int i=0; i<5; ++i) { // unsure find only 0 here
val=static_cast<int>(input->readLong(1));
if (val)
f << "flA" << i << "=" << val << ",";
}
}
val=static_cast<int>(input->readLong(4));
if (val) // 0-20
f << "g0=" << val << ",";
long actPos=input->tell();
std::vector<int> listIds;
if (!RagTime5StructManager::readDataIdList(input, 1, listIds)) {
MWAW_DEBUG_MSG(("RagTime5LayoutInternal::LayoutCParser::parseHeaderZone: can not read first cluster block\n"));
f << "##badCluster,";
input->seek(actPos+4, librevenge::RVNG_SEEK_SET);
}
else if (listIds[0]) { // find link to a named frame cluster
m_cluster->m_clusterIdsList.push_back(listIds[0]);
f << "clusterId1=" << getClusterName(listIds[0]) << ",";
}
for (int i=0; i<2; ++i) { // always 0
val=static_cast<int>(input->readLong(2));
if (val)
f << "g" << i+1 << "=" << val << ",";
}
float dim[4];
for (auto &d : dim) d=float(input->readLong(4))/65536.f;
MWAWVec2f frameSize(dim[0],dim[1]);
f << "sz=" << frameSize << ",";
for (int i=0; i<2; ++i) dim[i]=float(input->readLong(4))/65536.f;
if (MWAWVec2f(dim[0],dim[1])!=frameSize)
f << "sz2=" << MWAWVec2f(dim[0],dim[1]) << ",";
for (int i=0; i<10; ++i) { // find g3=0|1|69, g8=0|5|8, g9=g11=g12=1, g10=small number(but not a data id)
val=static_cast<int>(input->readLong(2));
if (val)
f << "g" << i+3 << "=" << val << ",";
}
for (auto &d : dim) d=float(input->readLong(4))/65536.f;
f << "dim=" << MWAWBox2f(MWAWVec2f(dim[0],dim[1]), MWAWVec2f(dim[2],dim[3])) << ",";
for (int i=0; i<4; ++i) { // h3=0|1|3|6
val=static_cast<int>(input->readLong(2));
if (val)
f << "h" << i << "=" << val << ",";
}
if (fSz==127 || fSz==132) {
for (int i=0; i<2; ++i) { // always 0
val=static_cast<int>(input->readLong(2));
if (val)
f << "h" << i+3 << "=" << val << ",";
}
}
return true;
}
//! the current cluster
std::shared_ptr<ClusterLayout> m_cluster;
//! the actual zone id
int m_actualZoneId;
//! the number of zones
int m_numZones;
//! a index to know which field is parsed : 0: main, 1:list of zones, 2: unknown, 3:data0, 4:list, 5: unknown
int m_what;
//! the link id : 0: listItem, 1: pipeline, 2: settinglinks, 3: namelink,
int m_linkId;
//! the actual field name
std::string m_fieldName;
//! the actual zone
ClusterLayout::Zone m_actualZone;
};
LayoutCParser::~LayoutCParser()
{
}
}
std::shared_ptr<RagTime5ClusterManager::Cluster> RagTime5Layout::readLayoutCluster(RagTime5Zone &zone, int zoneType)
{
auto clusterManager=m_mainParser.getClusterManager();
if (!clusterManager) {
MWAW_DEBUG_MSG(("RagTime5Layout::readLayoutCluster: oops can not find the cluster manager\n"));
return std::shared_ptr<RagTime5ClusterManager::Cluster>();
}
RagTime5LayoutInternal::LayoutCParser parser(*clusterManager, zoneType);
if (!clusterManager->readCluster(zone, parser) || !parser.getLayoutCluster()) {
MWAW_DEBUG_MSG(("RagTime5Layout::readLayoutCluster: oops can not find the cluster\n"));
return std::shared_ptr<RagTime5ClusterManager::Cluster>();
}
auto cluster=parser.getLayoutCluster();
if (!cluster->m_listItemLink.empty())
m_mainParser.readFixedSizeZone(cluster->m_listItemLink, "LayoutUnknown0");
if (!cluster->m_pipelineLink.empty() && cluster->m_pipelineLink.m_ids.size()==1) {
if (cluster->m_pipelineLink.m_fieldSize==4) {
RagTime5LayoutInternal::ClustListParser listParser(*clusterManager, 4, "LayoutPipeline");
m_mainParser.readFixedSizeZone(cluster->m_pipelineLink, listParser);
m_mainParser.checkClusterList(listParser.getIdList());
}
else {
MWAW_DEBUG_MSG(("RagTime5Layout::readClusterLayoutData: find unexpected field size for pipeline data\n"));
m_mainParser.readFixedSizeZone(cluster->m_pipelineLink, "LayoutPipelineBAD");
}
}
// can have some setting
for (int wh=0; wh<2; ++wh) {
auto const &list=wh==0 ? cluster->m_conditionFormulaLinks : cluster->m_settingLinks;
for (auto const &lnk : list) {
if (lnk.empty()) continue;
RagTime5ClusterManager::Cluster unknCluster(RagTime5ClusterManager::Cluster::C_Unknown);
unknCluster.m_dataLink=lnk;
RagTime5StructManager::FieldParser defaultParser(wh==0 ? "CondFormula" : "Settings");
m_mainParser.readStructZone(unknCluster, defaultParser, 0);
}
}
if (!cluster->m_nameLink.empty()) {
std::map<int, librevenge::RVNGString> idToStringMap;
m_mainParser.readUnicodeStringList(cluster->m_nameLink, idToStringMap);
}
for (auto const &lnk : cluster->m_linksList) {
if (lnk.m_type==RagTime5ClusterManager::Link::L_List) {
m_mainParser.readListZone(lnk);
continue;
}
std::stringstream s;
s << "Layout_Data" << lnk.m_fieldSize;
RagTime5StructManager::DataParser defaultParser(s.str());
m_mainParser.readFixedSizeZone(lnk, defaultParser);
}
if (m_state->m_idLayoutMap.find(zone.m_ids[0])!=m_state->m_idLayoutMap.end()) {
MWAW_DEBUG_MSG(("RagTime5Layout::readLayoutCluster: cluster %d already exists\n", zone.m_ids[0]));
}
else
m_state->m_idLayoutMap[zone.m_ids[0]]=cluster;
return cluster;
}
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: