Blame src/lib/MultiplanParser.cxx

rpm-build 6f7582
/* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */
rpm-build 6f7582
rpm-build 6f7582
/* libmwaw
rpm-build 6f7582
* Version: MPL 2.0 / LGPLv2+
rpm-build 6f7582
*
rpm-build 6f7582
* The contents of this file are subject to the Mozilla Public License Version
rpm-build 6f7582
* 2.0 (the "License"); you may not use this file except in compliance with
rpm-build 6f7582
* the License or as specified alternatively below. You may obtain a copy of
rpm-build 6f7582
* the License at http://www.mozilla.org/MPL/
rpm-build 6f7582
*
rpm-build 6f7582
* Software distributed under the License is distributed on an "AS IS" basis,
rpm-build 6f7582
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
rpm-build 6f7582
* for the specific language governing rights and limitations under the
rpm-build 6f7582
* License.
rpm-build 6f7582
*
rpm-build 6f7582
* Major Contributor(s):
rpm-build 6f7582
* Copyright (C) 2002 William Lachance (wrlach@gmail.com)
rpm-build 6f7582
* Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net)
rpm-build 6f7582
* Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
rpm-build 6f7582
* Copyright (C) 2006, 2007 Andrew Ziem
rpm-build 6f7582
* Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr)
rpm-build 6f7582
*
rpm-build 6f7582
*
rpm-build 6f7582
* All Rights Reserved.
rpm-build 6f7582
*
rpm-build 6f7582
* For minor contributions see the git repository.
rpm-build 6f7582
*
rpm-build 6f7582
* Alternatively, the contents of this file may be used under the terms of
rpm-build 6f7582
* the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
rpm-build 6f7582
* in which case the provisions of the LGPLv2+ are applicable
rpm-build 6f7582
* instead of those above.
rpm-build 6f7582
*/
rpm-build 6f7582
rpm-build 6f7582
#include <cmath>
rpm-build 6f7582
#include <cstring>
rpm-build 6f7582
#include <iomanip>
rpm-build 6f7582
#include <iostream>
rpm-build 6f7582
#include <limits>
rpm-build 6f7582
#include <map>
rpm-build 6f7582
#include <set>
rpm-build 6f7582
#include <sstream>
rpm-build 6f7582
rpm-build 6f7582
#include <librevenge/librevenge.h>
rpm-build 6f7582
rpm-build 6f7582
#include "MWAWCell.hxx"
rpm-build 6f7582
#include "MWAWFont.hxx"
rpm-build 6f7582
#include "MWAWFontConverter.hxx"
rpm-build 6f7582
#include "MWAWHeader.hxx"
rpm-build 6f7582
#include "MWAWParagraph.hxx"
rpm-build 6f7582
#include "MWAWPosition.hxx"
rpm-build 6f7582
#include "MWAWSpreadsheetListener.hxx"
rpm-build 6f7582
#include "MWAWSubDocument.hxx"
rpm-build 6f7582
rpm-build 6f7582
#include "MultiplanParser.hxx"
rpm-build 6f7582
rpm-build 6f7582
/** Internal: the structures of a MultiplanParser */
rpm-build 6f7582
namespace MultiplanParserInternal
rpm-build 6f7582
{
rpm-build 6f7582
////////////////////////////////////////
rpm-build 6f7582
//! Internal: the state of a MultiplanParser
rpm-build 6f7582
struct State {
rpm-build 6f7582
  //! constructor
rpm-build 6f7582
  State()
rpm-build 6f7582
    : m_font()
rpm-build 6f7582
    , m_maximumCell()
rpm-build 6f7582
    , m_columnPositions()
rpm-build 6f7582
    , m_cellPositions()
rpm-build 6f7582
    , m_cellPositionsSet()
rpm-build 6f7582
    , m_posToLinkMap()
rpm-build 6f7582
    , m_posToNameMap()
rpm-build 6f7582
    , m_posToSharedDataSeen()
rpm-build 6f7582
  {
rpm-build 6f7582
  }
rpm-build 6f7582
  //! returns the column width in point
rpm-build 6f7582
  std::vector<float> getColumnsWidth() const;
rpm-build 6f7582
  //! the default font
rpm-build 6f7582
  MWAWFont m_font;
rpm-build 6f7582
  //! the maximumCell
rpm-build 6f7582
  MWAWVec2i m_maximumCell;
rpm-build 6f7582
  //! the columns begin position in point
rpm-build 6f7582
  std::vector<int> m_columnPositions;
rpm-build 6f7582
  //! the header/footer/printer message entries
rpm-build 6f7582
  MWAWEntry m_hfpEntries[3];
rpm-build 6f7582
  //! the positions of each cell: a vector for each row
rpm-build 6f7582
  std::vector<std::vector<int> > m_cellPositions;
rpm-build 6f7582
  //! the list of all position (use for checking)
rpm-build 6f7582
  std::set<int> m_cellPositionsSet;
rpm-build 6f7582
  //! the different main spreadsheet zones
rpm-build 6f7582
  MWAWEntry m_entries[9];
rpm-build 6f7582
  //! the list of link instruction
rpm-build 6f7582
  std::map<int, MWAWCellContent::FormulaInstruction> m_posToLinkMap;
rpm-build 6f7582
  //! the map name's pos to name's cell instruction
rpm-build 6f7582
  std::map<int, MWAWCellContent::FormulaInstruction> m_posToNameMap;
rpm-build 6f7582
  //! a set a shared data already seen
rpm-build 6f7582
  std::set<int> m_posToSharedDataSeen;
rpm-build 6f7582
};
rpm-build 6f7582
rpm-build 6f7582
std::vector<float> State::getColumnsWidth() const
rpm-build 6f7582
{
rpm-build 6f7582
  std::vector<float> res;
rpm-build 6f7582
  bool first=true;
rpm-build 6f7582
  int lastPos=0;
rpm-build 6f7582
  float const defWidth=64.f;
rpm-build 6f7582
  for (auto p : m_columnPositions) {
rpm-build 6f7582
    if (first) {
rpm-build 6f7582
      first=false;
rpm-build 6f7582
      continue;
rpm-build 6f7582
    }
rpm-build 6f7582
    if (p
rpm-build 6f7582
      res.push_back(defWidth);
rpm-build 6f7582
    else
rpm-build 6f7582
      res.push_back(float(p-lastPos));
rpm-build 6f7582
    lastPos=p;
rpm-build 6f7582
  }
rpm-build 6f7582
  if (res.size()<64) res.resize(64, defWidth);
rpm-build 6f7582
  return res;
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
////////////////////////////////////////
rpm-build 6f7582
//! Internal: the subdocument of a MultiplanParserInternal
rpm-build 6f7582
class SubDocument final : public MWAWSubDocument
rpm-build 6f7582
{
rpm-build 6f7582
public:
rpm-build 6f7582
  SubDocument(MultiplanParser &parser, MWAWInputStreamPtr const &input, MWAWEntry const &entry)
rpm-build 6f7582
    : MWAWSubDocument(&parser, input, entry)
rpm-build 6f7582
    , m_parser(parser)
rpm-build 6f7582
  {
rpm-build 6f7582
  }
rpm-build 6f7582
rpm-build 6f7582
  //! destructor
rpm-build 6f7582
  ~SubDocument() final {}
rpm-build 6f7582
rpm-build 6f7582
  //! operator!=
rpm-build 6f7582
  bool operator!=(MWAWSubDocument const &doc) const final;
rpm-build 6f7582
rpm-build 6f7582
  //! the parser function
rpm-build 6f7582
  void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;
rpm-build 6f7582
rpm-build 6f7582
protected:
rpm-build 6f7582
  /** the main parser */
rpm-build 6f7582
  MultiplanParser &m_parser;
rpm-build 6f7582
};
rpm-build 6f7582
rpm-build 6f7582
void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/)
rpm-build 6f7582
{
rpm-build 6f7582
  if (!listener.get()) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::SubDocument::parse: no listener\n"));
rpm-build 6f7582
    return;
rpm-build 6f7582
  }
rpm-build 6f7582
rpm-build 6f7582
  long pos = m_input->tell();
rpm-build 6f7582
  m_parser.sendText(m_zone);
rpm-build 6f7582
  m_input->seek(pos, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
bool SubDocument::operator!=(MWAWSubDocument const &doc) const
rpm-build 6f7582
{
rpm-build 6f7582
  if (MWAWSubDocument::operator!=(doc)) return true;
rpm-build 6f7582
  auto const *sDoc = dynamic_cast<SubDocument const *>(&doc;;
rpm-build 6f7582
  if (!sDoc) return true;
rpm-build 6f7582
  if (&m_parser != &sDoc->m_parser) return true;
rpm-build 6f7582
  return false;
rpm-build 6f7582
}
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
////////////////////////////////////////////////////////////
rpm-build 6f7582
// constructor/destructor, ...
rpm-build 6f7582
////////////////////////////////////////////////////////////
rpm-build 6f7582
MultiplanParser::MultiplanParser(MWAWInputStreamPtr const &input, MWAWRSRCParserPtr const &rsrcParser, MWAWHeader *header)
rpm-build 6f7582
  : MWAWSpreadsheetParser(input, rsrcParser, header)
rpm-build 6f7582
  , m_state(new MultiplanParserInternal::State)
rpm-build 6f7582
{
rpm-build 6f7582
  setAsciiName("main-1");
rpm-build 6f7582
  // reduce the margin (in case, the page is not defined)
rpm-build 6f7582
  getPageSpan().setMargins(0.1);
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
MultiplanParser::~MultiplanParser()
rpm-build 6f7582
{
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
////////////////////////////////////////////////////////////
rpm-build 6f7582
// the parser
rpm-build 6f7582
////////////////////////////////////////////////////////////
rpm-build 6f7582
void MultiplanParser::parse(librevenge::RVNGSpreadsheetInterface *docInterface)
rpm-build 6f7582
{
rpm-build 6f7582
  if (!getInput().get() || !checkHeader(nullptr))  throw(libmwaw::ParseException());
rpm-build 6f7582
  bool ok = true;
rpm-build 6f7582
  try {
rpm-build 6f7582
    // create the asciiFile
rpm-build 6f7582
    ascii().setStream(getInput());
rpm-build 6f7582
    ascii().open(asciiName());
rpm-build 6f7582
    checkHeader(nullptr);
rpm-build 6f7582
    ok = createZones();
rpm-build 6f7582
    if (ok) {
rpm-build 6f7582
      createDocument(docInterface);
rpm-build 6f7582
      sendSpreadsheet();
rpm-build 6f7582
    }
rpm-build 6f7582
  }
rpm-build 6f7582
  catch (...) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::parse: exception catched when parsing\n"));
rpm-build 6f7582
    ok = false;
rpm-build 6f7582
  }
rpm-build 6f7582
rpm-build 6f7582
  ascii().reset();
rpm-build 6f7582
  resetSpreadsheetListener();
rpm-build 6f7582
  if (!ok) throw(libmwaw::ParseException());
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
////////////////////////////////////////////////////////////
rpm-build 6f7582
// create the document
rpm-build 6f7582
////////////////////////////////////////////////////////////
rpm-build 6f7582
void MultiplanParser::createDocument(librevenge::RVNGSpreadsheetInterface *documentInterface)
rpm-build 6f7582
{
rpm-build 6f7582
  if (!documentInterface) return;
rpm-build 6f7582
  if (getSpreadsheetListener()) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::createDocument: listener already exist\n"));
rpm-build 6f7582
    return;
rpm-build 6f7582
  }
rpm-build 6f7582
rpm-build 6f7582
  // create the page list
rpm-build 6f7582
  MWAWPageSpan ps(getPageSpan());
rpm-build 6f7582
  ps.setPageSpan(1);
rpm-build 6f7582
  for (int i=0; i<2; ++i) {
rpm-build 6f7582
    if (!m_state->m_hfpEntries[i].valid()) continue;
rpm-build 6f7582
    MWAWHeaderFooter header(i==0 ? MWAWHeaderFooter::HEADER :  MWAWHeaderFooter::FOOTER, MWAWHeaderFooter::ALL);
rpm-build 6f7582
    header.m_subDocument.reset
rpm-build 6f7582
    (new MultiplanParserInternal::SubDocument
rpm-build 6f7582
     (*this, getInput(), m_state->m_hfpEntries[i]));
rpm-build 6f7582
    ps.setHeaderFooter(header);
rpm-build 6f7582
  }
rpm-build 6f7582
  std::vector<MWAWPageSpan> pageList(1,ps);
rpm-build 6f7582
  //
rpm-build 6f7582
  MWAWSpreadsheetListenerPtr listen(new MWAWSpreadsheetListener(*getParserState(), pageList, documentInterface));
rpm-build 6f7582
  setSpreadsheetListener(listen);
rpm-build 6f7582
  listen->startDocument();
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
rpm-build 6f7582
////////////////////////////////////////////////////////////
rpm-build 6f7582
//
rpm-build 6f7582
// Intermediate level
rpm-build 6f7582
//
rpm-build 6f7582
////////////////////////////////////////////////////////////
rpm-build 6f7582
bool MultiplanParser::createZones()
rpm-build 6f7582
{
rpm-build 6f7582
  if (!readPrinterMessage() || !readZoneB()) return false;
rpm-build 6f7582
  if (!readColumnsPos() || !readPrinterInfo()) return false;
rpm-build 6f7582
  if (!readHeaderFooter() || !readZoneC()) return false;
rpm-build 6f7582
  if (!readZonesList()) return false;
rpm-build 6f7582
  MWAWInputStreamPtr input = getInput();
rpm-build 6f7582
  if (!input->isEnd()) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::createZones: find extra data\n"));
rpm-build 6f7582
    ascii().addPos(input->tell());
rpm-build 6f7582
    ascii().addNote("Entries(Unknown):###extra");
rpm-build 6f7582
  }
rpm-build 6f7582
  return true;
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
////////////////////////////////////////////////////////////
rpm-build 6f7582
//
rpm-build 6f7582
// Low level
rpm-build 6f7582
//
rpm-build 6f7582
////////////////////////////////////////////////////////////
rpm-build 6f7582
rpm-build 6f7582
////////////////////////////////////////////////////////////
rpm-build 6f7582
// spreadsheet
rpm-build 6f7582
////////////////////////////////////////////////////////////
rpm-build 6f7582
bool MultiplanParser::readHeaderFooter()
rpm-build 6f7582
{
rpm-build 6f7582
  MWAWInputStreamPtr input = getInput();
rpm-build 6f7582
  long pos = input->tell();
rpm-build 6f7582
  if (!input->checkPosition(pos+2*256)) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readHeaderFooter: the zone seems too short\n"));
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  libmwaw::DebugStream f;
rpm-build 6f7582
  for (int i=0; i<2; ++i) {
rpm-build 6f7582
    pos = input->tell();
rpm-build 6f7582
    f.str("");
rpm-build 6f7582
    f << "Entries(HF)[" << (i==0 ? "header" : "footer") << "]:";
rpm-build 6f7582
    int sSz=int(input->readULong(1));
rpm-build 6f7582
    m_state->m_hfpEntries[i].setBegin(pos+1);
rpm-build 6f7582
    m_state->m_hfpEntries[i].setLength(sSz);
rpm-build 6f7582
    std::string name;
rpm-build 6f7582
    for (int c=0; c<sSz; ++c) name+=char(input->readULong(1));
rpm-build 6f7582
    f << name;
rpm-build 6f7582
    ascii().addPos(pos);
rpm-build 6f7582
    ascii().addNote(f.str().c_str());
rpm-build 6f7582
    input->seek(pos+256, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  }
rpm-build 6f7582
  return true;
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
bool MultiplanParser::readPrinterInfo()
rpm-build 6f7582
{
rpm-build 6f7582
  MWAWInputStreamPtr input = getInput();
rpm-build 6f7582
  long pos = input->tell();
rpm-build 6f7582
  if (!input->checkPosition(pos+0xbc)) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readPrinterInfo: the zone seems too short\n"));
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  libmwaw::DebugStream f;
rpm-build 6f7582
  f << "Entries(PrinterInfo):";
rpm-build 6f7582
  int val=int(input->readULong(2));
rpm-build 6f7582
  if (val!=0x7fff) f << "f0=" << val << ",";
rpm-build 6f7582
  val=int(input->readULong(2));
rpm-build 6f7582
  if (val) f << "f1=" << val << ",";
rpm-build 6f7582
  f << "left[margin]=" << input->readULong(1) << ",";
rpm-build 6f7582
  f << "width=" << input->readULong(1) << ",";
rpm-build 6f7582
  f << "right[margin]=" << input->readULong(1) << ",";
rpm-build 6f7582
  f << "length=" << input->readULong(1) << ",";
rpm-build 6f7582
  // then 0 and a string?
rpm-build 6f7582
  ascii().addDelimiter(input->tell(),'|');
rpm-build 6f7582
  ascii().addPos(pos);
rpm-build 6f7582
  ascii().addNote(f.str().c_str());
rpm-build 6f7582
  input->seek(pos+130, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
rpm-build 6f7582
  pos=input->tell();
rpm-build 6f7582
  f.str("");
rpm-build 6f7582
  f << "PrinterInfo[II]:";
rpm-build 6f7582
  f << "row[pbBreak]=[";
rpm-build 6f7582
  for (int i=0; i<32; ++i) {
rpm-build 6f7582
    val=int(input->readULong(1));
rpm-build 6f7582
    if (!val) continue;
rpm-build 6f7582
    for (int d=0, depl=1; d<8; ++d, depl<<=1) {
rpm-build 6f7582
      if (val&depl) f << i*8+d << ",";
rpm-build 6f7582
    }
rpm-build 6f7582
  }
rpm-build 6f7582
  f << "],";
rpm-build 6f7582
  f << "col[pbBreak]=[";
rpm-build 6f7582
  for (int i=0; i<8; ++i) {
rpm-build 6f7582
    val=int(input->readULong(1));
rpm-build 6f7582
    if (!val) continue;
rpm-build 6f7582
    for (int d=0, depl=1; d<8; ++d, depl<<=1) {
rpm-build 6f7582
      if (val&depl) f << i*8+d << ",";
rpm-build 6f7582
    }
rpm-build 6f7582
  }
rpm-build 6f7582
  f << "],";
rpm-build 6f7582
  for (int i=0; i<7; ++i) {
rpm-build 6f7582
    val=int(input->readULong(2));
rpm-build 6f7582
    int const expected[]= {0x48,0x48,0x36,0x36,1,1,0};
rpm-build 6f7582
    if (val==expected[i]) continue;
rpm-build 6f7582
    if (i==4) {
rpm-build 6f7582
      if (val==0)
rpm-build 6f7582
        f << "print[col,row,number]=no,";
rpm-build 6f7582
      else
rpm-build 6f7582
        f << "##print[col,row,number]=" << val << ",";
rpm-build 6f7582
    }
rpm-build 6f7582
    else
rpm-build 6f7582
      f << "g" << i << "=" << val << ",";
rpm-build 6f7582
  }
rpm-build 6f7582
  m_state->m_font.setId(int(input->readULong(2)));
rpm-build 6f7582
  m_state->m_font.setSize(float(input->readULong(2)));
rpm-build 6f7582
  f << "font=[" << m_state->m_font.getDebugString(getFontConverter()) << "],";
rpm-build 6f7582
  ascii().addPos(pos);
rpm-build 6f7582
  ascii().addNote(f.str().c_str());
rpm-build 6f7582
  input->seek(pos+58, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  return true;
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
bool MultiplanParser::readPrinterMessage()
rpm-build 6f7582
{
rpm-build 6f7582
  MWAWInputStreamPtr input = getInput();
rpm-build 6f7582
  long pos = input->tell();
rpm-build 6f7582
  if (!input->checkPosition(pos+256)) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readPrinterMessage: the zone seems too short\n"));
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  libmwaw::DebugStream f;
rpm-build 6f7582
  f << "Entries(HF)[printerMessage]:";
rpm-build 6f7582
  int sSz=int(input->readULong(1));
rpm-build 6f7582
  m_state->m_hfpEntries[2].setBegin(pos+1);
rpm-build 6f7582
  m_state->m_hfpEntries[2].setLength(sSz);
rpm-build 6f7582
  std::string name;
rpm-build 6f7582
  for (int c=0; c<sSz; ++c) name+=char(input->readULong(1));
rpm-build 6f7582
  f << name;
rpm-build 6f7582
  ascii().addPos(pos);
rpm-build 6f7582
  ascii().addNote(f.str().c_str());
rpm-build 6f7582
  input->seek(pos+256, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  return true;
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
bool MultiplanParser::readColumnsPos()
rpm-build 6f7582
{
rpm-build 6f7582
  MWAWInputStreamPtr input = getInput();
rpm-build 6f7582
  long pos = input->tell();
rpm-build 6f7582
  if (!input->checkPosition(pos+256)) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readColumnsPos: the zone seems too short\n"));
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  libmwaw::DebugStream f;
rpm-build 6f7582
  f << "Entries(ColPos):pos=[";
rpm-build 6f7582
  for (int i=0; i<64; ++i) {
rpm-build 6f7582
    m_state->m_columnPositions.push_back(int(input->readULong(2)));
rpm-build 6f7582
    f << m_state->m_columnPositions.back() << ",";
rpm-build 6f7582
  }
rpm-build 6f7582
  f << "],";
rpm-build 6f7582
  ascii().addPos(pos);
rpm-build 6f7582
  ascii().addNote(f.str().c_str());
rpm-build 6f7582
  return true;
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
bool MultiplanParser::readZonesList()
rpm-build 6f7582
{
rpm-build 6f7582
  MWAWInputStreamPtr input = getInput();
rpm-build 6f7582
  long pos = input->tell();
rpm-build 6f7582
  if (!input->checkPosition(pos+20)) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readZonesList: the zone seems too short\n"));
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  libmwaw::DebugStream f;
rpm-build 6f7582
  f << "Entries(ZonesList):";
rpm-build 6f7582
  int lastPos=0;
rpm-build 6f7582
  f << "zones=[";
rpm-build 6f7582
  for (int i=0, w=0; i<10; ++i) {
rpm-build 6f7582
    int newPos=int(input->readULong(2));
rpm-build 6f7582
    if (i==6) newPos+=lastPos; // length
rpm-build 6f7582
    if (i==7) {
rpm-build 6f7582
      lastPos=newPos;
rpm-build 6f7582
      continue;
rpm-build 6f7582
    }
rpm-build 6f7582
    if (newPos>lastPos) {
rpm-build 6f7582
      if (!input->checkPosition(pos+20+newPos)) {
rpm-build 6f7582
        MWAW_DEBUG_MSG(("MultiplanParser::readZonesList: find a bad position"));
rpm-build 6f7582
        f << "###";
rpm-build 6f7582
      }
rpm-build 6f7582
      else {
rpm-build 6f7582
        m_state->m_entries[w].setBegin(pos+20+lastPos);
rpm-build 6f7582
        m_state->m_entries[w].setEnd(pos+20+newPos);
rpm-build 6f7582
      }
rpm-build 6f7582
      f << std::hex << lastPos << "<->" << newPos << std::dec << ",";
rpm-build 6f7582
      lastPos=newPos;
rpm-build 6f7582
    }
rpm-build 6f7582
    else
rpm-build 6f7582
      f << "_,";
rpm-build 6f7582
    ++w;
rpm-build 6f7582
  }
rpm-build 6f7582
  f << "],";
rpm-build 6f7582
  ascii().addPos(pos);
rpm-build 6f7582
  ascii().addNote(f.str().c_str());
rpm-build 6f7582
  for (int i=0; i<9; ++i) {
rpm-build 6f7582
    if (!m_state->m_entries[i].valid()) continue;
rpm-build 6f7582
    bool ok=false;
rpm-build 6f7582
    std::string name;
rpm-build 6f7582
    switch (i) {
rpm-build 6f7582
    case 1:
rpm-build 6f7582
      ok=readZone1(m_state->m_entries[i]);
rpm-build 6f7582
      break;
rpm-build 6f7582
    case 3:
rpm-build 6f7582
      ok=readCellDataPosition(m_state->m_entries[i]);
rpm-build 6f7582
      break;
rpm-build 6f7582
    case 4:
rpm-build 6f7582
      name="Link";
rpm-build 6f7582
      break;
rpm-build 6f7582
    case 5:
rpm-build 6f7582
      name="Link";
rpm-build 6f7582
      break;
rpm-build 6f7582
    case 6:
rpm-build 6f7582
      name="DataCell";
rpm-build 6f7582
      break;
rpm-build 6f7582
    case 7: // the data are normally read in zone 6
rpm-build 6f7582
      name="SharedData";
rpm-build 6f7582
      break;
rpm-build 6f7582
    case 8:
rpm-build 6f7582
      name="Names";
rpm-build 6f7582
      break;
rpm-build 6f7582
    default:
rpm-build 6f7582
      ok=false;
rpm-build 6f7582
      break;
rpm-build 6f7582
    }
rpm-build 6f7582
    if (ok)
rpm-build 6f7582
      continue;
rpm-build 6f7582
    f.str("");
rpm-build 6f7582
    if (!name.empty())
rpm-build 6f7582
      f << "Entries(" << name << "):";
rpm-build 6f7582
    else
rpm-build 6f7582
      f << "Entries(Zone" << i << "):";
rpm-build 6f7582
    ascii().addPos(m_state->m_entries[i].begin());
rpm-build 6f7582
    ascii().addNote(f.str().c_str());
rpm-build 6f7582
    ascii().addPos(m_state->m_entries[i].end());
rpm-build 6f7582
    ascii().addNote("_");
rpm-build 6f7582
    input->seek(m_state->m_entries[i].end(), librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  }
rpm-build 6f7582
  return true;
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
bool MultiplanParser::readZone1(MWAWEntry const &entry)
rpm-build 6f7582
{
rpm-build 6f7582
  if (entry.length()%30) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readZone1: the zone size seems bad\n"));
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  MWAWInputStreamPtr input = getInput();
rpm-build 6f7582
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  libmwaw::DebugStream f;
rpm-build 6f7582
  f << "Entries(Zone1):";
rpm-build 6f7582
  ascii().addPos(entry.begin());
rpm-build 6f7582
  ascii().addNote(f.str().c_str());
rpm-build 6f7582
  int N=int(entry.length()/30);
rpm-build 6f7582
  for (int i=0; i
rpm-build 6f7582
    /* find something like that
rpm-build 6f7582
       0000000000fb01d80012001c00fb01d800000000000d0007ffe4ffeec000
rpm-build 6f7582
       00000000005500550012001c005500550000000000040001ffe4ffeec000
rpm-build 6f7582
    */
rpm-build 6f7582
    long pos=input->tell();
rpm-build 6f7582
    f.str("");
rpm-build 6f7582
    f << "Zone1-" << i << ":";
rpm-build 6f7582
    ascii().addPos(pos);
rpm-build 6f7582
    ascii().addNote(f.str().c_str());
rpm-build 6f7582
    input->seek(pos+30, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  }
rpm-build 6f7582
  return true;
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
bool MultiplanParser::readCellDataPosition(MWAWEntry const &entry)
rpm-build 6f7582
{
rpm-build 6f7582
  if (m_state->m_maximumCell[0]<=0 || m_state->m_maximumCell[1]<=0 || entry.length()/m_state->m_maximumCell[0]/2<m_state->m_maximumCell[1]) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readCellDataPosition: the zone seems bad\n"));
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  MWAWInputStreamPtr input = getInput();
rpm-build 6f7582
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  libmwaw::DebugStream f;
rpm-build 6f7582
  f << "Entries(DataPos):";
rpm-build 6f7582
  m_state->m_cellPositions.resize(size_t(m_state->m_maximumCell[0]));
rpm-build 6f7582
  auto &posSet=m_state->m_cellPositionsSet;
rpm-build 6f7582
  for (int i=0; i<m_state->m_maximumCell[0]; ++i) {
rpm-build 6f7582
    f << "[" << std::hex;
rpm-build 6f7582
    auto &cellPos=m_state->m_cellPositions[size_t(i)];
rpm-build 6f7582
    for (int j=0; j<m_state->m_maximumCell[1]; ++j) {
rpm-build 6f7582
      cellPos.push_back(int(input->readLong(2)));
rpm-build 6f7582
      posSet.insert(cellPos.back());
rpm-build 6f7582
      if (cellPos.back())
rpm-build 6f7582
        f << cellPos.back() << ",";
rpm-build 6f7582
      else
rpm-build 6f7582
        f << "_,";
rpm-build 6f7582
    }
rpm-build 6f7582
    f << std::dec << "],";
rpm-build 6f7582
  }
rpm-build 6f7582
  if (input->tell()!=entry.end()) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readCellDataPosition: find extra data\n"));
rpm-build 6f7582
    f << "###extra";
rpm-build 6f7582
    ascii().addDelimiter(input->tell(),'|');
rpm-build 6f7582
  }
rpm-build 6f7582
  ascii().addPos(entry.begin());
rpm-build 6f7582
  ascii().addNote(f.str().c_str());
rpm-build 6f7582
  return true;
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
bool MultiplanParser::readLink(int pos, MWAWCellContent::FormulaInstruction &instr)
rpm-build 6f7582
{
rpm-build 6f7582
  auto it=m_state->m_posToLinkMap.find(pos);
rpm-build 6f7582
  if (it!=m_state->m_posToLinkMap.end()) {
rpm-build 6f7582
    instr=it->second;
rpm-build 6f7582
    return true;
rpm-build 6f7582
  }
rpm-build 6f7582
  auto const &entry=m_state->m_entries[4];
rpm-build 6f7582
  if (!entry.valid() || pos<0 || pos+12>entry.length()) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readLink: the pos %d seems bad\n", pos));
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  auto input = getInput();
rpm-build 6f7582
  long actPos=input->tell();
rpm-build 6f7582
  long begPos=entry.begin()+pos;
rpm-build 6f7582
  input->seek(begPos, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  libmwaw::DebugStream f;
rpm-build 6f7582
  f << "Link-" << std::hex << pos << std::dec << "[pos]:";
rpm-build 6f7582
  int dSz=int(input->readULong(1));
rpm-build 6f7582
  if (dSz<0 || pos+12+dSz > entry.end()) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readLink: the pos %d seems bad\n", pos));
rpm-build 6f7582
    input->seek(actPos, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  int type=int(input->readULong(1));
rpm-build 6f7582
  f << "type=" << type << ",";
rpm-build 6f7582
  int lPos=int(input->readULong(2));
rpm-build 6f7582
  if (!readLinkFilename(lPos, instr))
rpm-build 6f7582
    f << "###";
rpm-build 6f7582
  f << "pos=" << std::hex << lPos << std::dec << ",";
rpm-build 6f7582
  int val;
rpm-build 6f7582
  for (int j=0; j<2; ++j) {
rpm-build 6f7582
    val=int(input->readULong(1));
rpm-build 6f7582
    int const expected[]= {0x1a,0x1a};
rpm-build 6f7582
    if (val!=expected[j]) f << "f" << j+2 << "=" << val << ",";
rpm-build 6f7582
  }
rpm-build 6f7582
  for (int j=0; j<3; ++j) {  // f4=1|821
rpm-build 6f7582
    val=int(input->readULong(2));
rpm-build 6f7582
    if (val)
rpm-build 6f7582
      f << "f" << j+4 << "=" << std::hex << val << std::dec << ",";
rpm-build 6f7582
  }
rpm-build 6f7582
  bool ok=false;
rpm-build 6f7582
  switch (type) {
rpm-build 6f7582
  case 0: {
rpm-build 6f7582
    ok=true;
rpm-build 6f7582
    auto fontConverter=getFontConverter();
rpm-build 6f7582
    auto const fId=m_state->m_font.id();
rpm-build 6f7582
    librevenge::RVNGString name=instr.m_fileName.c_str();
rpm-build 6f7582
    name.append(':');
rpm-build 6f7582
    for (int i=0; i
rpm-build 6f7582
      auto ch=static_cast<unsigned char>(input->readULong(1));
rpm-build 6f7582
      int unicode = fontConverter->unicode(fId, static_cast<unsigned char>(ch));
rpm-build 6f7582
      if (unicode!=-1)
rpm-build 6f7582
        libmwaw::appendUnicode(uint32_t(unicode), name);
rpm-build 6f7582
      else if (ch==0x9 || ch > 0x1f)
rpm-build 6f7582
        libmwaw::appendUnicode(static_cast<uint32_t>(ch), name);
rpm-build 6f7582
      else {
rpm-build 6f7582
        f << "##";
rpm-build 6f7582
        MWAW_DEBUG_MSG(("MultiplanParser::readLink: name seems bad\n"));
rpm-build 6f7582
      }
rpm-build 6f7582
    }
rpm-build 6f7582
    instr.m_type=instr.F_Text;
rpm-build 6f7582
    instr.m_content=name.cstr();
rpm-build 6f7582
    break;
rpm-build 6f7582
  }
rpm-build 6f7582
  case 1: {
rpm-build 6f7582
    if (dSz<4)
rpm-build 6f7582
      break;
rpm-build 6f7582
    ok=true;
rpm-build 6f7582
    int rows[2], cols[2];
rpm-build 6f7582
    for (auto &r : rows) r=int(input->readULong(1));
rpm-build 6f7582
    for (auto &c : cols) c=int(input->readULong(1));
rpm-build 6f7582
    for (int j=0; j<2; ++j) {
rpm-build 6f7582
      instr.m_position[j]=MWAWVec2i(cols[j],rows[j]);
rpm-build 6f7582
      instr.m_positionRelative[j]=MWAWVec2b(false,false);
rpm-build 6f7582
    }
rpm-build 6f7582
    instr.m_type=instr.m_position[0]==instr.m_position[1] ? instr.F_Cell : instr.F_CellList;
rpm-build 6f7582
    f << instr << ",";
rpm-build 6f7582
    break;
rpm-build 6f7582
  }
rpm-build 6f7582
  default:
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readLink: find unknown type %d\n", type));
rpm-build 6f7582
    break;
rpm-build 6f7582
  }
rpm-build 6f7582
  if (!ok) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readLink: can not read link at pos %d\n", pos));
rpm-build 6f7582
    f << "###";
rpm-build 6f7582
  }
rpm-build 6f7582
  else
rpm-build 6f7582
    m_state->m_posToLinkMap[pos]=instr;
rpm-build 6f7582
  ascii().addPos(begPos);
rpm-build 6f7582
  ascii().addNote(f.str().c_str());
rpm-build 6f7582
  input->seek(actPos, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  return ok;
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
bool MultiplanParser::readLinkFilename(int pos, MWAWCellContent::FormulaInstruction &instr)
rpm-build 6f7582
{
rpm-build 6f7582
  auto const &entry=m_state->m_entries[5];
rpm-build 6f7582
  if (!entry.valid() || pos<0 || pos+10>entry.length()) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readLinkFilename: the pos %d seems bad\n", pos));
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  MWAWInputStreamPtr input = getInput();
rpm-build 6f7582
  long actPos=input->tell();
rpm-build 6f7582
  long begPos=entry.begin()+pos;
rpm-build 6f7582
  input->seek(begPos, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  libmwaw::DebugStream f;
rpm-build 6f7582
  f << "Link-" << std::hex << pos << std::dec << ":";
rpm-build 6f7582
  for (int i=0; i<2; ++i) {
rpm-build 6f7582
    int val=int(input->readLong(2));
rpm-build 6f7582
    if (val!=1-i) f << "f" << i << "=" << val << ",";
rpm-build 6f7582
  }
rpm-build 6f7582
  f << "unkn=" << std::hex << input->readULong(4) << std::dec << ","; // d66aa996 | d66aab1e maybe dirId, fileId
rpm-build 6f7582
  int dSz=int(input->readULong(1));
rpm-build 6f7582
  if (begPos+9+dSz>entry.end()) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readLinkFilename: the pos %d seems bad\n", pos));
rpm-build 6f7582
    input->seek(actPos, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  librevenge::RVNGString filename;
rpm-build 6f7582
  auto fontConverter=getFontConverter();
rpm-build 6f7582
  auto const fId=m_state->m_font.id();
rpm-build 6f7582
  for (int i=0; i
rpm-build 6f7582
    auto ch=static_cast<unsigned char>(input->readULong(1));
rpm-build 6f7582
    int unicode = fontConverter->unicode(fId, static_cast<unsigned char>(ch));
rpm-build 6f7582
    if (unicode!=-1)
rpm-build 6f7582
      libmwaw::appendUnicode(uint32_t(unicode), filename);
rpm-build 6f7582
    else if (ch==0x9 || ch > 0x1f)
rpm-build 6f7582
      libmwaw::appendUnicode(static_cast<uint32_t>(ch), filename);
rpm-build 6f7582
    else {
rpm-build 6f7582
      f << "##";
rpm-build 6f7582
      MWAW_DEBUG_MSG(("MultiplanParser::readLinkFilename: dir seems bad\n"));
rpm-build 6f7582
    }
rpm-build 6f7582
  }
rpm-build 6f7582
  instr.m_fileName=filename.cstr();
rpm-build 6f7582
  f << instr.m_fileName << ",";
rpm-build 6f7582
  instr.m_sheet="Sheet0";
rpm-build 6f7582
  ascii().addPos(begPos);
rpm-build 6f7582
  ascii().addNote(f.str().c_str());
rpm-build 6f7582
  input->seek(actPos, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  return true;
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
bool MultiplanParser::readSharedData(int pos, int cellType, MWAWVec2i const &cellPos, MWAWCellContent &content)
rpm-build 6f7582
{
rpm-build 6f7582
  auto const &entry=m_state->m_entries[7];
rpm-build 6f7582
  if (!entry.valid() || pos<0 || pos+3>entry.length()) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readSharedData: the pos %d seems bad\n", pos));
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  MWAWInputStreamPtr input = getInput();
rpm-build 6f7582
  long actPos=input->tell();
rpm-build 6f7582
  long begPos=entry.begin()+pos;
rpm-build 6f7582
  input->seek(begPos, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  libmwaw::DebugStream f;
rpm-build 6f7582
  f << "SharedData-" << std::hex << pos << std::dec << ":";
rpm-build 6f7582
  int type=int(input->readULong(2));
rpm-build 6f7582
  f << "type=" << (type&3) << ",";
rpm-build 6f7582
  int N=(type/4);
rpm-build 6f7582
  if (N!=2) f << "used=" << N << ",";
rpm-build 6f7582
  int dSz=int(input->readULong(1));
rpm-build 6f7582
  long endPos=begPos+3+dSz;
rpm-build 6f7582
  if (endPos>entry.end()) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readSharedData: the pos %d seems bad\n", pos));
rpm-build 6f7582
    input->seek(actPos, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  bool ok=true;
rpm-build 6f7582
  switch (type&3) {
rpm-build 6f7582
  case 0:
rpm-build 6f7582
    switch (cellType&3) {
rpm-build 6f7582
    case 0: {
rpm-build 6f7582
      double value;
rpm-build 6f7582
      if (dSz!=8 || !readDouble(value))
rpm-build 6f7582
        ok=false;
rpm-build 6f7582
      else {
rpm-build 6f7582
        content.m_contentType=content.C_NUMBER;
rpm-build 6f7582
        content.setValue(value);
rpm-build 6f7582
        f << value << ",";
rpm-build 6f7582
      }
rpm-build 6f7582
      break;
rpm-build 6f7582
    }
rpm-build 6f7582
    case 1: {
rpm-build 6f7582
      content.m_contentType=content.C_TEXT;
rpm-build 6f7582
      content.m_textEntry.setBegin(input->tell());
rpm-build 6f7582
      content.m_textEntry.setLength(dSz);
rpm-build 6f7582
      std::string name;
rpm-build 6f7582
      for (int c=0; c<dSz; ++c) name+=char(input->readULong(1));
rpm-build 6f7582
      f << name << ",";
rpm-build 6f7582
      break;
rpm-build 6f7582
    }
rpm-build 6f7582
    case 2:
rpm-build 6f7582
      if (dSz!=8)
rpm-build 6f7582
        ok=false;
rpm-build 6f7582
      else {
rpm-build 6f7582
        f << "Nan" << input->readULong(1) << ",";
rpm-build 6f7582
        input->seek(7, librevenge::RVNG_SEEK_CUR);
rpm-build 6f7582
        content.m_contentType=content.C_NUMBER;
rpm-build 6f7582
        content.setValue(std::nan(""));
rpm-build 6f7582
      }
rpm-build 6f7582
      break;
rpm-build 6f7582
    case 3:
rpm-build 6f7582
    default:
rpm-build 6f7582
      if (dSz!=8)
rpm-build 6f7582
        ok=false;
rpm-build 6f7582
      else {
rpm-build 6f7582
        int val=int(input->readULong(1));
rpm-build 6f7582
        content.m_contentType=content.C_NUMBER;
rpm-build 6f7582
        content.setValue(val);
rpm-build 6f7582
        if (val==0)
rpm-build 6f7582
          f << "false,";
rpm-build 6f7582
        else if (val==1)
rpm-build 6f7582
          f << "true,";
rpm-build 6f7582
        else
rpm-build 6f7582
          f << "##bool=" << val << ",";
rpm-build 6f7582
        input->seek(7, librevenge::RVNG_SEEK_CUR);
rpm-build 6f7582
      }
rpm-build 6f7582
      break;
rpm-build 6f7582
    }
rpm-build 6f7582
    break;
rpm-build 6f7582
  case 1: {
rpm-build 6f7582
    std::string err;
rpm-build 6f7582
    if (!readFormula(cellPos, content.m_formula, endPos, err))
rpm-build 6f7582
      f << "###";
rpm-build 6f7582
    else
rpm-build 6f7582
      content.m_contentType=content.C_FORMULA;
rpm-build 6f7582
    for (auto const &fo : content.m_formula) f << fo;
rpm-build 6f7582
    f << ",";
rpm-build 6f7582
    f << err;
rpm-build 6f7582
    break;
rpm-build 6f7582
  }
rpm-build 6f7582
  default:
rpm-build 6f7582
    ok=false;
rpm-build 6f7582
    break;
rpm-build 6f7582
  }
rpm-build 6f7582
  if (!ok) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readSharedData: can not read data for the pos %d\n", pos));
rpm-build 6f7582
    f << "###";
rpm-build 6f7582
  }
rpm-build 6f7582
  if (m_state->m_posToSharedDataSeen.find(pos)==m_state->m_posToSharedDataSeen.end()) {
rpm-build 6f7582
    m_state->m_posToSharedDataSeen.insert(pos);
rpm-build 6f7582
    if (input->tell()!=endPos)
rpm-build 6f7582
      ascii().addDelimiter(input->tell(),'|');
rpm-build 6f7582
    ascii().addPos(begPos);
rpm-build 6f7582
    ascii().addNote(f.str().c_str());
rpm-build 6f7582
  }
rpm-build 6f7582
  input->seek(actPos, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  return true;
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
bool MultiplanParser::readName(int pos, MWAWCellContent::FormulaInstruction &instruction)
rpm-build 6f7582
{
rpm-build 6f7582
  auto it=m_state->m_posToNameMap.find(pos);
rpm-build 6f7582
  if (it!=m_state->m_posToNameMap.end()) {
rpm-build 6f7582
    instruction=it->second;
rpm-build 6f7582
    return true;
rpm-build 6f7582
  }
rpm-build 6f7582
  auto const &entry=m_state->m_entries[8]; // the named entry
rpm-build 6f7582
  if (!entry.valid() || pos<0 || pos+10>=entry.length()) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readName: the pos %d seeems bad\n", pos));
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  MWAWInputStreamPtr input = getInput();
rpm-build 6f7582
  long actPos=input->tell();
rpm-build 6f7582
  long begPos=entry.begin()+pos;
rpm-build 6f7582
  input->seek(begPos, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  libmwaw::DebugStream f;
rpm-build 6f7582
  f << "Names-" << std::hex << pos << std::dec << ":";
rpm-build 6f7582
  int val=int(input->readULong(1));
rpm-build 6f7582
  int dSz=(val>>3);
rpm-build 6f7582
  if (dSz<=0 || begPos+10+dSz>entry.end()) {
rpm-build 6f7582
    input->seek(actPos, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readName: the pos %d seeems bad\n", pos));
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  if (val&3) f << "f0=" << val << ",";
rpm-build 6f7582
  val=int(input->readULong(1)); // 40|60
rpm-build 6f7582
  if (val) f << "f1=" << std::hex << val << std::dec << ",";
rpm-build 6f7582
  int rows[2];
rpm-build 6f7582
  for (auto &r : rows) r=int(input->readULong(1));
rpm-build 6f7582
  val=int(input->readULong(2));
rpm-build 6f7582
  int cols[2]= {(val>>10),(val>>4)&0x3f};
rpm-build 6f7582
  for (int i=0; i<2; ++i) {
rpm-build 6f7582
    instruction.m_position[i]=MWAWVec2i(cols[i], rows[i]);
rpm-build 6f7582
    instruction.m_positionRelative[i]=MWAWVec2b(false,false);
rpm-build 6f7582
  }
rpm-build 6f7582
  instruction.m_type=instruction.m_position[0]==instruction.m_position[1] ? instruction.F_Cell : instruction.F_CellList;
rpm-build 6f7582
  f << instruction << ",";
rpm-build 6f7582
  m_state->m_posToNameMap[pos]=instruction;
rpm-build 6f7582
  if (val&0xf) f << "f2=" << (val&0xf) << ","; // 0|2
rpm-build 6f7582
  for (int i=0; i<2; ++i) { // 0
rpm-build 6f7582
    val=int(input->readLong(2));
rpm-build 6f7582
    if (val) f << "f" << i+2 << "=" << val << ",";
rpm-build 6f7582
  }
rpm-build 6f7582
  std::string name;
rpm-build 6f7582
  for (int c=0; c<dSz; ++c) name+=char(input->readULong(1));
rpm-build 6f7582
  f << name << ",";
rpm-build 6f7582
  ascii().addPos(begPos);
rpm-build 6f7582
  ascii().addNote(f.str().c_str());
rpm-build 6f7582
rpm-build 6f7582
  input->seek(actPos, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  return true;
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
bool MultiplanParser::readZoneB()
rpm-build 6f7582
{
rpm-build 6f7582
  MWAWInputStreamPtr input = getInput();
rpm-build 6f7582
  long pos = input->tell();
rpm-build 6f7582
  if (!input->checkPosition(pos+82)) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readZoneB: the zone seems too short\n"));
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  libmwaw::DebugStream f;
rpm-build 6f7582
  f << "Entries(ZoneB):";
rpm-build 6f7582
  int dim[2];
rpm-build 6f7582
  for (auto &d : dim) d=int(input->readULong(2));
rpm-build 6f7582
  m_state->m_maximumCell=MWAWVec2i(dim[0],dim[1]);
rpm-build 6f7582
  f << "cell[max]=" << m_state->m_maximumCell << ",";
rpm-build 6f7582
  int val;
rpm-build 6f7582
  for (int i=0; i<7; ++i) {
rpm-build 6f7582
    val=int(input->readLong(2));
rpm-build 6f7582
    int const expected[]= {0,0,0x7fff,0x47,0xc,0x1e7,0x10a};
rpm-build 6f7582
    if (val!=expected[i])
rpm-build 6f7582
      f << "f" << i << "=" << val << ",";
rpm-build 6f7582
  }
rpm-build 6f7582
  for (int i=0; i<15; ++i) {
rpm-build 6f7582
    val=int(input->readLong(2));
rpm-build 6f7582
    if (!val) continue;
rpm-build 6f7582
    f << "g" << i << "=" << val << ",";
rpm-build 6f7582
  }
rpm-build 6f7582
  ascii().addPos(pos);
rpm-build 6f7582
  ascii().addNote(f.str().c_str());
rpm-build 6f7582
rpm-build 6f7582
  pos=input->tell();
rpm-build 6f7582
  f.str("");
rpm-build 6f7582
  f << "ZoneB[II]:";
rpm-build 6f7582
  for (int i=0; i<2; ++i) {
rpm-build 6f7582
    val=int(input->readLong(1));
rpm-build 6f7582
    if (val!=1-i) f << "f" << i << "=" << val << ",";
rpm-build 6f7582
  }
rpm-build 6f7582
  int dim4[4];
rpm-build 6f7582
  for (auto &d : dim4) d=int(input->readULong(1));
rpm-build 6f7582
  f << "selection=" << MWAWBox2i(MWAWVec2i(dim4[0],dim4[1]),MWAWVec2i(dim4[2],dim4[3])) << ",";
rpm-build 6f7582
  for (int i=0; i<19; ++i) { // 0
rpm-build 6f7582
    val=int(input->readLong(1));
rpm-build 6f7582
    if (val) f << "g" << i << "=" << val << ",";
rpm-build 6f7582
  }
rpm-build 6f7582
  ascii().addPos(pos);
rpm-build 6f7582
  ascii().addNote(f.str().c_str());
rpm-build 6f7582
rpm-build 6f7582
  input->seek(pos+82, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  return true;
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
bool MultiplanParser::readZoneC()
rpm-build 6f7582
{
rpm-build 6f7582
  MWAWInputStreamPtr input = getInput();
rpm-build 6f7582
  long pos = input->tell();
rpm-build 6f7582
  if (!input->checkPosition(pos+22)) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readZoneC: the zone seems too short\n"));
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  libmwaw::DebugStream f;
rpm-build 6f7582
  f << "Entries(ZoneC):";
rpm-build 6f7582
  int val;
rpm-build 6f7582
  f << "unkn=[";
rpm-build 6f7582
  for (int i=0; i<4; ++i) { // small number
rpm-build 6f7582
    val=int(input->readLong(2));
rpm-build 6f7582
    if (val)
rpm-build 6f7582
      f << val << ",";
rpm-build 6f7582
    else
rpm-build 6f7582
      f << "_,";
rpm-build 6f7582
  }
rpm-build 6f7582
  f << "],";
rpm-build 6f7582
  val=int(input->readLong(2));
rpm-build 6f7582
  if (val==1)
rpm-build 6f7582
    f << "protected,";
rpm-build 6f7582
  else if (val)
rpm-build 6f7582
    f << "protected=#" << val << ",";
rpm-build 6f7582
  val=int(input->readULong(2));
rpm-build 6f7582
  if (val) f << "passwd[crypted]=" << std::hex << val << std::dec << ",";
rpm-build 6f7582
  for (int i=0; i<5; ++i) {
rpm-build 6f7582
    val=int(input->readLong(2));
rpm-build 6f7582
    int const expected[]= {0,0,0,2,1};
rpm-build 6f7582
    if (val!=expected[i]) f << "g" << i << "=" << val << ",";
rpm-build 6f7582
  }
rpm-build 6f7582
  ascii().addPos(pos);
rpm-build 6f7582
  ascii().addNote(f.str().c_str());
rpm-build 6f7582
  return true;
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
////////////////////////////////////////////////////////////
rpm-build 6f7582
// double
rpm-build 6f7582
////////////////////////////////////////////////////////////
rpm-build 6f7582
bool MultiplanParser::readDouble(double &value)
rpm-build 6f7582
{
rpm-build 6f7582
  MWAWInputStreamPtr input = getInput();
rpm-build 6f7582
  long pos=input->tell();
rpm-build 6f7582
  value=0;
rpm-build 6f7582
  if (!input->checkPosition(input->tell()+8)) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readDouble: the zone is too short\n"));
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  int exponant=int(input->readULong(1));
rpm-build 6f7582
  double sign=1;
rpm-build 6f7582
  if (exponant&0x80) {
rpm-build 6f7582
    exponant&=0x7f;
rpm-build 6f7582
    sign=-1;
rpm-build 6f7582
  }
rpm-build 6f7582
  bool ok=true;
rpm-build 6f7582
  double factor=1;
rpm-build 6f7582
  for (int i=0; i<7; ++i) {
rpm-build 6f7582
    int val=int(input->readULong(1));
rpm-build 6f7582
    for (int d=0; d<2; ++d) {
rpm-build 6f7582
      int v= d==0 ? (val>>4) : (val&0xf);
rpm-build 6f7582
      if (v>=10) {
rpm-build 6f7582
        MWAW_DEBUG_MSG(("MultiplanParser::readDouble: oops find a bad digits\n"));
rpm-build 6f7582
        ok=false;
rpm-build 6f7582
        break;
rpm-build 6f7582
      }
rpm-build 6f7582
      factor/=10.;
rpm-build 6f7582
      value+=factor*v;
rpm-build 6f7582
    }
rpm-build 6f7582
    if (!ok) break;
rpm-build 6f7582
  }
rpm-build 6f7582
  value *= sign*std::pow(10.,exponant-0x40);
rpm-build 6f7582
  input->seek(pos+8, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  return ok;
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
////////////////////////////////////////////////////////////
rpm-build 6f7582
// formula
rpm-build 6f7582
////////////////////////////////////////////////////////////
rpm-build 6f7582
namespace MultiplanParserInternal
rpm-build 6f7582
{
rpm-build 6f7582
struct Functions {
rpm-build 6f7582
  char const *m_name;
rpm-build 6f7582
  int m_arity;
rpm-build 6f7582
};
rpm-build 6f7582
rpm-build 6f7582
static Functions const s_listOperators[] = {
rpm-build 6f7582
  // 0
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  // 1
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  // 2
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { ":", 2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { ":", 2}, { "", -2}, { "", -2},
rpm-build 6f7582
  // 3
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  // 4
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { ":", 2}, { "", -2}, { "", -2},
rpm-build 6f7582
  // 5
rpm-build 6f7582
  { "&", 2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  // 6
rpm-build 6f7582
  { "<", 2}, { "", -2}, { "<=", 2}, { "", -2},
rpm-build 6f7582
  { "=", 2}, { "", -2}, { ">=", 2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  // 7
rpm-build 6f7582
  { ">", 2}, { "", -2}, { "<>", 2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  // 8
rpm-build 6f7582
  { "", -2}, { "", -2}, { "+", 2}, { "", -2},
rpm-build 6f7582
  { "-", 2}, { "", -2}, { "*", 2}, { "", -2},
rpm-build 6f7582
  { "/", 2}, { "", -2}, { "^", 2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "-", 1}, { "", -2},
rpm-build 6f7582
  // 9
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "%", 1}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
  { "", -2}, { "", -2}, { "", -2}, { "", -2},
rpm-build 6f7582
};
rpm-build 6f7582
rpm-build 6f7582
char const *s_listFunctions[]= {
rpm-build 6f7582
  // 0
rpm-build 6f7582
  "Count", "If", "IsNA", "IsError",
rpm-build 6f7582
  "Sum", "Average", "Min", "Max",
rpm-build 6f7582
  "Row", "Column", "NA", "NPV",
rpm-build 6f7582
  "Stdev", "Dollar", "Fixed", "Sin",
rpm-build 6f7582
  // 1
rpm-build 6f7582
  "Cos", "Tan", "Atan", "Pi",
rpm-build 6f7582
  "Sqrt", "Exp", "Ln", "Log",
rpm-build 6f7582
  "Abs", "Int", "Sign", "Round",
rpm-build 6f7582
  "Lookup", "Index", "Rept", "Mid",
rpm-build 6f7582
  // 2
rpm-build 6f7582
  "Length", "Value", "True", "False",
rpm-build 6f7582
  "And", "Or", "Not", "Mod",
rpm-build 6f7582
  "IterCnt", "Delta", "PV", "FV",
rpm-build 6f7582
  "NPer", "PMT", "Rate", "MIRR",
rpm-build 6f7582
  // 3
rpm-build 6f7582
  "Irr", nullptr, nullptr, nullptr,
rpm-build 6f7582
  nullptr, nullptr, nullptr, nullptr,
rpm-build 6f7582
  nullptr, nullptr, nullptr, nullptr,
rpm-build 6f7582
  nullptr, nullptr, nullptr, nullptr,
rpm-build 6f7582
};
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
bool MultiplanParser::readFormula(MWAWVec2i const &cellPos, std::vector<MWAWCellContent::FormulaInstruction> &formula, long endPos, std::string &error)
rpm-build 6f7582
{
rpm-build 6f7582
  formula.clear();
rpm-build 6f7582
  MWAWInputStreamPtr input = getInput();
rpm-build 6f7582
  std::vector<std::vector<MWAWCellContent::FormulaInstruction> > stack;
rpm-build 6f7582
  auto const &listOperators=MultiplanParserInternal::s_listOperators;
rpm-build 6f7582
  int const numOperators=int(MWAW_N_ELEMENTS(listOperators));
rpm-build 6f7582
  auto const &listFunctions=MultiplanParserInternal::s_listFunctions;
rpm-build 6f7582
  int const numFunctions=int(MWAW_N_ELEMENTS(listFunctions));
rpm-build 6f7582
  bool ok=true;
rpm-build 6f7582
  int closeDelayed=0;
rpm-build 6f7582
  bool checkForClose=false;
rpm-build 6f7582
  while (input->tell()<=endPos) {
rpm-build 6f7582
    long pos=input->tell();
rpm-build 6f7582
    int wh=pos==endPos ? -1 : int(input->readULong(1));
rpm-build 6f7582
    bool needCloseParenthesis=closeDelayed && (checkForClose || pos==endPos);
rpm-build 6f7582
    ok=true;
rpm-build 6f7582
    if (closeDelayed && !needCloseParenthesis && wh!=0x3c)
rpm-build 6f7582
      needCloseParenthesis=wh>=numOperators || listOperators[wh].m_arity!=2;
rpm-build 6f7582
    while (needCloseParenthesis && closeDelayed>0) {
rpm-build 6f7582
      auto len=stack.size();
rpm-build 6f7582
      if (len<2) {
rpm-build 6f7582
        error="##closedParenthesis,";
rpm-build 6f7582
        ok=false;
rpm-build 6f7582
        break;
rpm-build 6f7582
      }
rpm-build 6f7582
      auto &dParenthesisFunc=stack[len-2];
rpm-build 6f7582
      if (dParenthesisFunc.size()!=1 || dParenthesisFunc[0].m_type!=dParenthesisFunc[0].F_Operator ||
rpm-build 6f7582
          dParenthesisFunc[0].m_content!="(") {
rpm-build 6f7582
        error="##closedParenthesis,";
rpm-build 6f7582
        ok=false;
rpm-build 6f7582
        break;
rpm-build 6f7582
      }
rpm-build 6f7582
      dParenthesisFunc.insert(dParenthesisFunc.end(),stack.back().begin(), stack.back().end());
rpm-build 6f7582
      MWAWCellContent::FormulaInstruction instr;
rpm-build 6f7582
      instr.m_type=instr.F_Operator;
rpm-build 6f7582
      instr.m_content=")";
rpm-build 6f7582
      dParenthesisFunc.push_back(instr);
rpm-build 6f7582
      stack.resize(len-1);
rpm-build 6f7582
      --closeDelayed;
rpm-build 6f7582
    }
rpm-build 6f7582
    if (!ok || pos==endPos)
rpm-build 6f7582
      break;
rpm-build 6f7582
    int arity=0;
rpm-build 6f7582
    MWAWCellContent::FormulaInstruction instr;
rpm-build 6f7582
    ok=false;
rpm-build 6f7582
    bool noneInstr=false, closeFunction=false;
rpm-build 6f7582
    switch (wh) {
rpm-build 6f7582
    case 0:
rpm-build 6f7582
      if (pos+3>endPos || !readLink(int(input->readULong(2)), instr))
rpm-build 6f7582
        break;
rpm-build 6f7582
      ok=true;
rpm-build 6f7582
      break;
rpm-build 6f7582
    case 0x12: {
rpm-build 6f7582
      if (pos+2>endPos)
rpm-build 6f7582
        break;
rpm-build 6f7582
      ok=true;
rpm-build 6f7582
      instr.m_type=instr.F_Function;
rpm-build 6f7582
      int id=int(input->readULong(1));
rpm-build 6f7582
      if (id
rpm-build 6f7582
        instr.m_content=listFunctions[id];
rpm-build 6f7582
      else {
rpm-build 6f7582
        std::stringstream s;
rpm-build 6f7582
        s << "Funct" << std::hex << id << std::dec;
rpm-build 6f7582
        instr.m_content=s.str();
rpm-build 6f7582
      }
rpm-build 6f7582
      std::vector<MWAWCellContent::FormulaInstruction> child;
rpm-build 6f7582
      child.push_back(instr);
rpm-build 6f7582
      stack.push_back(child);
rpm-build 6f7582
      instr.m_type=instr.F_Operator;
rpm-build 6f7582
      instr.m_content="(";
rpm-build 6f7582
      break;
rpm-build 6f7582
    }
rpm-build 6f7582
    case 0x51:
rpm-build 6f7582
    case 0x71:
rpm-build 6f7582
    case 0x91:
rpm-build 6f7582
    case 0xd1:
rpm-build 6f7582
    case 0xf1:
rpm-build 6f7582
      closeFunction=ok=true;
rpm-build 6f7582
      break;
rpm-build 6f7582
    case 0x1c: // use before %
rpm-build 6f7582
    case 0x1e: // use for <> A 1e B "code <>"
rpm-build 6f7582
    case 0x34: // use for <=,>= ... A 34 B "code <=,..."
rpm-build 6f7582
    case 0x36: // use before -unary
rpm-build 6f7582
      noneInstr=ok=true;
rpm-build 6f7582
      break;
rpm-build 6f7582
    case 0x3a:
rpm-build 6f7582
      ok=true;
rpm-build 6f7582
      instr.m_type=instr.F_Operator;
rpm-build 6f7582
      instr.m_content=";";
rpm-build 6f7582
      break;
rpm-build 6f7582
    case 0x3c:
rpm-build 6f7582
      noneInstr=ok=true;
rpm-build 6f7582
      ++closeDelayed;
rpm-build 6f7582
      break;
rpm-build 6f7582
    case 0x3e:
rpm-build 6f7582
      ok=true;
rpm-build 6f7582
      instr.m_type=instr.F_Operator;
rpm-build 6f7582
      instr.m_content="(";
rpm-build 6f7582
      break;
rpm-build 6f7582
    case 0x56: {
rpm-build 6f7582
      int dSz=int(input->readULong(1));
rpm-build 6f7582
      if (pos+2+dSz>endPos)
rpm-build 6f7582
        break;
rpm-build 6f7582
      instr.m_type=instr.F_Text;
rpm-build 6f7582
      auto fontConverter=getFontConverter();
rpm-build 6f7582
      auto const fId=m_state->m_font.id();
rpm-build 6f7582
      librevenge::RVNGString content;
rpm-build 6f7582
      for (int i=0; i
rpm-build 6f7582
        auto ch=static_cast<unsigned char>(input->readULong(1));
rpm-build 6f7582
        int unicode = fontConverter->unicode(fId, static_cast<unsigned char>(ch));
rpm-build 6f7582
        if (unicode!=-1)
rpm-build 6f7582
          libmwaw::appendUnicode(uint32_t(unicode), content);
rpm-build 6f7582
        else if (ch==0x9 || ch > 0x1f)
rpm-build 6f7582
          libmwaw::appendUnicode(static_cast<uint32_t>(ch), content);
rpm-build 6f7582
        else {
rpm-build 6f7582
          MWAW_DEBUG_MSG(("MultiplanParser::readFormula: content seen bad seems bad\n"));
rpm-build 6f7582
          error="##content";
rpm-build 6f7582
        }
rpm-build 6f7582
      }
rpm-build 6f7582
      instr.m_content=content.cstr();
rpm-build 6f7582
      ok=true;
rpm-build 6f7582
      break;
rpm-build 6f7582
    }
rpm-build 6f7582
    case 0x21: // double
rpm-build 6f7582
    case 0xe1:
rpm-build 6f7582
    case 0x8f: // simple
rpm-build 6f7582
    case 0xef:
rpm-build 6f7582
      if (pos+3>endPos)
rpm-build 6f7582
        break;
rpm-build 6f7582
      instr.m_type=instr.F_Cell;
rpm-build 6f7582
      instr.m_positionRelative[0]=MWAWVec2b(false,false);
rpm-build 6f7582
      instr.m_position[0][1]=int(input->readULong(1));
rpm-build 6f7582
      instr.m_position[0][0]=int(input->readULong(1));
rpm-build 6f7582
      ok=(instr.m_position[0][0]<63) && (instr.m_position[0][1]<255);
rpm-build 6f7582
      if (!ok) {
rpm-build 6f7582
        error="###RorC";
rpm-build 6f7582
        MWAW_DEBUG_MSG(("MultiplanParser::readFormula: find only row/column reference\n"));
rpm-build 6f7582
      }
rpm-build 6f7582
      break;
rpm-build 6f7582
    case 0x29: // example C2 R1
rpm-build 6f7582
      MWAW_DEBUG_MSG(("MultiplanParser::readFormula: find union operator\n"));
rpm-build 6f7582
      error="###union";
rpm-build 6f7582
      ok=false;
rpm-build 6f7582
      break;
rpm-build 6f7582
    case 0x37: // use for list cell
rpm-build 6f7582
    case 0x53:
rpm-build 6f7582
    case 0x73:
rpm-build 6f7582
    case 0x93: // basic cell
rpm-build 6f7582
    case 0xf3: { // difference ?
rpm-build 6f7582
      if (pos+3>endPos)
rpm-build 6f7582
        break;
rpm-build 6f7582
      instr.m_type=instr.F_Cell;
rpm-build 6f7582
      instr.m_positionRelative[0]=MWAWVec2b(true,true);
rpm-build 6f7582
      int val=int(input->readULong(2));
rpm-build 6f7582
      auto &newPos=instr.m_position[0];
rpm-build 6f7582
      if (val&0x80)
rpm-build 6f7582
        newPos[1]=cellPos[1]-(val>>8);
rpm-build 6f7582
      else
rpm-build 6f7582
        newPos[1]=cellPos[1]+(val>>8);
rpm-build 6f7582
      if (val&0x40)
rpm-build 6f7582
        newPos[0]=cellPos[0]-(val&0x3f);
rpm-build 6f7582
      else
rpm-build 6f7582
        newPos[0]=cellPos[0]+(val&0x3f);
rpm-build 6f7582
      ok=newPos[0]>=0 && newPos[1]>=0;
rpm-build 6f7582
      break;
rpm-build 6f7582
    }
rpm-build 6f7582
    case 0x94:
rpm-build 6f7582
      if (pos+9>endPos || !readDouble(instr.m_doubleValue))
rpm-build 6f7582
        break;
rpm-build 6f7582
      instr.m_type=instr.F_Double;
rpm-build 6f7582
      ok=true;
rpm-build 6f7582
      break;
rpm-build 6f7582
    case 0xf5:
rpm-build 6f7582
      if (pos+3>endPos || !readName(int(input->readULong(2)), instr))
rpm-build 6f7582
        break;
rpm-build 6f7582
      ok=true;
rpm-build 6f7582
      break;
rpm-build 6f7582
    default:
rpm-build 6f7582
      if (wh
rpm-build 6f7582
        instr.m_content=listOperators[wh].m_name;
rpm-build 6f7582
        instr.m_type=instr.F_Function;
rpm-build 6f7582
        arity=listOperators[wh].m_arity;
rpm-build 6f7582
      }
rpm-build 6f7582
      if (instr.m_content.empty()) {
rpm-build 6f7582
        MWAW_DEBUG_MSG(("MultiplanParser::readFormula: find unknown type %x\n", wh));
rpm-build 6f7582
        std::stringstream s;
rpm-build 6f7582
        s << "##unkn[func]=" << std::hex << wh << std::dec << ",";
rpm-build 6f7582
        error=s.str();
rpm-build 6f7582
        break;
rpm-build 6f7582
      }
rpm-build 6f7582
      ok=true;
rpm-build 6f7582
      break;
rpm-build 6f7582
    }
rpm-build 6f7582
    if (!ok) {
rpm-build 6f7582
      input->seek(pos, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
      break;
rpm-build 6f7582
    }
rpm-build 6f7582
    checkForClose=!noneInstr && closeDelayed>0;
rpm-build 6f7582
    if (noneInstr) continue;
rpm-build 6f7582
    if (closeFunction) {
rpm-build 6f7582
      ok=false;
rpm-build 6f7582
      if (stack.empty()) {
rpm-build 6f7582
        error="##closed,";
rpm-build 6f7582
        break;
rpm-build 6f7582
      }
rpm-build 6f7582
      auto it=stack.end();
rpm-build 6f7582
      --it;
rpm-build 6f7582
      for (; it!=stack.begin(); --it) {
rpm-build 6f7582
        if (it->size()!=1) continue;
rpm-build 6f7582
        auto const &dInstr=(*it)[0];
rpm-build 6f7582
        if (dInstr.m_type!=dInstr.F_Operator || dInstr.m_content!="(") continue;
rpm-build 6f7582
        auto fIt=it;
rpm-build 6f7582
        --fIt;
rpm-build 6f7582
        auto &functionStack=*fIt;
rpm-build 6f7582
        if (functionStack.size()!=1 || functionStack[0].m_type!=functionStack[0].F_Function) continue;
rpm-build 6f7582
        ok=true;
rpm-build 6f7582
        for (; it!=stack.end(); ++it)
rpm-build 6f7582
          functionStack.insert(functionStack.end(), it->begin(), it->end());
rpm-build 6f7582
        ++fIt;
rpm-build 6f7582
        stack.erase(fIt, stack.end());
rpm-build 6f7582
        break;
rpm-build 6f7582
      }
rpm-build 6f7582
      if (!ok) {
rpm-build 6f7582
        error="##closed";
rpm-build 6f7582
        break;
rpm-build 6f7582
      }
rpm-build 6f7582
      instr.m_type=instr.F_Operator;
rpm-build 6f7582
      instr.m_content=")";
rpm-build 6f7582
      stack.back().push_back(instr);
rpm-build 6f7582
      continue;
rpm-build 6f7582
    }
rpm-build 6f7582
    std::vector<MWAWCellContent::FormulaInstruction> child;
rpm-build 6f7582
    if (instr.m_type!=MWAWCellContent::FormulaInstruction::F_Function) {
rpm-build 6f7582
      child.push_back(instr);
rpm-build 6f7582
      stack.push_back(child);
rpm-build 6f7582
      continue;
rpm-build 6f7582
    }
rpm-build 6f7582
    size_t numElt = stack.size();
rpm-build 6f7582
    if (static_cast<int>(numElt) < arity) {
rpm-build 6f7582
      std::stringstream s;
rpm-build 6f7582
      s << instr.m_content << "[##" << arity << "]";
rpm-build 6f7582
      error=s.str();
rpm-build 6f7582
      input->seek(pos, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
      ok=false;
rpm-build 6f7582
      break;
rpm-build 6f7582
    }
rpm-build 6f7582
    if (arity==1) {
rpm-build 6f7582
      instr.m_type=MWAWCellContent::FormulaInstruction::F_Operator;
rpm-build 6f7582
      if (instr.m_content=="%")
rpm-build 6f7582
        stack[numElt-1].push_back(instr);
rpm-build 6f7582
      else
rpm-build 6f7582
        stack[numElt-1].insert(stack[numElt-1].begin(), instr);
rpm-build 6f7582
      continue;
rpm-build 6f7582
    }
rpm-build 6f7582
    if (arity==2) {
rpm-build 6f7582
      instr.m_type=MWAWCellContent::FormulaInstruction::F_Operator;
rpm-build 6f7582
      stack[numElt-2].push_back(instr);
rpm-build 6f7582
      stack[numElt-2].insert(stack[numElt-2].end(), stack[numElt-1].begin(), stack[numElt-1].end());
rpm-build 6f7582
      stack.resize(numElt-1);
rpm-build 6f7582
      continue;
rpm-build 6f7582
    }
rpm-build 6f7582
    ok=false;
rpm-build 6f7582
    error = "### unexpected arity";
rpm-build 6f7582
    input->seek(pos, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
    break;
rpm-build 6f7582
  }
rpm-build 6f7582
  long pos=input->tell();
rpm-build 6f7582
  if (pos!=endPos || !ok || closeDelayed || stack.size()!=1 || stack[0].empty()) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::readFormula: can not read a formula\n"));
rpm-build 6f7582
    ascii().addDelimiter(pos, '|');
rpm-build 6f7582
    input->seek(endPos, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
rpm-build 6f7582
    std::stringstream s;
rpm-build 6f7582
    if (!error.empty())
rpm-build 6f7582
      s << error;
rpm-build 6f7582
    else
rpm-build 6f7582
      s << "##unknownError";
rpm-build 6f7582
    s << "[";
rpm-build 6f7582
    for (auto const &i : stack) {
rpm-build 6f7582
      for (auto const &j : i)
rpm-build 6f7582
        s << j << ",";
rpm-build 6f7582
    }
rpm-build 6f7582
    s << "],";
rpm-build 6f7582
    error=s.str();
rpm-build 6f7582
    return true;
rpm-build 6f7582
  }
rpm-build 6f7582
  formula=stack[0];
rpm-build 6f7582
  return true;
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
////////////////////////////////////////////////////////////
rpm-build 6f7582
// read the header
rpm-build 6f7582
////////////////////////////////////////////////////////////
rpm-build 6f7582
bool MultiplanParser::checkHeader(MWAWHeader *header, bool strict)
rpm-build 6f7582
{
rpm-build 6f7582
  *m_state = MultiplanParserInternal::State();
rpm-build 6f7582
rpm-build 6f7582
  MWAWInputStreamPtr input = getInput();
rpm-build 6f7582
  if (!input || !input->hasDataFork())
rpm-build 6f7582
    return false;
rpm-build 6f7582
rpm-build 6f7582
  if (!input->checkPosition(0x778)) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::checkHeader: file is too short\n"));
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  input->seek(0,librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  if (input->readULong(2)!=0x11ab || input->readULong(2)!=0 ||
rpm-build 6f7582
      input->readULong(2)!=0x13e8 || input->readULong(2)!=0)
rpm-build 6f7582
    return false;
rpm-build 6f7582
  libmwaw::DebugStream f;
rpm-build 6f7582
  f << "FileHeader:";
rpm-build 6f7582
  for (int i=0; i<2; ++i) {
rpm-build 6f7582
    int val=int(input->readLong(2));
rpm-build 6f7582
    if (val)
rpm-build 6f7582
      f << "f" << i << "=" << val << ",";
rpm-build 6f7582
  }
rpm-build 6f7582
  ascii().addPos(0);
rpm-build 6f7582
  ascii().addNote(f.str().c_str());
rpm-build 6f7582
  if (strict) {
rpm-build 6f7582
    // read the last zone list position and check that it corresponds to a valid position
rpm-build 6f7582
    input->seek(0x758, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
    int val=int(input->readULong(2));
rpm-build 6f7582
    if (val<0x3c || !input->checkPosition(0x75a+val)) {
rpm-build 6f7582
      MWAW_DEBUG_MSG(("MultiplanParser::checkHeader: can not find last spreadsheet position\n"));
rpm-build 6f7582
      return false;
rpm-build 6f7582
    }
rpm-build 6f7582
  }
rpm-build 6f7582
  /* checkme: MsMultiplan DOS begins by a list of 8 potential filename
rpm-build 6f7582
     linked to this files (with length 0x1f) maybe something like
rpm-build 6f7582
     that... */
rpm-build 6f7582
  input->seek(0x30,librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  ascii().addPos(0x30);
rpm-build 6f7582
  ascii().addNote("Entries(ZoneA):");
rpm-build 6f7582
  for (int i=0; i<4; ++i) {
rpm-build 6f7582
    long pos=input->tell();
rpm-build 6f7582
    f.str("");
rpm-build 6f7582
    f << "ZoneA" << i << ":";
rpm-build 6f7582
    ascii().addPos(pos);
rpm-build 6f7582
    ascii().addNote(f.str().c_str());
rpm-build 6f7582
    input->seek(pos+0x80,librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  }
rpm-build 6f7582
  long pos=input->tell();
rpm-build 6f7582
  ascii().addPos(pos);
rpm-build 6f7582
  ascii().addNote("ZoneA4");
rpm-build 6f7582
  input->seek(0x272,librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  if (header)
rpm-build 6f7582
    header->reset(MWAWDocument::MWAW_T_MICROSOFTMULTIPLAN, 1, MWAWDocument::MWAW_K_SPREADSHEET);
rpm-build 6f7582
  return true;
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
////////////////////////////////////////////////////////////
rpm-build 6f7582
// send spreadsheet
rpm-build 6f7582
////////////////////////////////////////////////////////////
rpm-build 6f7582
bool MultiplanParser::sendText(MWAWEntry const &entry)
rpm-build 6f7582
{
rpm-build 6f7582
  auto listener=getMainListener();
rpm-build 6f7582
  if (!listener) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::sendText: can not find the listener\n"));
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  listener->setFont(m_state->m_font);
rpm-build 6f7582
  auto input=getInput();
rpm-build 6f7582
  input->seek(entry.begin(), librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  for (long l=0; l
rpm-build 6f7582
    if (input->isEnd()) {
rpm-build 6f7582
      MWAW_DEBUG_MSG(("MultiplanParser::sendText: oops, can not read a character\n"));
rpm-build 6f7582
      break;
rpm-build 6f7582
    }
rpm-build 6f7582
    auto c=static_cast<unsigned char>(input->readULong(1));
rpm-build 6f7582
    if (c==0x9)
rpm-build 6f7582
      listener->insertTab();
rpm-build 6f7582
    else if (c==0xa || c==0xd)
rpm-build 6f7582
      listener->insertEOL();
rpm-build 6f7582
    else
rpm-build 6f7582
      listener->insertCharacter(c);
rpm-build 6f7582
  }
rpm-build 6f7582
  return true;
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
bool MultiplanParser::sendCell(MWAWVec2i const &cellPos, int p)
rpm-build 6f7582
{
rpm-build 6f7582
  MWAWSpreadsheetListenerPtr listener=getSpreadsheetListener();
rpm-build 6f7582
  if (!listener) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::sendCell: I can not find the listener\n"));
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  auto const &entry=m_state->m_entries[6];
rpm-build 6f7582
  if (p<=0 || p>entry.length()) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::sendCell: unexpected position %d\n", p));
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  MWAWCell cell;
rpm-build 6f7582
  MWAWCellContent content;
rpm-build 6f7582
  MWAWCell::Format format;
rpm-build 6f7582
  cell.setPosition(cellPos);
rpm-build 6f7582
  cell.setFont(m_state->m_font);
rpm-build 6f7582
  libmwaw::DebugStream f;
rpm-build 6f7582
  f << "DataCell[C" << cellPos[0]+1 << "R" << cellPos[1]+1 << "]:";
rpm-build 6f7582
  long pos=entry.begin()+p;
rpm-build 6f7582
  auto it=m_state->m_cellPositionsSet.find(p);
rpm-build 6f7582
  ++it;
rpm-build 6f7582
  long endPos=it!=m_state->m_cellPositionsSet.end() ? entry.begin()+*it : entry.end();
rpm-build 6f7582
  if (endPos-pos<4) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::sendCell: a cell %d seems to short\n", p));
rpm-build 6f7582
    f << "###";
rpm-build 6f7582
    ascii().addPos(pos);
rpm-build 6f7582
    ascii().addNote(f.str().c_str());
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  auto input=getInput();
rpm-build 6f7582
  input->seek(pos, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  int formSize=int(input->readULong(1));
rpm-build 6f7582
  if (formSize) f << "form[size]=" << std::hex << formSize << std::dec << ",";
rpm-build 6f7582
  int val=int(input->readULong(1));
rpm-build 6f7582
  int digits=(val&0xf);
rpm-build 6f7582
  if (digits) f << "decimal=" << digits << ",";
rpm-build 6f7582
  int form=(val>>4)&7;
rpm-build 6f7582
  format.m_numberFormat=MWAWCell::F_NUMBER_GENERIC;
rpm-build 6f7582
  switch (form) {
rpm-build 6f7582
  case 2:
rpm-build 6f7582
    format.m_numberFormat=MWAWCell::F_NUMBER_SCIENTIFIC;
rpm-build 6f7582
    format.m_digits=digits;
rpm-build 6f7582
    f << "scientific,";
rpm-build 6f7582
    break;
rpm-build 6f7582
  case 3:
rpm-build 6f7582
    format.m_numberFormat=MWAWCell::F_NUMBER_DECIMAL;
rpm-build 6f7582
    format.m_digits=digits;
rpm-build 6f7582
    f << "decimal,";
rpm-build 6f7582
    break;
rpm-build 6f7582
  case 4: // default
rpm-build 6f7582
    break;
rpm-build 6f7582
  case 5:
rpm-build 6f7582
    format.m_numberFormat=MWAWCell::F_NUMBER_CURRENCY;
rpm-build 6f7582
    format.m_digits=digits;
rpm-build 6f7582
    f << "currency,";
rpm-build 6f7582
    break;
rpm-build 6f7582
  case 6: // a bar
rpm-build 6f7582
    f << "bar,";
rpm-build 6f7582
    break;
rpm-build 6f7582
  case 7:
rpm-build 6f7582
    format.m_numberFormat=MWAWCell::F_NUMBER_PERCENT;
rpm-build 6f7582
    format.m_digits=digits;
rpm-build 6f7582
    f << "percent,";
rpm-build 6f7582
    break;
rpm-build 6f7582
  default:
rpm-build 6f7582
    f << "format=" << form << ",";
rpm-build 6f7582
    break;
rpm-build 6f7582
  }
rpm-build 6f7582
  cell.setProtected((val&0x80)!=0);
rpm-build 6f7582
  if ((val&0x80)==0) f << "no[protection],";
rpm-build 6f7582
  val=int(input->readULong(1));
rpm-build 6f7582
  int align=(val>>2)&7;
rpm-build 6f7582
  switch (align) {
rpm-build 6f7582
  case 1:
rpm-build 6f7582
    cell.setHAlignment(cell.HALIGN_CENTER);
rpm-build 6f7582
    f << "center,";
rpm-build 6f7582
    break;
rpm-build 6f7582
  case 0: // default
rpm-build 6f7582
  case 2: // generic
rpm-build 6f7582
    break;
rpm-build 6f7582
  case 3:
rpm-build 6f7582
    cell.setHAlignment(cell.HALIGN_LEFT);
rpm-build 6f7582
    f << "left,";
rpm-build 6f7582
    break;
rpm-build 6f7582
  case 4:
rpm-build 6f7582
    cell.setHAlignment(cell.HALIGN_RIGHT);
rpm-build 6f7582
    f << "right,";
rpm-build 6f7582
    break;
rpm-build 6f7582
  default:
rpm-build 6f7582
    f << "#align=" << (align) << ",";
rpm-build 6f7582
    break;
rpm-build 6f7582
  }
rpm-build 6f7582
  switch (val&3) {
rpm-build 6f7582
  case 0:
rpm-build 6f7582
    f << "double,";
rpm-build 6f7582
    format.m_format=MWAWCell::F_NUMBER;
rpm-build 6f7582
    content.m_contentType=content.C_NUMBER;
rpm-build 6f7582
    break;
rpm-build 6f7582
  case 1:
rpm-build 6f7582
    format.m_format=MWAWCell::F_TEXT;
rpm-build 6f7582
    content.m_contentType=content.C_TEXT;
rpm-build 6f7582
    f << "text,";
rpm-build 6f7582
    break;
rpm-build 6f7582
  case 2:
rpm-build 6f7582
    format.m_format=MWAWCell::F_NUMBER;
rpm-build 6f7582
    content.m_contentType=content.C_NUMBER;
rpm-build 6f7582
    f << "nan,";
rpm-build 6f7582
    break;
rpm-build 6f7582
  case 3: // or nothing
rpm-build 6f7582
    format.m_format=MWAWCell::F_BOOLEAN;
rpm-build 6f7582
    content.m_contentType=content.C_NUMBER;
rpm-build 6f7582
    f << "bool,";
rpm-build 6f7582
    break;
rpm-build 6f7582
  default: // impossible
rpm-build 6f7582
    break;
rpm-build 6f7582
  }
rpm-build 6f7582
  cell.setFormat(format);
rpm-build 6f7582
  if ((val&0x20)==0)
rpm-build 6f7582
    f << "no20[f1],";
rpm-build 6f7582
  if (val&0x40)
rpm-build 6f7582
    f << "shared,";
rpm-build 6f7582
  int type=(val&0xe3);
rpm-build 6f7582
  if (val&0x80) f << "80[f1],";
rpm-build 6f7582
  int dSz=int(input->readULong(1));
rpm-build 6f7582
  if (endPos
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::sendCell: a cell seems to short\n"));
rpm-build 6f7582
    f << "###";
rpm-build 6f7582
    ascii().addPos(pos);
rpm-build 6f7582
    ascii().addNote(f.str().c_str());
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  if ((type&0x3)==0 && dSz==8) {
rpm-build 6f7582
    double value;
rpm-build 6f7582
    if (!readDouble(value))
rpm-build 6f7582
      f << "###";
rpm-build 6f7582
    else
rpm-build 6f7582
      content.setValue(value);
rpm-build 6f7582
    f << value << ",";
rpm-build 6f7582
  }
rpm-build 6f7582
  else if ((type&0x3)==1 && dSz && pos+4+dSz+((type&0x40) ? 2 : 0) <= endPos) {
rpm-build 6f7582
    content.m_textEntry.setBegin(input->tell());
rpm-build 6f7582
    content.m_textEntry.setLength(dSz);
rpm-build 6f7582
    std::string name;
rpm-build 6f7582
    for (int c=0; c<dSz; ++c) name+=char(input->readULong(1));
rpm-build 6f7582
    f << name << ",";
rpm-build 6f7582
  }
rpm-build 6f7582
  else if ((type&0x3)==2 && dSz==8) {
rpm-build 6f7582
    content.setValue(std::nan(""));
rpm-build 6f7582
    f << "Nan" << input->readULong(1) << ",";
rpm-build 6f7582
    input->seek(7, librevenge::RVNG_SEEK_CUR);
rpm-build 6f7582
  }
rpm-build 6f7582
  else if ((type&0x3)==3 && dSz==8) {
rpm-build 6f7582
    val=int(input->readULong(1));
rpm-build 6f7582
    content.setValue(val);
rpm-build 6f7582
    if (val==0)
rpm-build 6f7582
      f << "false,";
rpm-build 6f7582
    else if (val==1)
rpm-build 6f7582
      f << "true,";
rpm-build 6f7582
    else
rpm-build 6f7582
      f << "##bool=" << val << ",";
rpm-build 6f7582
    input->seek(7, librevenge::RVNG_SEEK_CUR);
rpm-build 6f7582
  }
rpm-build 6f7582
  if ((type&0x40) && input->tell()+2<=endPos && (formSize==0 || formSize==2)) {
rpm-build 6f7582
    if ((input->tell()-pos)%2)
rpm-build 6f7582
      input->seek(1, librevenge::RVNG_SEEK_CUR);
rpm-build 6f7582
    int nPos=int(input->readULong(2));
rpm-build 6f7582
    if (!readSharedData(nPos, type, cellPos, content))
rpm-build 6f7582
      f << "###";
rpm-build 6f7582
    f << "sharedData-" << std::hex << nPos << std::dec << ",";
rpm-build 6f7582
  }
rpm-build 6f7582
  else if (!(type&0x40) && formSize && input->tell()+formSize<=endPos) {
rpm-build 6f7582
    auto endFPos=input->tell()+formSize;
rpm-build 6f7582
    std::string err;
rpm-build 6f7582
    if (!readFormula(cellPos, content.m_formula, endFPos, err)) {
rpm-build 6f7582
      ascii().addDelimiter(input->tell(),'|');
rpm-build 6f7582
      f << "###";
rpm-build 6f7582
    }
rpm-build 6f7582
    else
rpm-build 6f7582
      content.m_contentType=content.C_FORMULA;
rpm-build 6f7582
rpm-build 6f7582
    for (auto const &fo : content.m_formula) f << fo;
rpm-build 6f7582
    f << ",";
rpm-build 6f7582
    f << err;
rpm-build 6f7582
    input->seek(endFPos, librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
  }
rpm-build 6f7582
  else if (formSize) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::sendCell: can not read a formula\n"));
rpm-build 6f7582
    f << "###form";
rpm-build 6f7582
  }
rpm-build 6f7582
  listener->openSheetCell(cell, content);
rpm-build 6f7582
  if (content.m_textEntry.valid()) {
rpm-build 6f7582
    listener->setFont(cell.getFont());
rpm-build 6f7582
    input->seek(content.m_textEntry.begin(), librevenge::RVNG_SEEK_SET);
rpm-build 6f7582
    while (!input->isEnd() && input->tell()
rpm-build 6f7582
      auto c=static_cast<unsigned char>(input->readULong(1));
rpm-build 6f7582
      if (c==0x9)
rpm-build 6f7582
        listener->insertTab();
rpm-build 6f7582
      else if (c==0xa || c==0xd)
rpm-build 6f7582
        listener->insertEOL();
rpm-build 6f7582
      else
rpm-build 6f7582
        listener->insertCharacter(c);
rpm-build 6f7582
    }
rpm-build 6f7582
  }
rpm-build 6f7582
  listener->closeSheetCell();
rpm-build 6f7582
  if (input->tell()!=endPos)
rpm-build 6f7582
    ascii().addDelimiter(input->tell(),'|');
rpm-build 6f7582
  ascii().addPos(pos);
rpm-build 6f7582
  ascii().addNote(f.str().c_str());
rpm-build 6f7582
  return true;
rpm-build 6f7582
}
rpm-build 6f7582
rpm-build 6f7582
bool MultiplanParser::sendSpreadsheet()
rpm-build 6f7582
{
rpm-build 6f7582
  MWAWSpreadsheetListenerPtr listener=getSpreadsheetListener();
rpm-build 6f7582
  if (!listener) {
rpm-build 6f7582
    MWAW_DEBUG_MSG(("MultiplanParser::sendSpreadsheet: I can not find the listener\n"));
rpm-build 6f7582
    return false;
rpm-build 6f7582
  }
rpm-build 6f7582
  listener->openSheet(m_state->getColumnsWidth(), librevenge::RVNG_POINT, std::vector<int>(), "Sheet0");
rpm-build 6f7582
  auto const &dataEntry=m_state->m_entries[6];
rpm-build 6f7582
  m_state->m_cellPositionsSet.insert(int(dataEntry.length()));
rpm-build 6f7582
  for (size_t r=0; r<m_state->m_cellPositions.size(); ++r) {
rpm-build 6f7582
    auto const &row = m_state->m_cellPositions[r];
rpm-build 6f7582
    listener->openSheetRow(-16.f, librevenge::RVNG_POINT);
rpm-build 6f7582
    for (size_t col=0; col
rpm-build 6f7582
      auto p=row[col];
rpm-build 6f7582
      if (p<0 || p>dataEntry.length()) {
rpm-build 6f7582
        MWAW_DEBUG_MSG(("MultiplanParser::sendSpreadsheet: find some bad data\n"));
rpm-build 6f7582
        continue;
rpm-build 6f7582
      }
rpm-build 6f7582
      if (!p) continue;
rpm-build 6f7582
      MWAWVec2i cellPos(static_cast<int>(col), static_cast<int>(r));
rpm-build 6f7582
      sendCell(cellPos, p);
rpm-build 6f7582
    }
rpm-build 6f7582
    listener->closeSheetRow();
rpm-build 6f7582
  }
rpm-build 6f7582
  listener->closeSheet();
rpm-build 6f7582
  return true;
rpm-build 6f7582
}
rpm-build 6f7582
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: