/* -*- 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 <array>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <set>
#include <sstream>

#include <librevenge/librevenge.h>

#include "MWAWFont.hxx"
#include "MWAWFontConverter.hxx"
#include "MWAWGraphicListener.hxx"
#include "MWAWGraphicShape.hxx"
#include "MWAWParagraph.hxx"
#include "MWAWPictData.hxx"
#include "MWAWPosition.hxx"
#include "MWAWSubDocument.hxx"

#include "ReadySetGoParser.hxx"
#include "ReadySetGoStyleManager.hxx"

#include "ReadySetGoGraph.hxx"

/** Internal: the structures of a ReadySetGoGraph */
namespace ReadySetGoGraphInternal
{
////////////////////////////////////////
//! Internal: a shape in a ReadySetGoGraph document
struct Shape {
  //! the shape type
  enum Type { T_Empty, T_Line, T_Oval, T_Picture, T_Polygon, T_Rectangle, T_RectOval, T_Text, T_Unknown };
  //! constructor
  explicit Shape(Type type)
    : m_type(type)
    , m_box()
    , m_rotate(0)
    , m_style(MWAWGraphicStyle::emptyStyle())
    , m_groupId(0)
    , m_wrapRoundAround(false)
    , m_cornerSize(-1,-1)
    , m_vertices()
    , m_textId(-1)
    , m_paragraph()
    , m_hasPicture(false)
  {
    for (auto &link : m_linkIds) link=-1;
    for (auto &cPos : m_textPositions) cPos=-1;
  }

  //! the shape type
  Type m_type;
  //! the bounding box
  MWAWBox2f m_box;
  //! the shape rotation: v6
  int m_rotate;
  //! the graphic style
  MWAWGraphicStyle m_style;
  //! the group id: v6
  int m_groupId; // FIXME: useme
  //! the round around wraping flag
  bool m_wrapRoundAround;
  //! the line points
  MWAWVec2f m_points[2];
  //! the corner size: rectangle oval
  MWAWVec2i m_cornerSize;
  //! the list of vertices : polygon
  std::vector<MWAWVec2f> m_vertices;

  //! the text limits: v4
  int m_textPositions[2];
  //! the text link id
  int m_textId;
  //! the text links: prev/next
  int m_linkIds[2];
  //! the paragraph style
  MWAWParagraph m_paragraph;

  //! a flag to know if a picture is empty or not
  bool m_hasPicture;

  //! the zone entries: picture or text zones
  MWAWEntry m_entries[3];
};

////////////////////////////////////////
//! Internal: a layout in a ReadySetGoGraph document
struct Layout {
  //! constructor
  Layout()
    : m_useMasterPage(true)
    , m_masterId(0)
    , m_shapes()
  {
  }

  //! a flag to know if we use or not the master page
  bool m_useMasterPage;
  //! the master id: v6
  int m_masterId;
  //! a map id to shape
  std::vector<Shape> m_shapes;
};

////////////////////////////////////////
//! Internal: the state of a ReadySetGoGraph
struct State {
  //! constructor
  State()
    : m_version(-1)
    , m_layouts()
    , m_masterLayouts()
  {
  }

  //! the file version
  int m_version;
  //! the list of layout (one by potential master + page)
  std::vector<Layout> m_layouts;
  //! the list of master layouts: v6
  std::vector<Layout> m_masterLayouts;
};

////////////////////////////////////////
//! Internal: the subdocument of a ReadySetGoGraph
class SubDocument final : public MWAWSubDocument
{
public:
  SubDocument(ReadySetGoGraph &pars, MWAWInputStreamPtr const &input, Shape const &shape)
    : MWAWSubDocument(&pars.m_parser, input, MWAWEntry())
    , m_graphParser(&pars)
    , m_shape(&shape)
  {
  }

  //! destructor
  ~SubDocument() final {}

  //! operator!=
  bool operator!=(MWAWSubDocument const &doc) const final
  {
    if (MWAWSubDocument::operator!=(doc)) return true;
    auto const *sDoc = dynamic_cast<SubDocument const *>(&doc);
    if (!sDoc) return true;
    if (m_graphParser != sDoc->m_graphParser) return true;
    if (m_shape != sDoc->m_shape) return true;
    return false;
  }

  //! the parser function
  void parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType type) final;

protected:
  /** the graph parser */
  ReadySetGoGraph *m_graphParser;
  //! the text shape
  Shape const *m_shape;
private:
  SubDocument(SubDocument const &orig) = delete;
  SubDocument &operator=(SubDocument const &orig) = delete;
};

void SubDocument::parse(MWAWListenerPtr &listener, libmwaw::SubDocumentType /*type*/)
{
  if (!listener || !listener->canWriteText()) {
    MWAW_DEBUG_MSG(("ReadySetGoParserInternal::SubDocument::parse: no listener\n"));
    return;
  }
  if (!m_graphParser || !m_shape) {
    MWAW_DEBUG_MSG(("ReadySetGoParserInternal::SubDocument::parse: no parser\n"));
    return;
  }
  long pos = m_input->tell();
  m_graphParser->sendText(*m_shape);
  m_input->seek(pos, librevenge::RVNG_SEEK_SET);
}

}

////////////////////////////////////////////////////////////
// constructor/destructor, ...
////////////////////////////////////////////////////////////
ReadySetGoGraph::ReadySetGoGraph(ReadySetGoParser &parser)
  : m_state(new ReadySetGoGraphInternal::State)
  , m_parser(parser)
  , m_styleManager(parser.m_styleManager)
{
}

ReadySetGoGraph::~ReadySetGoGraph()
{
}

int ReadySetGoGraph::version() const
{
  if (m_state->m_version==-1)
    m_state->m_version=m_parser.version();
  return m_state->m_version;
}

void ReadySetGoGraph::updatePageSpanList(std::vector<MWAWPageSpan> &spanList) const
{
  // create the page list
  int const vers=version();
  int num=int(m_state->m_layouts.size());
  if (vers>=3)
    num=std::max<int>(0,num-2);
  if (vers<3) {
    MWAWPageSpan ps(m_parser.getPageSpan());
    ps.setPageSpan(std::max<int>(1,num));
    spanList.push_back(ps);
  }
  else {
    bool const sharedList=vers<6 || (vers==6 && m_parser.isDesignStudioFile());
    std::vector<std::array<bool,2> > hasMasters;
    size_t numMasters=!sharedList ? (m_state->m_masterLayouts.size()+1)/2 : 1;
    hasMasters.resize(numMasters);
    for (auto &hasMaster : hasMasters) hasMaster= {{false, false}};
    if (sharedList) {
      for (size_t i=0; i<2; ++i)
        hasMasters[0][i]=!m_state->m_layouts[i].m_shapes.empty();
    }
    else {
      for (size_t i=0; i<m_state->m_masterLayouts.size(); ++i)
        hasMasters[i/2][i%2] =!m_state->m_masterLayouts[i].m_shapes.empty();
    }
    for (size_t i=(sharedList ? 2 : 0); i<m_state->m_layouts.size(); ++i) {
      auto const &layout=m_state->m_layouts[i];
      MWAWPageSpan ps(m_parser.getPageSpan());
      ps.setPageSpan(1);
      int whichMaster= !sharedList ? layout.m_masterId : 0;
      if (layout.m_useMasterPage && whichMaster>=0 && whichMaster<int(hasMasters.size()) && hasMasters[size_t(whichMaster)][(i+1)%2]) {
        librevenge::RVNGString name;
        name.sprintf("MasterPage%d", 2*whichMaster+int((i+1)%2));
        ps.setMasterPageName(name);
      }
      spanList.push_back(ps);
    }
  }
}

bool ReadySetGoGraph::updateTextBoxLinks()
{
  int const vers=version();
  if (vers<=2)
    return true;
  std::map<int, ReadySetGoGraphInternal::Shape *> idToShapeMap;
  std::map<int, int> idToLinkIdsMap[2];
  for (int st=0; st<2; ++st) {
    auto &layouts = st==0 ?  m_state->m_layouts : m_state->m_masterLayouts;
    for (auto &layout : layouts) {
      for (auto &shape : layout.m_shapes) {
        if (shape.m_linkIds[0]<0 && shape.m_linkIds[1]<0)
          continue;
        if (idToShapeMap.find(shape.m_textId)!=idToShapeMap.end()) {
          MWAW_DEBUG_MSG(("ReadySetGoGraph::updateTextBoxLinks: find dupplicated text id=%d\n", shape.m_textId));
          return false;
        }
        idToShapeMap[shape.m_textId]=&shape;
        for (int i=0; i<2; ++i) {
          if (shape.m_linkIds[i]<0) continue;
          if (idToLinkIdsMap[i].find(shape.m_linkIds[i])!=idToLinkIdsMap[i].end()) {
            MWAW_DEBUG_MSG(("ReadySetGoGraph::updateTextBoxLinks[%d]: find dupplicated text id=%d\n", i, shape.m_linkIds[i]));
            return false;
          }
          idToLinkIdsMap[i][shape.m_linkIds[i]]=shape.m_textId;
        }
      }
    }
  }

  // check that the link are coherent, ie. for each link, there exists a reciprocal link
  for (auto st=0; st<2; ++st) {
    std::set<int> badIds;
    for (auto const &it : idToLinkIdsMap[st]) {
      auto rIt=idToLinkIdsMap[1-st].find(it.second);
      if (rIt==idToLinkIdsMap[1-st].end() || rIt->second!=it.first) {
        MWAW_DEBUG_MSG(("ReadySetGoGraph::updateTextBoxLinks: find no reciprocal link for link=%d-%d\n", it.first, it.second));
        badIds.insert(it.first);
      }
    }
    for (auto bad : badIds)
      idToLinkIdsMap[st].erase(bad);
  }

  // check that there is no loop: following next path
  for (auto const &iIt : idToShapeMap) {
    std::set<int> ids;
    int id=iIt.first, firstId=id;
    bool ok=true;
    while (true) {
      if (ids.find(id)!=ids.end()) {
        ok=false;
        MWAW_DEBUG_MSG(("ReadySetGoGraph::updateTextBoxLinks: find a loop for link id=%d\n", id));
        break;
      }
      ids.insert(id);
      auto const &nextIt=idToLinkIdsMap[1].find(id);
      if (nextIt==idToLinkIdsMap[1].end())
        break;
      id=nextIt->second;
    }
    if (ok) continue;
    // ok: remove this loop
    id=firstId;
    while (true) {
      auto const &nextIt=idToLinkIdsMap[1].find(id);
      if (nextIt==idToLinkIdsMap[1].end())
        break;
      int nextId=nextIt->second;
      idToLinkIdsMap[1].erase(id);
      idToLinkIdsMap[0].erase(nextId);
      id=nextId;
    }
  }

  if (vers<4) {
    // update the shape's style name
    for (auto const &iIt : idToShapeMap) {
      auto &shape=*iIt.second;
      int prevId=shape.m_linkIds[0];
      if (prevId>=0 && idToLinkIdsMap[0].find(prevId)!=idToLinkIdsMap[0].end()) {
        std::stringstream s;
        s << "Frame" << iIt.first;
        shape.m_style.m_frameName=s.str();
      }
      int nextId=shape.m_linkIds[1];
      if (nextId>=0 && idToLinkIdsMap[1].find(nextId)!=idToLinkIdsMap[1].end()) {
        std::stringstream s;
        s << "Frame" << nextId;
        shape.m_style.m_frameNextName=s.str();
      }
    }
  }
  else {
    for (auto const &iIt : idToShapeMap) {
      auto &shape=*iIt.second;
      if (shape.m_linkIds[0]>=0 || shape.m_linkIds[1]<0) continue;
      // shape is the first node of a loop
      int nextId=shape.m_linkIds[1];
      auto *currentShape=&shape;
      while (nextId>=0) {
        if (idToLinkIdsMap[1].find(nextId)==idToLinkIdsMap[1].end()) // the link has been cutted
          break;
        auto nextShapeIt=idToShapeMap.find(nextId);
        if (nextShapeIt==idToShapeMap.end()) {
          MWAW_DEBUG_MSG(("ReadySetGoGraph::updateTextBoxLinks: can not find shape corresponding to id=%d\n", nextId));
          break;
        }
        auto *nextShape=nextShapeIt->second;
        for (int l=0; l<3; ++l) // update the shape entries
          nextShape->m_entries[l]=shape.m_entries[l];
        nextId=nextShape->m_linkIds[1];
        if (currentShape->m_textPositions[1]>=nextShape->m_textPositions[0]-1)
          currentShape->m_textPositions[1]=std::max(0,nextShape->m_textPositions[0]-1);
        else if (currentShape->m_textPositions[1]<nextShape->m_textPositions[0]-10) { // a difference of 2 characters seems ok
          MWAW_DEBUG_MSG(("ReadySetGoGraph::updateTextBoxLinks: can not update the text limits\n"));
        }
        currentShape=nextShape;
      }
    }
  }
  return true;
}

////////////////////////////////////////////////////////////
//
// Intermediate level
//
////////////////////////////////////////////////////////////
bool ReadySetGoGraph::readLayoutsList(int numLayouts, bool master)
{
  int const vers=version();
  if (vers<3) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readLayoutsList: unexpected version\n"));
    return false;
  }
  MWAWInputStreamPtr input = m_parser.getInput();
  if (!input)
    return false;
  long pos=input->tell();
  if (!input->checkPosition(pos+4)) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readLayoutsList: can not read the zone length\n"));
    return false;
  }
  libmwaw::DebugFile &ascFile = m_parser.ascii();
  libmwaw::DebugStream f;
  bool const designStudio=m_parser.isDesignStudioFile();
  f << "Entries(Layout):";
  long len=long(input->readLong(4));
  long endPos=pos+4+len;
  int const dataSize=vers==3 ? 10 : vers==4 ? 14 : vers==5 ? 136 : (designStudio ? 210 : 212);
  if (len<0 || len/dataSize<numLayouts || endPos<pos+4 || !input->checkPosition(endPos)) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readLayoutsList: can not read the zone length\n"));
    f << "###";
    ascFile.addPos(pos);
    ascFile.addNote(f.str().c_str());
    return false;
  }
  f << "N=" << numLayouts << ",";
  ascFile.addPos(pos);
  ascFile.addNote(f.str().c_str());
  std::vector<ReadySetGoGraphInternal::Layout> &layouts= master ? m_state->m_masterLayouts : m_state->m_layouts;
  for (int l=0; l<numLayouts; ++l) { // LR,1:R,2:L,...
    pos=input->tell();
    f.str("");
    f << "Layout-" << (master ? "M" : "L") << l << ":";
    layouts.push_back(ReadySetGoGraphInternal::Layout());
    auto &layout=layouts.back();
    if (vers==3) {
      for (int i=0; i<2; ++i) { // f0=0 or 8(rare)
        int val=int(input->readLong(2));
        if (val)
          f << "f" << i << "=" << val << ",";
      }
    }
    else {
      int dim[4];
      for (auto &d : dim) d=int(input->readLong(2));
      if (dim[2]!=dim[0] || dim[3]!=dim[1])
        f << "box?=" << MWAWBox2i(MWAWVec2i(dim[0],dim[1]), MWAWVec2i(dim[2],dim[3])) << ",";
    }
    int val=int(input->readULong(4));
    if (val)
      f << "ID=" << std::hex << val << std::dec << ","; // last shape id in layout?
    val=int(input->readULong(2)); // 1|3
    if ((val&1)==0) {
      f << "use[master]=false,";
      layout.m_useMasterPage=false;
    }
    val &= 0xfffe;
    if (val)
      f << "fl=" << std::hex << val << std::dec << ",";
    if (vers>=6 && !designStudio) {
      ascFile.addDelimiter(input->tell(),'|');
      input->seek(pos+210, librevenge::RVNG_SEEK_SET);
      ascFile.addDelimiter(input->tell(),'|');
      layout.m_masterId=int(input->readULong(2));
      if (layout.m_masterId)
        f << "master=" << layout.m_masterId << ",";
    }
    if (input->tell()!=pos+dataSize)
      ascFile.addDelimiter(input->tell(),'|');
    input->seek(pos+dataSize, librevenge::RVNG_SEEK_SET);
    ascFile.addPos(pos);
    ascFile.addNote(f.str().c_str());
  }

  if (input->tell()!=endPos) {
    if (!master) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::readLayoutsList: find extra data\n"));
      ascFile.addPos(input->tell());
      ascFile.addNote("Layout-extra:###");
    }
    else {
      ascFile.addPos(input->tell());
      ascFile.addNote("_");
    }
  }
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
  return true;
}

bool ReadySetGoGraph::readShapes()
{
  MWAWInputStreamPtr input = m_parser.getInput();
  if (!input)
    return false;
  long pos=input->tell();

  int const vers=version();
  libmwaw::DebugFile &ascFile = m_parser.ascii();
  libmwaw::DebugStream f;
  if (vers<=2) {
    f << "Entries(Pages):";
    if (!input->checkPosition(pos+2)) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapes: the zone seems too short\n"));
      f << "###";
      ascFile.addPos(pos);
      ascFile.addNote(f.str().c_str());
      return false;
    }
    int numPages=1;
    if (vers==2) {
      numPages=int(input->readULong(2));
      if (!input->checkPosition(pos+2+2*numPages)) {
        MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapes: the zone seems too short\n"));
        f << "###N=" << numPages << ",";
        ascFile.addPos(pos);
        ascFile.addNote(f.str().c_str());
        return false;
      }
      ascFile.addPos(pos);
      ascFile.addNote(f.str().c_str());
    }
    std::vector<int> numShapesByPage;
    f << "N=[";
    for (int i=0; i<numPages; ++i) {
      numShapesByPage.push_back(int(input->readULong(2)));
      f << numShapesByPage.back();
    }
    f << "],";
    ascFile.addPos(pos);
    ascFile.addNote(f.str().c_str());

    for (size_t p=0; p<size_t(numPages); ++p) {
      m_state->m_layouts.push_back(ReadySetGoGraphInternal::Layout());
      auto &layout=m_state->m_layouts.back();
      for (int sh=0; sh<numShapesByPage[p]; ++sh) {
        pos=input->tell();
        if (vers==1) {
          if (readShapeV1() && !layout.m_shapes.empty() &&
              (layout.m_shapes.back().m_type!=ReadySetGoGraphInternal::Shape::T_Empty || sh+1==numShapesByPage[p]))
            continue;
          MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapes: can not read a shape\n"));
          ascFile.addPos(pos);
          ascFile.addNote("Entries(BadShape):###");
          return false;
        }
        else if (!readShapeV2(layout))
          return false;
      }
    }
    return true;
  }

  // Design Studio v2
  if (m_parser.isDesignStudioFile()) {
    for (auto &layout : m_state->m_layouts) {
      while (!input->isEnd()) {
        bool last;
        if (!readShapeDSV2(layout, last))
          return false;
        if (last)
          break;
      }
    }
    updateTextBoxLinks();
    return true;
  }
  // v3, v4, v4.5
  if (vers<=5) {
    for (auto &layout : m_state->m_layouts) {
      while (!input->isEnd()) {
        bool last;
        if (!readShapeV3(layout, last))
          return false;
        if (last)
          break;
      }
    }
    updateTextBoxLinks();
    return true;
  }
  // v6
  // normally two layouts by master labelled from 'A'-'Z'
  for (size_t i=0; i<m_state->m_masterLayouts.size(); ++i) {
    while (!input->isEnd()) {
      bool last;
      if (!readShapeV6(m_state->m_masterLayouts[i], last))
        return false;
      if (last)
        break;
    }
  }
  // followed by num layouts-2,
  // I supposed that layouts 0 and 1 remain only to be "coherent" with v4.5 format
  for (size_t i=2; i<m_state->m_layouts.size(); ++i) {
    while (!input->isEnd()) {
      bool last;
      if (!readShapeV6(m_state->m_layouts[i], last))
        return false;
      if (last)
        break;
    }
  }
  updateTextBoxLinks();
  return true;
}

bool ReadySetGoGraph::readShapesInObject()
{
  if (version()<6) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapesInObject: unexpected version\n"));
    return false;
  }
  MWAWInputStreamPtr input = m_parser.getInput();
  if (!input)
    return false;
  ReadySetGoGraphInternal::Layout dummy;
  if (m_parser.isDesignStudioFile()) {
    while (!input->isEnd()) {
      bool last;
      if (!readShapeDSV2(dummy, last))
        return false;
      if (last)
        break;
    }
  }
  else {
    while (!input->isEnd()) {
      bool last;
      if (!readShapeV6(dummy, last))
        return false;
      if (last)
        break;
    }
  }
  return true;
}


////////////////////////////////////////////////////////////
// low level
////////////////////////////////////////////////////////////
bool ReadySetGoGraph::readShapeV1()
{
  MWAWInputStreamPtr input = m_parser.getInput();
  if (!input)
    return false;
  long pos=input->tell();
  if (!input->checkPosition(pos+26)) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV1: can not read a shape\n"));
    return false;
  }
  if (m_state->m_layouts.empty()) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV1: oops, must create a new layout\n"));
    m_state->m_layouts.resize(1);
  }
  int type=int(input->readULong(2));

  static char const *wh[]= {"EndZone", "Text", nullptr, "Frame", "Solid", "Picture"};
  if (type<0 || type==2 || type>5) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV1: unknown type\n"));
    return false;
  }
  libmwaw::DebugFile &ascFile = m_parser.ascii();
  libmwaw::DebugStream f;
  if (wh[type])
    f << "Entries(" << wh[type] << "):";
  else
    f << "Entries(Zone" << type << "):";
  int const expectedSize[]= {26, 74, 0, 30, 28, 28};
  if (expectedSize[type]<=0 || !input->checkPosition(pos+expectedSize[type])) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV1: the zone seems too short for a shape\n"));
    f << "###";
    ascFile.addPos(pos);
    ascFile.addNote(f.str().c_str());
    return false;
  }
  static ReadySetGoGraphInternal::Shape::Type const shapeTypes[]= {
    ReadySetGoGraphInternal::Shape::T_Empty,
    ReadySetGoGraphInternal::Shape::T_Text,
    ReadySetGoGraphInternal::Shape::T_Unknown,
    ReadySetGoGraphInternal::Shape::T_Rectangle, // frame
    ReadySetGoGraphInternal::Shape::T_Rectangle, // solid
    ReadySetGoGraphInternal::Shape::T_Picture
  };
  ReadySetGoGraphInternal::Shape shape(shapeTypes[type]);
  float dim[4];
  for (auto &d : dim) d=float(input->readLong(2));
  shape.m_box=MWAWBox2f(MWAWVec2f(dim[0],dim[1]), MWAWVec2f(dim[0]+dim[2],dim[1]+dim[3]));
  f << "box=" << shape.m_box << ",";
  if (type!=0) {
    for (auto &d : dim) {
      d=float(input->readLong(2));
      d+=float(input->readLong(2))/10000;
    }
    f << "box[inch]=" << MWAWBox2f(MWAWVec2f(dim[0],dim[1]), MWAWVec2f(dim[0]+dim[2],dim[1]+dim[3])) << ",";
    int val;
    if (type==3) {
      val=int(input->readLong(2));
      if (val<0 || val>100) {
        MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV1: the frame size seems bad\n"));
        f << "###";
      }
      else
        shape.m_style.m_lineWidth=float(val);
      if (val!=1)
        f << "frame[size]=" << val << ",";
    }
    if (type==5) {
      val=int(input->readLong(2));
      shape.m_hasPicture=val!=0;
      if (val==0)
        f <<"noPict,";
      else if (val!=1)
        f << "###pict=" << val << ",";
    }
    else if (type!=1) {
      val=int(input->readLong(2));
      if (val<0 || val>4) {
        MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV1: the color id seems bad\n"));
        f << "###col=" << val << ",";
      }
      else {
        uint8_t grey=uint8_t(val==0 ? 255 : 32*val);
        if (type==3)
          shape.m_style.m_lineColor=MWAWColor(grey,grey,grey);
        else
          shape.m_style.setSurfaceColor(MWAWColor(grey,grey,grey));
        f << "color="  << val << ","; // 0: none, 1: black, 2: grey1, .., 4: light grey
      }
    }
    else {
      shape.m_paragraph.m_marginsUnit=librevenge::RVNG_INCH;
      for (int i=0; i<2; ++i) { // 0
        val=int(input->readLong(2));
        shape.m_paragraph.m_margins[1-i]=float(val)+float(input->readULong(2))/10000;
        if (*shape.m_paragraph.m_margins[1-i]>0) f << (i==0 ? "para" : "left") << "[indent]=" << *shape.m_paragraph.m_margins[1-i] << ",";
      }
      shape.m_paragraph.m_margins[0]=*shape.m_paragraph.m_margins[0]-*shape.m_paragraph.m_margins[1];
      std::string extra;
      m_styleManager->readTabulationsV1(*shape.m_paragraph.m_tabs, extra);
      f << extra;
    }
  }
  if (input->tell()!=pos+expectedSize[type]) {
    ascFile.addDelimiter(input->tell(),'|');
    input->seek(pos+expectedSize[type], librevenge::RVNG_SEEK_SET);
  }
  ascFile.addPos(pos);
  ascFile.addNote(f.str().c_str());
  if (type!=1 && (type!=5 || !shape.m_hasPicture)) {
    m_state->m_layouts[0].m_shapes.push_back(shape);
    return true;
  }
  // before size zone0+zone1
  for (int st=0; st<2; ++st) { // zone1=[text, style], zone2=[para]
    pos=input->tell();
    f.str("");
    if (type==1)
      f << "Text-" << (st==0 ? "char" : "para") << ":";
    else
      f << "Picture:";
    int len=int(input->readULong(2));
    if (!input->checkPosition(pos+2+len)) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV1: the zone seems too short for a text sub zone\n"));
      f << "###";
      ascFile.addPos(pos);
      ascFile.addNote(f.str().c_str());
      return false;
    }
    shape.m_entries[st].setBegin(pos+2);
    shape.m_entries[st].setLength(len);
    ascFile.addPos(pos);
    ascFile.addNote(f.str().c_str());
    input->seek(pos+2+len+(len%2), librevenge::RVNG_SEEK_SET);
    if (type==5)
      break;
  }

  m_state->m_layouts[0].m_shapes.push_back(shape);
  return true;
}

bool ReadySetGoGraph::readShapeV2(ReadySetGoGraphInternal::Layout &layout)
{
  MWAWInputStreamPtr input = m_parser.getInput();
  if (!input)
    return false;

  long pos=input->tell();
  if (!input->checkPosition(pos+8)) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV2: can not read a shape\n"));
    return false;
  }
  int type=int(input->readULong(2));
  int id=int(input->readULong(2));
  libmwaw::DebugFile &ascFile = m_parser.ascii();
  libmwaw::DebugStream f;
  if (type<0 || type>6) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV2: find bad type=%d\n", type));
    f << "Entries(Zone" << type << ")[S" << id << "]:###";
    ascFile.addPos(pos);
    ascFile.addNote(f.str().c_str());
    return false;
  }
  char const *wh[]= { nullptr, "Solid", "Frame", "Picture", "Text", nullptr, nullptr };
  std::string what;
  if (wh[type])
    what=wh[type];
  else {
    std::stringstream s;
    s << "Zone" << type;
    what=s.str();
  }
  f << "Entries(" << what << ")[S" << id << "]:";
  static ReadySetGoGraphInternal::Shape::Type const shapeTypes[]= {
    ReadySetGoGraphInternal::Shape::T_Unknown,
    ReadySetGoGraphInternal::Shape::T_Rectangle, // solid
    ReadySetGoGraphInternal::Shape::T_Rectangle, // frame
    ReadySetGoGraphInternal::Shape::T_Picture,
    ReadySetGoGraphInternal::Shape::T_Text,
    ReadySetGoGraphInternal::Shape::T_Unknown,
    ReadySetGoGraphInternal::Shape::T_Unknown
  };
  ReadySetGoGraphInternal::Shape shape(shapeTypes[type]);
  int len=int(input->readULong(2));
  if (len<0x1c || !input->checkPosition(pos+6+len)) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV2: find unexpected size for generic data block\n"));
    f << "###";
    ascFile.addPos(pos);
    ascFile.addNote(f.str().c_str());
    return false;
  }
  int val=int(input->readLong(2));
  if (val!=type) f << "##type2=" << val << ",";
  for (int i=0; i<2; ++i) {
    val=int(input->readLong(2));
    if (val!=id) f << "id" << i+1 << "=" << val << ",";
  }
  val=int(input->readLong(2));
  if (val!=1) f << "f0=" << val << ",";
  float dim[4];
  for (auto &d : dim) {
    d=72*float(input->readLong(2));
    d+=72*float(input->readLong(2))/10000;
  }
  shape.m_box=MWAWBox2f(MWAWVec2f(dim[0],dim[1]), MWAWVec2f(dim[0]+dim[2],dim[1]+dim[3]));
  f << "box=" << shape.m_box << ",";
  f << "ID=" << std::hex << input->readULong(4) << std::dec << ",";
  if (input->tell()!=pos+6+len) {
    ascFile.addDelimiter(input->tell(),'|');
    input->seek(pos+6+len, librevenge::RVNG_SEEK_SET);
  }
  ascFile.addPos(pos);
  ascFile.addNote(f.str().c_str());

  pos=input->tell();
  f.str("");
  f << what << "-data:S" << id << ",";
  len=int(input->readULong(2));
  long endPos=pos+2+len;
  if (len<0 || !input->checkPosition(endPos)) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV2: find unexpected size for shape data block\n"));
    f << "###";
    ascFile.addPos(pos);
    ascFile.addNote(f.str().c_str());
    return false;
  }
  switch (type) {
  case 1: // solid
  case 2: { // frame
    if (len!=2+2*type) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV2[%d]: find unexpected size for shape data block\n", type));
      f << "###";
      break;
    }
    val=int(input->readLong(2));
    if (val<0 || val>4) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV2: the color id seems bad\n"));
      f << "###col=" << val << ",";
    }
    else {
      uint8_t grey=uint8_t(val==0 ? 255 : 32*val);
      if (type==2)
        shape.m_style.m_lineColor=MWAWColor(grey,grey,grey);
      else
        shape.m_style.setSurfaceColor(MWAWColor(grey,grey,grey));
      f << "color="  << val << ","; // 0: none, 1: black, 2: grey1, .., 4: light grey
    }
    if (type==2) {
      val=int(input->readLong(2));
      if (val<0 || val>100) {
        MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV2: the frame size seems bad\n"));
        f << "###";
      }
      else
        shape.m_style.m_lineWidth=float(val);
      if (val!=1)
        f << "frame[size]=" << val << ",";
    }
    int subType=int(input->readLong(2));
    switch (subType) {
    case 1: // rectangle
      break;
    case 2:
      shape.m_type=ReadySetGoGraphInternal::Shape::T_RectOval;
      f << "rectOval,";
      break;
    case 3:
      shape.m_type=ReadySetGoGraphInternal::Shape::T_Oval;
      f << "oval,";
      break;
    default:
      MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV2: unknown rectangle type\n"));
      f << "###type=" << subType << ",";
      break;
    }
    break;
  }
  case 3: {
    if (len!=16) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV2[pict]: find unexpected size for shape data block\n"));
      f << "###";
      break;
    }
    for (int i=0; i<2; ++i) {
      val=int(input->readULong(2));
      if (val!=100)
        f << "scale" << (i==0 ? "X" : "Y") << "=" << val << "%,";
    }
    int iDim[2]; // some multiples of 6, link to decal?
    for (auto &d : iDim) d=int(input->readLong(2));
    if (iDim[0] || iDim[1])
      f << "crop=" << MWAWVec2i(iDim[1],iDim[0]) << ","; // checkme
    val=int(input->readULong(4));
    if (val) {
      shape.m_hasPicture=true;
      f << "ID=" << std::hex << val << std::dec << ",";
    }
    for (int i=0; i<2; ++i) { // 0
      val=int(input->readULong(2));
      if (val) f << "f" << i << "=" << val << ",";
    }
    break;
  }
  case 4: {
    if (len!=0x9a) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV2[text]: find unexpected size for shape data block\n"));
      f << "###";
      break;
    }
    shape.m_paragraph.m_marginsUnit=librevenge::RVNG_INCH;
    for (int i=0; i<2; ++i) { // 0
      val=int(input->readLong(2));
      shape.m_paragraph.m_margins[1-i]=float(val)+float(input->readULong(2))/10000;
      if (*shape.m_paragraph.m_margins[1-i]>0) f << (i==0 ? "para" : "left") << "[indent]=" << *shape.m_paragraph.m_margins[i] << ",";
    }
    shape.m_paragraph.m_margins[0]=*shape.m_paragraph.m_margins[0]-*shape.m_paragraph.m_margins[1];
    std::string extra;
    m_styleManager->readTabulationsV1(*shape.m_paragraph.m_tabs, extra);
    f << extra;
    ascFile.addPos(pos);
    ascFile.addNote(f.str().c_str());

    pos=input->tell();
    f.str("");
    f << what << "-data1:";
    input->seek(pos+66, librevenge::RVNG_SEEK_SET);
    ascFile.addPos(pos);
    ascFile.addNote(f.str().c_str());

    pos=input->tell();
    f.str("");
    f << what << "-data2:";
    // pos+16: maybe alignement
    break;
  }
  default:
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV2: reading data of type=%d is not implemented\n", type));
    f << "###";
    break;
  }
  if (input->tell()!=pos && input->tell()!=endPos)
    ascFile.addDelimiter(input->tell(),'|');
  input->seek(endPos, librevenge::RVNG_SEEK_SET);
  ascFile.addPos(pos);
  ascFile.addNote(f.str().c_str());

  if (type==3 && shape.m_hasPicture) {
    pos=input->tell();
    len=int(input->readULong(2));
    f.str("");
    f << "Picture:";
    if (!input->checkPosition(pos+2+len)) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV2: find unexpected size for picture\n"));
      f << "###";
      ascFile.addPos(pos);
      ascFile.addNote(f.str().c_str());
      return false;
    }
    shape.m_entries[0].setBegin(pos+2);
    shape.m_entries[0].setLength(len);
    input->seek(pos+2+len, librevenge::RVNG_SEEK_SET);
    ascFile.addPos(pos);
    ascFile.addNote(f.str().c_str());
  }
  if (type!=4) {
    layout.m_shapes.push_back(shape);
    return true;
  }
  for (int st=0; st<2; ++st) { // zone1=[text, style], zone2=[para]
    pos=input->tell();
    f.str("");
    f << "Text-" << (st==0 ? "char" : "para") << ":";
    len=int(input->readULong(2));
    if (!input->checkPosition(pos+2+len)) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV2: find unexpected size for text sub zone=%d\n", st));
      f << "###";
      ascFile.addPos(pos);
      ascFile.addNote(f.str().c_str());
      return false;
    }
    shape.m_entries[st].setBegin(pos+2);
    shape.m_entries[st].setLength(len);
    input->seek(pos+2+len, librevenge::RVNG_SEEK_SET);
    ascFile.addPos(pos);
    ascFile.addNote(f.str().c_str());
  }
  layout.m_shapes.push_back(shape);
  return true;
}

bool ReadySetGoGraph::readShapeV3(ReadySetGoGraphInternal::Layout &layout, bool &last)
{
  last=false;
  MWAWInputStreamPtr input = m_parser.getInput();
  if (!input)
    return false;

  int const vers=version();
  long pos=input->tell();
  if (!input->checkPosition(pos+2)) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV3: can not read a shape\n"));
    return false;
  }

  auto &ascFile = m_parser.ascii();
  int type=int(input->readLong(2));
  if (type==-1) {
    ascFile.addPos(pos);
    ascFile.addNote("Layout-end:");
    last=true;
    return true;
  }
  if (type<0 || type>6) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV3: the type seems bad\n"));
    input->seek(pos, librevenge::RVNG_SEEK_SET);
    return false;
  }
  libmwaw::DebugStream f;

  long len=long(input->readLong(4));
  int const decal=vers<=3 ? 0 : 4;
  if (len<32+decal || (long)((unsigned long)pos+6+(unsigned long)len)<pos+6 || !input->checkPosition(pos+6+len)) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV3: can not find a shape length\n"));
    input->seek(pos, librevenge::RVNG_SEEK_SET);
    f << "Entries(Shape" << type << "):";
    f << "###";
    ascFile.addPos(pos);
    ascFile.addNote(f.str().c_str());
    return false;
  }
  static ReadySetGoGraphInternal::Shape::Type const shapeTypes[]= {
    ReadySetGoGraphInternal::Shape::T_Rectangle,
    ReadySetGoGraphInternal::Shape::T_RectOval, // + oval size
    ReadySetGoGraphInternal::Shape::T_Oval,
    ReadySetGoGraphInternal::Shape::T_Picture,
    ReadySetGoGraphInternal::Shape::T_Text,
    ReadySetGoGraphInternal::Shape::T_Line,
    ReadySetGoGraphInternal::Shape::T_Line
  };
  static char const *what[]= { "Rectangle", "RectOval", "Oval", "Picture", "Text", "Line" /* hv*/, "Line" /* not axis aligned*/};
  f << "Entries(" << what[type] << "):";
  ReadySetGoGraphInternal::Shape shape(shapeTypes[type]);
  f << "IDS=["; // next, prev
  for (int i=0; i<2; ++i) f << std::hex << input->readULong(4) << std::dec << ",";
  f << "],";
  float dim[4];
  for (auto &d : dim) d=72*float(input->readLong(4))/65536;
  shape.m_box=MWAWBox2f(MWAWVec2f(dim[0],dim[1]), MWAWVec2f(dim[0]+dim[2],dim[1]+dim[3]));
  f << "box=" << shape.m_box << ",";
  int val;
  if (vers>3) {
    val=int(input->readULong(4));
    if (val!=0x1555)
      f << "dist[text,repel]=" << float(val)/65536 << ",";;
  }
  val=int(input->readLong(1));
  if (val!=type)
    f << "##type1=" << val << ",";
  val=int(input->readLong(1));
  if (val==-1)
    f << "selected,";
  else if (val)
    f << "#selected=" << val << ",";
  bool hasPicture=false, hasTabs=false;
  val=int(input->readLong(1));
  if (val==-1) {
    if (vers<4)
      shape.m_wrapRoundAround=true;
    f << "run[around],";
  }
  else if (val)
    f << "run[around]=" << val << ",";
  val=int(input->readULong(1)); // only v4?
  if (val&1)
    f << "locked,";
  if (val&2)
    f << "print[no],";
  if (val&4) {
    f << "run[around],";
    if (vers>=4)
      shape.m_wrapRoundAround=true;
  }
  val &=0xf8;
  if (val)
    f << "fl=" << std::hex << val << std::dec << ",";
  switch (type) {
  case 0:
  case 1:
  case 2:
  case 5:
  case 6: {
    if (len!=(type==1 ? 36 : type==6 ? 40 : 32)+decal+(vers>=5 ? 4 : 0)) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV3[%d]: unexpected data length\n", type));
      f << "###";
      break;
    }
    auto &style=shape.m_style;
    val=int(input->readLong(1));
    int const extraVal=vers<5 ? 0 : 3;
    if (val>=0 && val<=5+extraVal) {
      float const w[]= {0.125f, 0.25f, 0.5f, 0.75f, 1, 2, 4, 6, 8};
      style.m_lineWidth=w[val+(3-extraVal)];
    }
    else if (val>=6+extraVal && val<=10+extraVal) {
      float const w[]= {1, 2, 4, 6, 8};
      style.m_lineWidth=w[val-6-extraVal];
      f << "dash,";
      style.m_lineDashWidth= {10,10};
    }
    else if (val>=11+extraVal && val<=13+extraVal) {
      // changeme: double line 2-1-1, 1-1-2, 1-1-1
      style.m_lineWidth=val==13+extraVal ? 3 : 4;
      f << "double[line],";
    }
    else {
      style.m_lineWidth=1;
      MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV3[%d]: find unknown line style\n", type));
      f << "###line[style]=" << val << ",";
    }
    if (style.m_lineWidth<1 || style.m_lineWidth>1)
      f << "line[width]=" << style.m_lineWidth << ",";

    int patIds[2];
    int const nonePatId=vers==3 ? 39 : 48;
    for (auto &p : patIds) p=int(input->readULong(1));
    input->seek(1, librevenge::RVNG_SEEK_CUR); // junk?

    int colIds[2]= {-1,-1};
    MWAWColor colors[2]= {MWAWColor::white(), MWAWColor::black()};
    if (vers>=5) {
      for (int i=0; i<2; ++i) {
        colIds[i]=int(input->readULong(2));
        int const expected[]= {7, 60};
        if (colIds[i]==expected[i]) continue;
        f << "col[" << (i==0 ? "surf" : "line") << "]=";
        if (colIds[i]>0 && m_styleManager->getColor(colIds[i], colors[i]))
          f << colors[i] << ",";
        else {
          f << "###" << colIds[i] << ",";
          colIds[i]=-1;
        }
      }
    }
    if (type==1) {
      int corner[2];
      for (auto &d : corner) d=int(input->readLong(2));
      shape.m_cornerSize=MWAWVec2i(corner[0], corner[1]);
      f << "corner=" << shape.m_cornerSize << ",";
    }
    if (type==5) { // we must retrieve the line points
      auto const &box=shape.m_box;
      if (box.size()[0]>box.size()[1]) {
        auto y=(box[0][1]+box[1][1])/2;
        shape.m_points[0]=MWAWVec2f(box[0][0],y);
        shape.m_points[1]=MWAWVec2f(box[1][0],y);
      }
      else {
        auto x=(box[0][0]+box[1][0])/2;
        shape.m_points[0]=MWAWVec2f(x,box[0][1]);
        shape.m_points[1]=MWAWVec2f(x,box[1][1]);
      }
    }
    if (type==6) {
      float iDim[4];
      for (auto &d: iDim) d=float(input->readLong(2));
      shape.m_points[0]=MWAWVec2f(iDim[1],iDim[0]);
      shape.m_points[1]=MWAWVec2f(iDim[3],iDim[2]);
      f << "pos=" << shape.m_points[0] << "<->" << shape.m_points[1] << ",";
    }

    // time to set the patterns/colors
    if (patIds[0]!=nonePatId && (type!=5 && type!=6)) {
      MWAWGraphicStyle::Pattern pat;
      MWAWColor color;
      if (!m_styleManager->getPattern(patIds[0]-1, pat))
        f << "##surface[color]=" << patIds[0] << ",";
      else {
        if (colIds[0]>=0)
          pat.m_colors[0]=colors[0];
        if (pat.getUniqueColor(color)) {
          style.setSurfaceColor(color);
          f << "surface[color]=" << color << ",";
        }
        else {
          style.setPattern(pat);
          f << "surface[pat]=" << pat << ",";
        }
      }
    }
    if (patIds[1]==nonePatId) // transparent
      style.m_lineWidth=0;
    else {
      MWAWGraphicStyle::Pattern pat;
      MWAWColor color;
      if (!m_styleManager->getPattern(patIds[1]-1, pat))
        f << "##line[color]=" << patIds[1] << ",";
      else {
        if (colIds[1]>=0)
          pat.m_colors[0]=colors[1];
        if (pat.getAverageColor(style.m_lineColor))
          f << "line[color]=" << style.m_lineColor << ",";
        else {
          MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV3[%d]: can not determine a shape color\n", type));
          f << "###line[color]=" << patIds[1] << ",";
        }
      }
    }
    break;
  }
  case 3: {
    if (len!=(vers==3 ? 40 : vers==4 ? 84 : 0x16c)) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV3[picture]: unexpected data length\n"));
      f << "###";
      break;
    }
    val=int(input->readLong(4));
    if (val) {
      f << "ID1=" << std::hex << val << std::dec << ",";
      hasPicture=true;
    }
    if (vers>4) {
      val=int(input->readLong(2));
      if (val) f << "f2=" << val << ",";
    }
    int iDim[2]; // some multiples of 6, link to decal?
    for (auto &d : iDim) d=int(input->readLong(2));
    if (iDim[0] || iDim[1])
      f << "crop=" << MWAWVec2i(iDim[1],iDim[0]) << ",";
    for (int i=0; i<2; ++i) {
      val=int(input->readULong(2));
      if (val!=100)
        f << "scale" << (i==0 ? "X" : "Y") << "=" << val << "%,";
    }
    if (vers==3)
      break;
    for (int i=0; i<(vers==4 ? 20 : 3); ++i) {
      val=int(input->readLong(2));
      if (!val) continue;
      if (i==2) // g2&2 run around graphic/frame?, g2&200 print as gray
        f << "g" << i << "=" << std::hex << val << std::dec << ",";
      else
        f << "g" << i << "=" << val << ",";
    }
    break;
  }
  case 4: {
    if (len!=(vers==3 ? 80 : vers==4 ? 100 : 104)) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV3[text]: unexpected data length\n"));
      f << "###";
      break;
    }
    f << "IDS1=["; // next, prev
    for (int i=0; i<2; ++i) f << std::hex << input->readULong(4) << std::dec << ",";
    f << "],";
    if (vers==3) {
      f << "id=" << input->readLong(2) << ","; // 1-f
      f << "ID2=" << std::hex << input->readULong(4) << std::dec << ",";
      val=int(input->readULong(4));
      if (val) {
        f << "tab[ID]=" << std::hex << val << std::dec << ",";
        hasTabs=true;
      }
    }
    else {
      val=int(input->readULong(4));
      if (val) {
        f << "tab[ID]=" << std::hex << val << std::dec << ",";
        hasTabs=true;
      }
      f << "id=" << input->readLong(2) << ","; // 1-f
      f << "ID2=" << std::hex << input->readULong(4) << std::dec << ",";
    }
    int tDim[4];
    for (auto &d : tDim) d=int(input->readLong(2));
    f << "unkn=" << MWAWBox2i(MWAWVec2i(tDim[0],tDim[1]),MWAWVec2i(tDim[2],tDim[3])) << ",";
    for (int i=0; i<5; ++i) {
      val=int(input->readLong(2));
      if (val)
        f << "f" << i+2 << "=" << val << ",";
    }
    val=int(input->readULong(2));
    if (val&0x4)
      f << "postscript,";
    if (val&0x10) // useme: basically the text is hidden
      f << "white[type],";
    if (val&0x20)
      f << "ignore[run,around],";
    val&=0xffdb;
    if (val)
      f << "fl1=" << std::hex << val << std::dec << ",";
    ascFile.addDelimiter(input->tell(),'|');
    input->seek(pos+76+(vers==3 ? 0 : 4), librevenge::RVNG_SEEK_SET);
    ascFile.addDelimiter(input->tell(),'|');
    shape.m_textId=int(input->readLong(2));
    f << "text[id]=" << shape.m_textId << ",";
    for (int i=0; i<2; ++i) {
      shape.m_linkIds[i]=int(input->readLong(2));
      if (shape.m_linkIds[i]==-1)
        continue;
      f << (i==0 ? "prev" : "next") << "[link]=" << shape.m_linkIds[i] << ",";
    }
    for (int i=0; i<2; ++i) {
      val=int(input->readLong(2));
      if (val!=-1)
        f << "g" << i << "=" << val << ",";
    }
    if (vers==3)
      break;
    for (int i=0; i<(vers==4 ? 8 : 9); ++i) { // g4=3100
      val=int(input->readLong(2));
      if (val)
        f << "g" << i+2 << "=" << val << ",";
    }
    if (vers==4)
      break;
    val=int(input->readLong(1));
    switch (val) {
    case 0: // top
      break;
    case 1:
      shape.m_style.m_verticalAlignment=MWAWGraphicStyle::V_AlignBottom;
      f << "vAlign=bottom,";
      break;
    case 2:
      shape.m_style.m_verticalAlignment=MWAWGraphicStyle::V_AlignCenter;
      f << "vAlign=center,";
      break;
    case 3:
      shape.m_style.m_verticalAlignment=MWAWGraphicStyle::V_AlignJustify;
      f << "vAlign=justify[feathering],";
      break;
    case 4:
      shape.m_style.m_verticalAlignment=MWAWGraphicStyle::V_AlignJustify;
      f << "vAlign=justify[paragraph],";
      break;
    default:
      MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV3[text]: unknown vertical alignment\n"));
      f << "##vAlign=" << val << ",";
      break;
    }
    val=int(input->readLong(1));
    if (val) f << "h0=" << val << ",";
    break;
  }
  default:
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV3[%d]: unexpected data\n", type));
    f << "###";
    break;
  }
  if (input->tell()!=pos+6+len)
    ascFile.addDelimiter(input->tell(),'|');
  ascFile.addPos(pos);
  ascFile.addNote(f.str().c_str());
  input->seek(pos+6+len, librevenge::RVNG_SEEK_SET);

  if (hasPicture) {
    pos=input->tell();
    len=long(input->readLong(4));
    if ((len&0xffff)<7 || !input->checkPosition(pos+4+len))
      input->seek(pos, librevenge::RVNG_SEEK_SET);
    else {
      shape.m_entries[0].setBegin(pos+4);
      shape.m_entries[0].setLength(len);
      input->seek(pos+4+len, librevenge::RVNG_SEEK_SET);
      ascFile.addPos(pos);
      ascFile.addNote("Picture-data:");
    }
  }
  if (type==4 && vers>3) {
    pos=input->tell();
    f.str("");
    f << "Text-limits:";
    if (!input->checkPosition(pos+8)) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV3: can not find the text limits positions\n"));
      f << "###";
      ascFile.addPos(pos);
      ascFile.addNote(f.str().c_str());
      return false;
    }
    for (int i=0; i<2; ++i) {
      shape.m_textPositions[i]=int(input->readLong(4));
      if (shape.m_textPositions[i]==0) continue;
      f << (i==0 ? "min[pos]" : "max[pos]") << "=" << shape.m_textPositions[i] << ",";
    }
    ascFile.addPos(pos);
    ascFile.addNote(f.str().c_str());
  }
  if (type==4 && shape.m_linkIds[0]<0) {
    for (int st=0; st<(!hasTabs ? 2 : 3); ++st) {
      pos=input->tell();
      len=long(input->readLong(4));
      if (len<10 || (long)((unsigned long)pos+4+(unsigned long)len)<pos+4 || !input->checkPosition(pos+4+len)) {
        MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV3[text]: can not find a shape length\n"));
        input->seek(pos, librevenge::RVNG_SEEK_SET);
        f << "###";
        ascFile.addPos(pos);
        ascFile.addNote("Text-####");
        return false;
      }
      shape.m_entries[st].setBegin(pos+4);
      shape.m_entries[st].setLength(len);
      ascFile.addPos(pos);
      ascFile.addNote(st==0 ? "Text-text" : st==1 ? "Entries(Style):" : "Entries(Tabs):");
      input->seek(pos+4+len, librevenge::RVNG_SEEK_SET);
    }
  }
  layout.m_shapes.push_back(shape);
  return true;
}

bool ReadySetGoGraph::readShapeV6(ReadySetGoGraphInternal::Layout &layout, bool &last)
{
  last=false;
  MWAWInputStreamPtr input = m_parser.getInput();
  if (!input)
    return false;

  int const vers=version();
  if (vers<6 || m_parser.isDesignStudioFile()) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV6: unexpected version\n"));
    return false;
  }
  long pos=input->tell();
  if (!input->checkPosition(pos+2)) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV6: can not read a shape\n"));
    return false;
  }

  auto &ascFile = m_parser.ascii();
  int type=int(input->readLong(2));
  if (type==-1) {
    ascFile.addPos(pos);
    ascFile.addNote("Layout-end:");
    last=true;
    return true;
  }
  libmwaw::DebugStream f;
  if (type<0 || type>7) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV6: the type seems bad\n"));
    input->seek(pos, librevenge::RVNG_SEEK_SET);
    f << "Entries(Shape" << type << "):";
    f << "###";
    ascFile.addPos(pos);
    ascFile.addNote(f.str().c_str());
    return false;
  }

  long len=long(input->readLong(4));
  int const minSize[]= {0x98, 0x9c, 0x98, 0x1e6, 0xe0, 0x98, 0xa0, 0xa0};
  if (len<minSize[type] || (long)((unsigned long)pos+6+(unsigned long)len)<pos+6 || !input->checkPosition(pos+6+len)) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV6: can not find a shape length\n"));
    input->seek(pos, librevenge::RVNG_SEEK_SET);
    f << "Entries(Shape" << type << "):";
    f << "###";
    ascFile.addPos(pos);
    ascFile.addNote(f.str().c_str());
    return false;
  }
  static ReadySetGoGraphInternal::Shape::Type const shapeTypes[]= {
    ReadySetGoGraphInternal::Shape::T_Rectangle,
    ReadySetGoGraphInternal::Shape::T_RectOval, // + oval size
    ReadySetGoGraphInternal::Shape::T_Oval,
    ReadySetGoGraphInternal::Shape::T_Picture,
    ReadySetGoGraphInternal::Shape::T_Text,
    ReadySetGoGraphInternal::Shape::T_Line,
    ReadySetGoGraphInternal::Shape::T_Line,
    ReadySetGoGraphInternal::Shape::T_Polygon,
  };
  static char const *what[]= { "Rectangle", "RectOval", "Oval", "Picture", "Text", "Line" /* hv*/, "Line" /* not axis aligned*/, "Polygon" };
  f << "Entries(" << what[type] << "):";
  ReadySetGoGraphInternal::Shape shape(shapeTypes[type]);
  f << "IDS=["; // next, prev
  for (int i=0; i<2; ++i) f << std::hex << input->readULong(4) << std::dec << ",";
  f << "],";
  float dim[4];
  for (auto &d : dim) d=72*float(input->readLong(4))/65536;
  shape.m_box=MWAWBox2f(MWAWVec2f(dim[0],dim[1]), MWAWVec2f(dim[0]+dim[2],dim[1]+dim[3]));
  f << "box=" << shape.m_box << ",";
  int val;
  val=int(input->readULong(4));
  if (val!=0x1555)
    f << "dist[text,repel]=" << float(val)/65536 << ",";;
  val=int(input->readLong(1));
  if (val!=type)
    f << "##type1=" << val << ",";
  val=int(input->readLong(1));
  if (val==-1)
    f << "selected,";
  else if (val)
    f << "#selected=" << val << ",";
  bool hasTabs=false;
  int numPictures=0;
  int numPoints=0;
  val=int(input->readLong(1));
  if (val==-1)
    f << "run[around],";
  else if (val)
    f << "run[around]=" << val << ",";
  val=int(input->readULong(1)); // only v4?
  if (val&1)
    f << "locked,";
  if (val&2)
    f << "print[no],";
  if (val&4) {
    f << "run[around],";
    shape.m_wrapRoundAround=true;
  }
  val &=0xf8;
  if (val)
    f << "fl=" << std::hex << val << std::dec << ",";
  auto &style=shape.m_style;
  shape.m_rotate=int(input->readLong(2));
  if (shape.m_rotate) {
    f << "rot=" << double(shape.m_rotate)/10 << ",";
    style.m_rotate=float(shape.m_rotate)/10;
  }
  val=int(input->readULong(2));
  if (val&0x100) {
    f << "flipY,";
    style.m_flip[1]=true;
  }
  if (val&0x200) {
    f << "flipX,";
    style.m_flip[0]=true;
  }
  val&=0xfcff;
  if (val) f << "f7" << "=" << std::hex << val << std::dec << ",";
  for (auto &d : dim) d=float(input->readLong(2));
  if (dim[0]<dim[2] || dim[1]<dim[3])
    f << "box1=" << MWAWBox2f(MWAWVec2f(dim[1],dim[0]), MWAWVec2f(dim[3],dim[2])) << ",";
  for (int i=0; i<2; ++i) {
    val=int(input->readLong(2));
    if (val) f << "f" << 8+i << "=" << val << ",";
  }
  for (int i=0; i<2; ++i) {
    for (auto &d : dim) d=float(input->readLong(2));
    if (dim[0]<dim[2] || dim[1]<dim[3])
      f << "box" << 2+i << "=" << MWAWBox2f(MWAWVec2f(dim[1],dim[0]), MWAWVec2f(dim[3],dim[2])) << ",";
  }
  for (int i=0; i<14; ++i) {
    val=int(input->readLong(2));
    if (val) f << "f" << 10+i << "=" << val << ",";
  }
  shape.m_groupId=int(input->readLong(2));
  if (shape.m_groupId) f << "group=" << shape.m_groupId << ",";
  ascFile.addDelimiter(input->tell(),'|');
  input->seek(32, librevenge::RVNG_SEEK_CUR);
  ascFile.addDelimiter(input->tell(),'|');
  val=int(input->readULong(4));
  if (val)
    f << "ID[unk]=" << std::hex << val << std::dec << ",";
  ascFile.addDelimiter(input->tell(),'|');
  input->seek(8, librevenge::RVNG_SEEK_CUR);
  ascFile.addDelimiter(input->tell(),'|');

  int const nonePatId=4;
  int backColId=60;
  int backPatId=nonePatId;
  if (type==4) {
    f << "IDS1=["; // next, prev
    for (int i=0; i<2; ++i) f << std::hex << input->readULong(4) << std::dec << ",";
    f << "],";
    val=int(input->readULong(4));
    if (val) {
      f << "tab[ID]=" << std::hex << val << std::dec << ",";
      hasTabs=true;
    }
    f << "id=" << input->readLong(2) << ","; // 1-f
    f << "ID2=" << std::hex << input->readULong(4) << std::dec << ",";
    int tDim[4];
    for (auto &d : tDim) d=int(input->readLong(2));
    f << "unkn=" << MWAWBox2i(MWAWVec2i(tDim[0],tDim[1]),MWAWVec2i(tDim[2],tDim[3])) << ",";
    for (int i=0; i<5; ++i) {
      val=int(input->readLong(2));
      if (!val) continue;
      f << "f" << i+2 << "=" << val << ",";
    }
    val=int(input->readULong(2));
    if (val&0x4)
      f << "postscript,";
    if (val&0x10) // useme: basically the text is hidden
      f << "white[type],";
    if (val&0x20)
      f << "ignore[run,around],";
    val&=0xffdb;
    if (val)
      f << "fl1=" << std::hex << val << std::dec << ",";
    ascFile.addDelimiter(input->tell(),'|');
    input->seek(pos+76+110, librevenge::RVNG_SEEK_SET);
    ascFile.addDelimiter(input->tell(),'|');
    shape.m_textId=int(input->readLong(2));
    f << "text[id]=" << shape.m_textId << ",";
    for (int i=0; i<2; ++i) {
      shape.m_linkIds[i]=int(input->readLong(2));
      if (shape.m_linkIds[i]==-1)
        continue;
      f << (i==0 ? "prev" : "next") << "[link]=" << shape.m_linkIds[i] << ",";
    }
    for (int i=0; i<2; ++i) {
      val=int(input->readLong(2));
      if (val!=-1)
        f << "g" << i << "=" << val << ",";
    }
    bool hasBackPattern=false;
    uint8_t backPattern[8];
    for (auto &p : backPattern) {
      p=uint8_t(input->readULong(1));
      if (p) hasBackPattern=true;
    }
    if (hasBackPattern) {
      f << "back[pat]=[";
      for (auto const &p : backPattern) f << std::hex << int(p) << std::dec << ",";
      f << "],";
    }
    backColId=int(input->readLong(2));
    if (backColId!=60)
      f << "back[col,id]=" << backColId << ",";
    backPatId=int(input->readULong(1));
    if (backPatId!=nonePatId)
      f << "back[pat,id]=" << backPatId << ",";
    input->seek(1, librevenge::RVNG_SEEK_CUR);
    for (int i=0; i<3; ++i) {
      val=int(input->readLong(2));
      if (!val)
        continue;
      f << "g" << i+2 << "=" << val << ",";
    }
    val=int(input->readLong(1));
    switch (val) {
    case 0: // top
      break;
    case 1:
      style.m_verticalAlignment=MWAWGraphicStyle::V_AlignBottom;
      f << "vAlign=bottom,";
      break;
    case 2:
      style.m_verticalAlignment=MWAWGraphicStyle::V_AlignCenter;
      f << "vAlign=center,";
      break;
    case 3:
      style.m_verticalAlignment=MWAWGraphicStyle::V_AlignJustify;
      f << "vAlign=justify[feathering],";
      break;
    case 4:
      style.m_verticalAlignment=MWAWGraphicStyle::V_AlignJustify;
      f << "vAlign=justify[paragraph],";
      break;
    default:
      MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV6[text]: unknown vertical alignment\n"));
      f << "##vAlign=" << val << ",";
      break;
    }
    val=int(input->readLong(1));
    if (val) f << "h0=" << val << ",";
  }
  val=int(input->readLong(1));
  if (val>=0 && val<=8) {
    float const w[]= {0.125f, 0.25f, 0.5f, 0.75f, 1, 2, 4, 6, 8};
    style.m_lineWidth=w[val];
  }
  else if (val>=9 && val<=13) {
    float const w[]= {1, 2, 4, 6, 8};
    style.m_lineWidth=w[val-9];
    f << "dash,";
    style.m_lineDashWidth= {10,10};
  }
  else if (val>=14 && val<=16) {
    // changeme: double line 2-1-1, 1-1-2, 1-1-1
    style.m_lineWidth=val==16 ? 3 : 4;
    f << "double[line],";
  }
  else {
    style.m_lineWidth=1;
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV6[%d]: find unknown line style\n", type));
    f << "###line[style]=" << val << ",";
  }
  if (style.m_lineWidth<1 || style.m_lineWidth>1)
    f << "line[width]=" << style.m_lineWidth << ",";
  val=int(input->readLong(1));
  if (val!=1)
    f << "g0=" << val << ",";

  if (type==3) // fixme
    style.m_lineWidth=0;
  int numColors=(type<=2 || (type>=5 && type<=7)) ? 2 : 1;
  int patIds[2];
  for (auto &p : patIds) p=int(input->readULong(1));
  int colIds[2]= {-1,-1};
  MWAWColor colors[2]= {MWAWColor::white(), MWAWColor::black()};
  for (int i=0; i<numColors; ++i) {
    colIds[i]=int(input->readULong(2));
    int const expected[]= {7, 60};
    if (colIds[i]==(type==3 ? 60 : expected[i])) continue;
    if (numColors==1)
      f << "col=";
    else
      f << "col[" << (i==0 ? "surf" : "line") << "]=";
    if (colIds[i]>0 && m_styleManager->getColor(colIds[i], colors[i]))
      f << colors[i] << ",";
    else {
      f << "###" << colIds[i] << ",";
      colIds[i]=-1;
    }
  }
  for (int i=0; i<numColors; ++i) {
    int tint=int(input->readLong(2));
    if (tint==10000) continue;
    f << "tints[" << (i==0 ? "surf" : "line") << "]=" << float(tint)/100 << "%,";
    if (tint<0 || tint>10000) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV6: find bad tint\n"));
      f << "###";
      continue;
    }
    colors[i]=MWAWColor::barycenter(float(10000-tint)/10000, MWAWColor::white(), float(tint)/10000, colors[i]);
  }
  val=int(input->readLong(2));
  if (val!=100) f << "g3=" << val << ",";

  switch (type) {
  case 0:
  case 1:
  case 2:
  case 5:
  case 6:
  case 7: {
    if (type==1) {
      int corner[2];
      for (auto &d : corner) d=int(input->readLong(2));
      shape.m_cornerSize=MWAWVec2i(corner[0], corner[1]);
      f << "corner=" << shape.m_cornerSize << ",";
    }
    if (type==5) { // we must retrieve the line points
      auto const &box=shape.m_box;
      if (box.size()[0]>box.size()[1]) {
        auto y=(box[0][1]+box[1][1])/2;
        shape.m_points[0]=MWAWVec2f(box[0][0],y);
        shape.m_points[1]=MWAWVec2f(box[1][0],y);
      }
      else {
        auto x=(box[0][0]+box[1][0])/2;
        shape.m_points[0]=MWAWVec2f(x,box[0][1]);
        shape.m_points[1]=MWAWVec2f(x,box[1][1]);
      }
    }
    if (type==6) {
      float iDim[4];
      for (auto &d: iDim) d=float(input->readLong(2));
      shape.m_points[0]=MWAWVec2f(iDim[1],iDim[0]);
      shape.m_points[1]=MWAWVec2f(iDim[3],iDim[2]);
      f << "pos=" << shape.m_points[0] << "<->" << shape.m_points[1] << ",";
    }
    if (type==7) {
      numPoints=int(input->readULong(2));
      f << "N=" << numPoints << ",";
      val=int(input->readULong(2));
      if (val!=0x100)
        f << "g4=" << val << ",";
      auto ID=input->readULong(4);
      if (ID)
        f << "ID=" << std::hex << ID << std::dec << ",";
      // checkme
    }
    // time to set the patterns/colors
    if (patIds[0]!=nonePatId && (type!=5 && type!=6)) {
      MWAWGraphicStyle::Pattern pat;
      MWAWColor color;
      if (!m_styleManager->getPattern(patIds[0]-1, pat))
        f << "##surface[color]=" << patIds[0] << ",";
      else {
        if (colIds[0]>=0)
          pat.m_colors[0]=colors[0];
        if (pat.getUniqueColor(color)) {
          style.setSurfaceColor(color);
          f << "surface[color]=" << color << ",";
        }
        else {
          style.setPattern(pat);
          f << "surface[pat]=" << pat << ",";
        }
      }
    }
    if (patIds[1]==nonePatId) // transparent
      style.m_lineWidth=0;
    else {
      MWAWGraphicStyle::Pattern pat;
      MWAWColor color;
      if (!m_styleManager->getPattern(patIds[1]-1, pat))
        f << "##line[color]=" << patIds[1] << ",";
      else {
        if (colIds[1]>=0)
          pat.m_colors[0]=colors[1];
        if (pat.getAverageColor(style.m_lineColor))
          f << "line[color]=" << style.m_lineColor << ",";
        else {
          MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV6[%d]: can not determine a shape color\n", type));
          f << "###line[color]=" << patIds[1] << ",";
        }
      }
    }
    break;
  }
  case 3: {
    if (patIds[0]!=4)
      f << "pattern[line]=" << patIds[0] << ",";
    if (vers==6) {
      val=int(input->readLong(2));
      if (val) f << "g4=" << val << ",";
    }
    val=int(input->readULong(4));
    if (val) {
      f << "ID[pict]=" << std::hex << val << std::dec << ",";
      ++numPictures;
    }
    for (int i=0; i<(vers==6 ? 1 : 2); ++i) {
      val=int(input->readLong(2));
      if (val) f << "g" << i+3 << "=" << val << ",";
    }
    int iDim[2]; // some multiples of 6, link to decal?
    for (auto &d : iDim) d=int(input->readLong(2));
    if (iDim[0] || iDim[1])
      f << "crop=" << MWAWVec2i(iDim[1],iDim[0]) << ",";
    for (int i=0; i<2; ++i) {
      val=int(input->readULong(2));
      if (val!=100)
        f << "scale" << (i==0 ? "X" : "Y") << "=" << val << "%,";
    }
    long aPos=input->tell(); // checkme probably identical in v4.5
    std::string pictType;
    for (int i=0; i<4; ++i) {
      char c=char(input->readULong(1));
      if (!c) break;
      pictType+=c;
    }
    if (!pictType.empty()) {
      f << "type=" << pictType << ",";
      ++numPictures;
    }
    input->seek(aPos+4, librevenge::RVNG_SEEK_SET);
    val=int(input->readLong(2));
    if (val) // run around graphic/frame?, g2&200 print as gray
      f << "fl=" << std::hex << val << std::dec << ",";

    long actPos=input->tell();
    libmwaw::DebugStream f2;
    f2 << "Picture-A:";
    input->seek(actPos+314, librevenge::RVNG_SEEK_SET);
    ascFile.addDelimiter(input->tell(),'|');
    val=int(input->readULong(1));
    if (val)
      f << "shape=" << val << ",";
    ascFile.addPos(actPos);
    ascFile.addNote(f2.str().c_str());
    break;
  }
  case 4: {
    if (patIds[0]==nonePatId) // transparent
      style.m_lineWidth=0;
    else {
      MWAWGraphicStyle::Pattern pat;
      MWAWColor color;
      if (!m_styleManager->getPattern(patIds[0]-1, pat))
        f << "##line[color]=" << patIds[0] << ",";
      else {
        if (colIds[0]>=0)
          pat.m_colors[0]=colors[0];
        if (pat.getAverageColor(style.m_lineColor))
          f << "line[color]=" << style.m_lineColor << ",";
        else {
          MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV6[%d]: can not determine a shape color\n", type));
          f << "###line[color]=" << patIds[0] << ",";
        }
      }
    }

    val=int(input->readLong(2));
    if (val)
      f << "h0=" << val << ",";
    int backTint=int(input->readLong(2));
    if (backTint) f << "tint=" << float(backTint)/100 << "%,";
    if (backPatId==nonePatId)
      break;

    MWAWColor color = MWAWColor::black();
    if (backColId!=60)
      m_styleManager->getColor(backColId, color);
    color=MWAWColor::barycenter(float(10000-backTint)/10000, MWAWColor::white(), float(backTint)/10000, color);
    MWAWGraphicStyle::Pattern pat;
    if (backPatId<1 || !m_styleManager->getPattern(backPatId-1, pat))
      style.setSurfaceColor(color);
    else {
      pat.m_colors[0]=color;
      if (pat.getUniqueColor(color))
        style.setSurfaceColor(color);
      else
        style.setPattern(pat);
    }
    break;
  }
  default:
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV6[%d]: unexpected data\n", type));
    f << "###";
    break;
  }
  if (input->tell()!=pos+6+len)
    ascFile.addDelimiter(input->tell(),'|');
  ascFile.addPos(pos);
  ascFile.addNote(f.str().c_str());
  input->seek(pos+6+len, librevenge::RVNG_SEEK_SET);

  for (int p=0; p<numPictures; ++p) {
    pos=input->tell();
    len=long(input->readLong(4));
    if (len==0 && p==1) { // can happen in v7 files
      ascFile.addPos(pos);
      ascFile.addNote("_");
      continue;
    }
    if ((len&0xffff)<7 || !input->checkPosition(pos+4+len)) {
      input->seek(pos, librevenge::RVNG_SEEK_SET);
      break;
    }
    shape.m_entries[p].setBegin(pos+4);
    shape.m_entries[p].setLength(len);
    input->seek(pos+4+len, librevenge::RVNG_SEEK_SET);
    ascFile.addPos(pos);
    ascFile.addNote("Picture-data:");
  }
  if (numPoints) { // FIXME
    pos=input->tell();
    len=long(input->readLong(4));
    if ((len&0xffff)<2 || !input->checkPosition(pos+4+len))
      input->seek(pos, librevenge::RVNG_SEEK_SET);
    else {
      f.str("");
      f << "Polygon-point:";
      int len2=int(input->readLong(2));
      if (len2>len || 2+4*(2+numPoints)>len2) {
        MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV6: the number of points seems bad\n"));
        f << "###";
        numPoints=0;
      }
      f << "box=[";
      for (int i=0; i<2; ++i) {
        int pts[2];
        for (auto &pt : pts) pt=int(input->readLong(2));
        f << MWAWVec2i(pts[1], pts[0]) << ",";
      }
      f << "],";
      f << "pts=[";
      for (int i=0; i<numPoints; ++i) {
        float pts[2];
        for (auto &pt : pts) pt=float(input->readLong(2));
        shape.m_vertices.push_back(MWAWVec2f(pts[1], pts[0]));
        f << shape.m_vertices.back() << ",";
      }
      f << "],";
      input->seek(pos+4+len, librevenge::RVNG_SEEK_SET);
      ascFile.addPos(pos);
      ascFile.addNote(f.str().c_str());
    }
  }
  if (type==4) {
    pos=input->tell();
    f.str("");
    f << "Text-limits:";
    if (!input->checkPosition(pos+8)) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV6: can not find the text limits positions\n"));
      f << "###";
      ascFile.addPos(pos);
      ascFile.addNote(f.str().c_str());
      return false;
    }
    for (int i=0; i<2; ++i) {
      shape.m_textPositions[i]=int(input->readLong(4));
      if (shape.m_textPositions[i]==0) continue;
      f << (i==0 ? "min[pos]" : "max[pos]") << "=" << shape.m_textPositions[i] << ",";
    }
    ascFile.addPos(pos);
    ascFile.addNote(f.str().c_str());
  }
  if (type==4 && shape.m_linkIds[0]<0) {
    for (int st=0; st<(!hasTabs ? 2 : 3); ++st) {
      pos=input->tell();
      len=long(input->readLong(4));
      if (len<10 || (long)((unsigned long)pos+4+(unsigned long)len)<pos+4 || !input->checkPosition(pos+4+len)) {
        MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeV6[text]: can not find a shape length\n"));
        input->seek(pos, librevenge::RVNG_SEEK_SET);
        f << "###";
        ascFile.addPos(pos);
        ascFile.addNote("Text-####");
        return false;
      }
      shape.m_entries[st].setBegin(pos+4);
      shape.m_entries[st].setLength(len);
      ascFile.addPos(pos);
      ascFile.addNote(st==0 ? "Text-text" : st==1 ? "Entries(Style):" : "Entries(Tabs):");
      input->seek(pos+4+len, librevenge::RVNG_SEEK_SET);
    }
  }
  layout.m_shapes.push_back(shape);
  return true;
}

bool ReadySetGoGraph::readShapeDSV2(ReadySetGoGraphInternal::Layout &layout, bool &last)
{
  last=false;
  MWAWInputStreamPtr input = m_parser.getInput();
  if (!input)
    return false;

  int const vers=version();
  if (vers<6 || !m_parser.isDesignStudioFile()) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeDSV2: unexpected version\n"));
    return false;
  }
  long pos=input->tell();
  if (!input->checkPosition(pos+2)) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeDSV2: can not read a shape\n"));
    return false;
  }

  auto &ascFile = m_parser.ascii();
  int type=int(input->readLong(2));
  if (type==-1) {
    ascFile.addPos(pos);
    ascFile.addNote("Layout-end:");
    last=true;
    return true;
  }
  libmwaw::DebugStream f;
  if (type<0 || type>7) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeDSV2: the type seems bad\n"));
    input->seek(pos, librevenge::RVNG_SEEK_SET);
    f << "Entries(Shape" << type << "):";
    f << "###";
    ascFile.addPos(pos);
    ascFile.addNote(f.str().c_str());
    return false;
  }

  long len=long(input->readLong(4));
  int const minSize[]= {0x7c, 0x80, 0x7c, 0x1ca, 0xc4, 0x84, 0x84, 0x84};
  if (len<minSize[type]-28 || (long)((unsigned long)pos+6+(unsigned long)len)<pos+6 || !input->checkPosition(pos+6+len)) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeDSV2: can not find a shape length\n"));
    input->seek(pos, librevenge::RVNG_SEEK_SET);
    f << "Entries(Shape" << type << "):";
    f << "###";
    ascFile.addPos(pos);
    ascFile.addNote(f.str().c_str());
    return false;
  }
  static ReadySetGoGraphInternal::Shape::Type const shapeTypes[]= {
    ReadySetGoGraphInternal::Shape::T_Rectangle,
    ReadySetGoGraphInternal::Shape::T_RectOval, // + oval size
    ReadySetGoGraphInternal::Shape::T_Oval,
    ReadySetGoGraphInternal::Shape::T_Picture,
    ReadySetGoGraphInternal::Shape::T_Text,
    ReadySetGoGraphInternal::Shape::T_Line,
    ReadySetGoGraphInternal::Shape::T_Line,
    ReadySetGoGraphInternal::Shape::T_Polygon,
  };
  // checkme can type=1 and type=6 exists
  static char const *what[]= { "Rectangle", "RectOval", "Oval", "Picture", "Text", "Line" /* hv*/, "Line" /* not axis aligned*/, "Polygon" };
  f << "Entries(" << what[type] << "):";
  ReadySetGoGraphInternal::Shape shape(shapeTypes[type]);
  f << "IDS=["; // next, prev
  for (int i=0; i<2; ++i) f << std::hex << input->readULong(4) << std::dec << ",";
  f << "],";
  float dim[4];
  for (auto &d : dim) d=72*float(input->readLong(4))/65536;
  shape.m_box=MWAWBox2f(MWAWVec2f(dim[0],dim[1]), MWAWVec2f(dim[0]+dim[2],dim[1]+dim[3]));
  f << "box=" << shape.m_box << ",";
  int val;
  val=int(input->readULong(4));
  if (val!=0x1555)
    f << "dist[text,repel]=" << float(val)/65536 << ",";;
  val=int(input->readLong(1));
  if (val!=type)
    f << "##type1=" << val << ",";
  val=int(input->readLong(1));
  if (val==-1)
    f << "selected,";
  else if (val)
    f << "#selected=" << val << ",";
  bool hasTabs=false;
  int numPictures=0;
  int numPoints=0;
  val=int(input->readLong(1));
  if (val==-1)
    f << "run[around],";
  else if (val)
    f << "run[around]=" << val << ",";
  val=int(input->readULong(1)); // only v4?
  if (val&1)
    f << "locked,";
  if (val&2)
    f << "print[no],";
  if (val&4) {
    f << "run[around],";
    shape.m_wrapRoundAround=true;
  }
  val &=0xf8;
  if (val)
    f << "fl=" << std::hex << val << std::dec << ",";
  auto &style=shape.m_style;
  shape.m_rotate=int(input->readLong(2));
  if (shape.m_rotate) {
    f << "rot=" << double(shape.m_rotate)/10 << ",";
    style.m_rotate=float(shape.m_rotate)/10;
  }
  val=int(input->readULong(2));
  if (val&0x100) {
    f << "flipY,";
    style.m_flip[1]=true;
  }
  if (val&0x200) {
    f << "flipX,";
    style.m_flip[0]=true;
  }
  val&=0xfcff;
  if (val) f << "f7" << "=" << std::hex << val << std::dec << ",";
  for (auto &d : dim) d=float(input->readLong(2));
  if (dim[0]<dim[2] || dim[1]<dim[3])
    f << "box1=" << MWAWBox2f(MWAWVec2f(dim[1],dim[0]), MWAWVec2f(dim[3],dim[2])) << ",";
  for (int i=0; i<2; ++i) {
    val=int(input->readLong(2));
    if (val) f << "f" << 8+i << "=" << val << ",";
  }
  for (int i=0; i<2; ++i) {
    for (auto &d : dim) d=float(input->readLong(2));
    if (dim[0]<dim[2] || dim[1]<dim[3])
      f << "box" << 2+i << "=" << MWAWBox2f(MWAWVec2f(dim[1],dim[0]), MWAWVec2f(dim[3],dim[2])) << ",";
  }
  for (int i=0; i<14; ++i) {
    val=int(input->readLong(2));
    if (val) f << "f" << 10+i << "=" << val << ",";
  }
  shape.m_groupId=int(input->readLong(2));
  if (shape.m_groupId) f << "group=" << shape.m_groupId << ",";
  ascFile.addDelimiter(input->tell(),'|');
  input->seek(14, librevenge::RVNG_SEEK_CUR); // 0000002d003c0000002d003c0[12]00 12: maybe left/right page
  ascFile.addDelimiter(input->tell(),'|');
  val=int(input->readULong(4));
  if (val)
    f << "ID[unk]=" << std::hex << val << std::dec << ",";
  ascFile.addDelimiter(input->tell(),'|');
  val=int(input->readLong(2));
  if (val!=60) // a color index
    f << "g0=" << val << ",";
  for (int i=0; i<2; ++i) { // g1=2-4, g2=0-3
    val=int(input->readULong(1));
    if (val!=(i==0 ? 4 : 0))
      f << "g" << i+1 << "=" << val << ",";
  }

  int const nonePatId=48;
  int backColId=60;
  int backPatId=nonePatId;
  if (type==4) {
    f << "IDS1=["; // next, prev
    for (int i=0; i<2; ++i) f << std::hex << input->readULong(4) << std::dec << ",";
    f << "],";
    val=int(input->readULong(4));
    if (val) {
      f << "tab[ID]=" << std::hex << val << std::dec << ",";
      hasTabs=true;
    }
    f << "id=" << input->readLong(2) << ","; // 1-f
    f << "ID2=" << std::hex << input->readULong(4) << std::dec << ",";
    int tDim[4];
    for (auto &d : tDim) d=int(input->readLong(2));
    f << "unkn=" << MWAWBox2i(MWAWVec2i(tDim[0],tDim[1]),MWAWVec2i(tDim[2],tDim[3])) << ",";
    for (int i=0; i<5; ++i) {
      val=int(input->readLong(2));
      if (!val) continue;
      f << "f" << i+2 << "=" << val << ",";
    }
    val=int(input->readULong(2));
    if (val&0x4)
      f << "postscript,";
    if (val&0x10) // useme: basically the text is hidden
      f << "white[type],";
    if (val&0x20)
      f << "ignore[run,around],";
    val&=0xffdb;
    if (val)
      f << "fl1=" << std::hex << val << std::dec << ",";
    ascFile.addDelimiter(input->tell(),'|');
    input->seek(pos+76+88, librevenge::RVNG_SEEK_SET);
    ascFile.addDelimiter(input->tell(),'@');
    shape.m_textId=int(input->readLong(2));
    f << "text[id]=" << shape.m_textId << ",";
    for (int i=0; i<2; ++i) {
      shape.m_linkIds[i]=int(input->readLong(2));
      if (shape.m_linkIds[i]==-1)
        continue;
      f << (i==0 ? "prev" : "next") << "[link]=" << shape.m_linkIds[i] << ",";
    }
    for (int i=0; i<2; ++i) {
      val=int(input->readLong(2));
      if (val!=-1)
        f << "g" << i << "=" << val << ",";
    }
    ascFile.addDelimiter(input->tell(),'@');
    bool hasBackPattern=false;
    uint8_t backPattern[8];
    for (auto &p : backPattern) {
      p=uint8_t(input->readULong(1));
      if (p) hasBackPattern=true;
    }
    if (hasBackPattern) {
      f << "back[pat]=[";
      for (auto const &p : backPattern) f << std::hex << int(p) << std::dec << ",";
      f << "],";
    }
    backColId=int(input->readLong(2));
    if (backColId!=60)
      f << "back[col,id]=" << backColId << ",";
    backPatId=int(input->readULong(1));
    if (backPatId!=nonePatId)
      f << "back[pat,id]=" << backPatId << ",";
    input->seek(1, librevenge::RVNG_SEEK_CUR);
    for (int i=0; i<3; ++i) {
      val=int(input->readLong(2));
      if (!val)
        continue;
      f << "g" << i+2 << "=" << val << ",";
    }
    val=int(input->readLong(1));
    switch (val) {
    case 0: // top
      break;
    case 1:
      style.m_verticalAlignment=MWAWGraphicStyle::V_AlignBottom;
      f << "vAlign=bottom,";
      break;
    case 2:
      style.m_verticalAlignment=MWAWGraphicStyle::V_AlignCenter;
      f << "vAlign=center,";
      break;
    case 3:
      style.m_verticalAlignment=MWAWGraphicStyle::V_AlignJustify;
      f << "vAlign=justify[feathering],";
      break;
    case 4:
      style.m_verticalAlignment=MWAWGraphicStyle::V_AlignJustify;
      f << "vAlign=justify[paragraph],";
      break;
    default:
      MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeDSV2[text]: unknown vertical alignment\n"));
      f << "##vAlign=" << val << ",";
      break;
    }
    val=int(input->readLong(1));
    if (val) f << "h0=" << val << ",";
  }
  val=int(input->readLong(1));
  int width=int(input->readULong(1));
  if (val>=0 && val<=8) {
    float const w[]= {0.125f, 0.25f, 0.5f, 0.75f, 1, 2, 4, 6, 8};
    style.m_lineWidth=w[val];
  }
  else if (val==9)
    style.m_lineWidth=float(width);
  else if (val>=11 && val<=14) {
    float const w[]= {1, 2, 4, 6, 8};
    style.m_lineWidth=w[val-11];
    f << "dash,";
    style.m_lineDashWidth= {10,10};
  }
  else if (val>=16 && val<=18) {
    // changeme: double line 2-1-1, 1-1-2, 1-1-1
    style.m_lineWidth=val==18 ? 3 : 4;
    f << "double[line],";
  }
  else {
    style.m_lineWidth=1;
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeDSV2[%d]: find unknown line style\n", type));
    f << "###line[style]=" << val << "[" << width << "],";
  }
  if (style.m_lineWidth<1 || style.m_lineWidth>1)
    f << "line[width]=" << style.m_lineWidth << ",";

  if (type==3) // fixme
    style.m_lineWidth=0;
  int numColors=(type<=2 || (type>=5 && type<=7)) ? 2 : 1;
  int patIds[2]; // 31 1
  for (auto &p : patIds) p=int(input->readULong(1));
  int colIds[2]= {-1,-1};
  MWAWColor colors[2]= {MWAWColor::white(), MWAWColor::black()};
  for (int i=0; i<numColors; ++i) {
    colIds[i]=int(input->readULong(2));
    int const expected[]= {7, 60};
    if (colIds[i]==(type==3 ? 60 : expected[i])) continue;
    if (numColors==1)
      f << "col=";
    else
      f << "col[" << (i==0 ? "surf" : "line") << "]=";
    if (colIds[i]>0 && m_styleManager->getColor(colIds[i], colors[i]))
      f << colors[i] << ",";
    else {
      f << "###" << colIds[i] << ",";
      colIds[i]=-1;
    }
  }

  switch (type) {
  case 0:
  case 1:
  case 2:
  case 5:
  case 6:
  case 7: {
    if (type==1) {
      int corner[2];
      for (auto &d : corner) d=int(input->readLong(2));
      shape.m_cornerSize=MWAWVec2i(corner[0], corner[1]);
      f << "corner=" << shape.m_cornerSize << ",";
    }
    if (type==5) { // we must retrieve the line points
      auto const &box=shape.m_box;
      if (box.size()[0]>box.size()[1]) {
        auto y=(box[0][1]+box[1][1])/2;
        shape.m_points[0]=MWAWVec2f(box[0][0],y);
        shape.m_points[1]=MWAWVec2f(box[1][0],y);
      }
      else {
        auto x=(box[0][0]+box[1][0])/2;
        shape.m_points[0]=MWAWVec2f(x,box[0][1]);
        shape.m_points[1]=MWAWVec2f(x,box[1][1]);
      }
      int arrowDim[3];
      for (auto &d: arrowDim) d=int(input->readLong(2));
      if (arrowDim[1]!=20 || arrowDim[2]!=10)
        f << "arrow[pt0]=" << MWAWVec2i(arrowDim[1], arrowDim[2]) << ",";
      if (arrowDim[0]!=20)
        f << "arrow[pt1]=" << MWAWVec2i(arrowDim[0], 0) << ",";
      float w=float(std::max<int>(5,arrowDim[2]));
      val=int(input->readULong(2));
      MWAWGraphicStyle::Arrow arrow;
      if (val&4) {
        // changeme normally the polygon is defined by O, pt0, pt1, arrowDim[1]x-arrowDim[2]
        f << "bound[arrow,only],";
        arrow=MWAWGraphicStyle::Arrow(w, MWAWBox2i(MWAWVec2i(0,0),MWAWVec2i(1122,2243)), "M0 2108v17 17l12 42 30 34 38 21 43 4 29-8 30-21 25-26 13-34 343-1532 339 1520 13 42 29 34 39 21 42 4 42-12 34-30 21-42v-39-12l-4 4-440-1998-9-42-25-39-38-25-43-8-42 8-38 25-26 39-8 42z", false);
      }
      else {
        bool ok=true;
        for (auto const &d : arrowDim) {
          if (d<=0) ok=false;
        }
        if (ok) {
          std::stringstream s;
          s << "M " << arrowDim[2] << " 0 "
            << 2*arrowDim[2] << " " << arrowDim[1] << " "
            << arrowDim[2] << " " << arrowDim[0] << " "
            << "0 " << arrowDim[1] << "z";
          arrow=MWAWGraphicStyle::Arrow(float(arrowDim[2]), MWAWBox2i(MWAWVec2i(0,0),MWAWVec2i(2*arrowDim[2],std::max(arrowDim[0],arrowDim[1]))), s.str(), false);
        }
        else
          arrow=MWAWGraphicStyle::Arrow(w, MWAWBox2i(MWAWVec2i(0,0),MWAWVec2i(20,30)), "m10 0l-10 30h20z", false);
      }
      if (val&1) {
        style.m_arrows[0]=arrow;
        f << "arrow[beg],";
      }
      if (val&2) {
        style.m_arrows[1]=arrow;
        f << "arrow[end],";
      }
      val&=0xfff8;
      if (val)
        f << "arrow[fl]=" << std::hex << val << std::dec << ",";
    }
    if (type==6) {
      float iDim[4];
      for (auto &d: iDim) d=float(input->readLong(2));
      shape.m_points[0]=MWAWVec2f(iDim[1],iDim[0]);
      shape.m_points[1]=MWAWVec2f(iDim[3],iDim[2]);
      f << "pos=" << shape.m_points[0] << "<->" << shape.m_points[1] << ",";
    }
    if (type==7) {
      numPoints=int(input->readULong(2));
      f << "N=" << numPoints << ",";
      val=int(input->readULong(2));
      if (val!=0x100)
        f << "g4=" << val << ",";
      auto ID=input->readULong(4);
      if (ID)
        f << "ID=" << std::hex << ID << std::dec << ",";
      // checkme
    }
    // time to set the patterns/colors
    if (patIds[0]!=nonePatId && (type!=5 && type!=6)) {
      MWAWGraphicStyle::Pattern pat;
      MWAWColor color;
      if (!m_styleManager->getPattern(patIds[0]-1, pat))
        f << "##surface[color]=" << patIds[0] << ",";
      else {
        if (colIds[0]>=0)
          pat.m_colors[0]=colors[0];
        if (pat.getUniqueColor(color)) {
          style.setSurfaceColor(color);
          f << "surface[color]=" << color << ",";
        }
        else {
          style.setPattern(pat);
          f << "surface[pat]=" << pat << ",";
        }
      }
    }
    if (patIds[1]==nonePatId) // transparent
      style.m_lineWidth=0;
    else {
      MWAWGraphicStyle::Pattern pat;
      MWAWColor color;
      if (!m_styleManager->getPattern(patIds[1]-1, pat))
        f << "##line[color]=" << patIds[1] << ",";
      else {
        if (colIds[1]>=0)
          pat.m_colors[0]=colors[1];
        if (pat.getAverageColor(style.m_lineColor))
          f << "line[color]=" << style.m_lineColor << ",";
        else {
          MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeDSV2[%d]: can not determine a shape color\n", type));
          f << "###line[color]=" << patIds[1] << ",";
        }
      }
    }
    break;
  }
  case 3: {
    if (patIds[0]!=4)
      f << "pattern[line]=" << patIds[0] << ",";
    if (vers==6) {
      val=int(input->readLong(2));
      if (val) f << "g4=" << val << ",";
    }
    val=int(input->readULong(2));
    if (val) {
      f << "num[pict]=" << val << ",";
      ++numPictures;
    }
    auto ID=int(input->readULong(4));
    if (ID)
      f << "ID[pict]=" << std::hex << ID << std::dec << ",";
    int iDim[2]; // some multiples of 6, link to decal?
    for (auto &d : iDim) d=int(input->readLong(2));
    if (iDim[0] || iDim[1])
      f << "crop=" << MWAWVec2i(iDim[1],iDim[0]) << ",";
    for (int i=0; i<2; ++i) {
      val=int(input->readULong(2));
      if (val!=100)
        f << "scale" << (i==0 ? "X" : "Y") << "=" << val << "%,";
    }
    long aPos=input->tell(); // checkme probably identical in v4.5
    std::string pictType;
    for (int i=0; i<4; ++i) {
      char c=char(input->readULong(1));
      if (!c) break;
      pictType+=c;
    }
    if (!pictType.empty())
      f << "type=" << pictType << ",";
    input->seek(aPos+4, librevenge::RVNG_SEEK_SET);
    val=int(input->readULong(2));
    if (val) // run around graphic/frame?, g2&200 print as gray
      f << "fl=" << std::hex << val << std::dec << ",";

    long actPos=input->tell();
    libmwaw::DebugStream f2;
    f2 << "Picture-A:";
    int cPos=int(input->readULong(1));
    std::string name;
    if (cPos>=32) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeDSV2[pict]: can not read the filename\n"));
      f2 << "###filename";
      cPos=0;
    }
    for (int i=0; i<cPos; ++i) {
      char c=char(input->readULong(1));
      if (!c) break;
      name+=c;
    }
    if (!name.empty())
      f2 << "file=" << name << ",";
    input->seek(actPos+314, librevenge::RVNG_SEEK_SET);
    ascFile.addDelimiter(input->tell(),'|');
    val=int(input->readULong(1));
    if (val)
      f << "shape=" << val << ",";
    ascFile.addPos(actPos);
    ascFile.addNote(f2.str().c_str());
    break;
  }
  case 4: {
    if (patIds[0]==nonePatId) // transparent
      style.m_lineWidth=0;
    else {
      MWAWGraphicStyle::Pattern pat;
      MWAWColor color;
      if (!m_styleManager->getPattern(patIds[0]-1, pat))
        f << "##line[color]=" << patIds[0] << ",";
      else {
        if (colIds[0]>=0)
          pat.m_colors[0]=colors[0];
        if (pat.getAverageColor(style.m_lineColor))
          f << "line[color]=" << style.m_lineColor << ",";
        else {
          MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeDSV2[%d]: can not determine a shape color\n", type));
          f << "###line[color]=" << patIds[0] << ",";
        }
      }
    }

    if (backPatId==nonePatId)
      break;

    MWAWColor color = MWAWColor::black();
    if (backColId!=60)
      m_styleManager->getColor(backColId, color);
    MWAWGraphicStyle::Pattern pat;
    if (backPatId<1 || !m_styleManager->getPattern(backPatId-1, pat))
      style.setSurfaceColor(color);
    else {
      pat.m_colors[0]=color;
      if (pat.getUniqueColor(color))
        style.setSurfaceColor(color);
      else
        style.setPattern(pat);
    }
    break;
  }
  default:
    MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeDSV2[%d]: unexpected data\n", type));
    f << "###";
    break;
  }
  if (input->tell()!=pos+6+len)
    ascFile.addDelimiter(input->tell(),'|');
  ascFile.addPos(pos);
  ascFile.addNote(f.str().c_str());
  input->seek(pos+6+len, librevenge::RVNG_SEEK_SET);

  for (int p=0; p<numPictures; ++p) {
    pos=input->tell();
    len=long(input->readLong(4));
    if ((len&0xffff)<7 || !input->checkPosition(pos+4+len)) {
      input->seek(pos, librevenge::RVNG_SEEK_SET);
      break;
    }
    shape.m_entries[p].setBegin(pos+4);
    shape.m_entries[p].setLength(len);
    input->seek(pos+4+len, librevenge::RVNG_SEEK_SET);
    ascFile.addPos(pos);
    ascFile.addNote("Picture-data:");
  }
  if (numPoints) { // FIXME
    pos=input->tell();
    len=long(input->readLong(4));
    if ((len&0xffff)<2 || !input->checkPosition(pos+4+len))
      input->seek(pos, librevenge::RVNG_SEEK_SET);
    else {
      f.str("");
      f << "Polygon-point:";
      int len2=int(input->readLong(2));
      if (len2>len || 2+4*(2+numPoints)>len2) {
        MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeDSV2: the number of points seems bad\n"));
        f << "###";
        numPoints=0;
      }
      f << "box=[";
      for (int i=0; i<2; ++i) {
        int pts[2];
        for (auto &pt : pts) pt=int(input->readLong(2));
        f << MWAWVec2i(pts[1], pts[0]) << ",";
      }
      f << "],";
      f << "pts=[";
      for (int i=0; i<numPoints; ++i) {
        float pts[2];
        for (auto &pt : pts) pt=float(input->readLong(2));
        shape.m_vertices.push_back(MWAWVec2f(pts[1], pts[0]));
        f << shape.m_vertices.back() << ",";
      }
      f << "],";
      input->seek(pos+4+len, librevenge::RVNG_SEEK_SET);
      ascFile.addPos(pos);
      ascFile.addNote(f.str().c_str());
    }
  }
  if (type==4) {
    pos=input->tell();
    f.str("");
    f << "Text-limits:";
    if (!input->checkPosition(pos+8)) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeDSV2: can not find the text limits positions\n"));
      f << "###";
      ascFile.addPos(pos);
      ascFile.addNote(f.str().c_str());
      return false;
    }
    for (int i=0; i<2; ++i) {
      shape.m_textPositions[i]=int(input->readLong(4));
      if (shape.m_textPositions[i]==0) continue;
      f << (i==0 ? "min[pos]" : "max[pos]") << "=" << shape.m_textPositions[i] << ",";
    }
    ascFile.addPos(pos);
    ascFile.addNote(f.str().c_str());
  }
  if (type==4 && shape.m_linkIds[0]<0) {
    for (int st=0; st<(!hasTabs ? 2 : 3); ++st) {
      pos=input->tell();
      len=long(input->readLong(4));
      if (len<10 || (long)((unsigned long)pos+4+(unsigned long)len)<pos+4 || !input->checkPosition(pos+4+len)) {
        MWAW_DEBUG_MSG(("ReadySetGoGraph::readShapeDSV2[text]: can not find a shape length\n"));
        input->seek(pos, librevenge::RVNG_SEEK_SET);
        f << "###";
        ascFile.addPos(pos);
        ascFile.addNote("Text-####");
        return false;
      }
      shape.m_entries[st].setBegin(pos+4);
      shape.m_entries[st].setLength(len);
      ascFile.addPos(pos);
      ascFile.addNote(st==0 ? "Text-text" : st==1 ? "Entries(Style):" : "Entries(Tabs):");
      input->seek(pos+4+len, librevenge::RVNG_SEEK_SET);
    }
  }
  layout.m_shapes.push_back(shape);
  return true;
}

////////////////////////////////////////////////////////////
// send data
////////////////////////////////////////////////////////////
bool ReadySetGoGraph::sendMasterPages()
{
  auto listener=m_parser.getGraphicListener();
  if (!listener) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::sendMasterPages: can not find the listener\n"));
    return false;
  }
  int const vers=version();
  if (vers<3)
    return true;
  bool const sharedList=vers<6 || (vers==6 && m_parser.isDesignStudioFile());
  auto const &layouts = sharedList ? m_state->m_layouts : m_state->m_masterLayouts;
  size_t const numMaster=sharedList ? std::min<size_t>(2,layouts.size()) : layouts.size();
  for (size_t layout=0; layout<numMaster; ++layout) {
    if (layouts[layout].m_shapes.empty())
      continue;
    MWAWPageSpan ps(m_parser.getPageSpan());
    librevenge::RVNGString name;
    name.sprintf("MasterPage%d", int(layout));
    ps.setMasterPageName(name);
    if (!listener->openMasterPage(ps)) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::sendMasterPages: can not create the master page\n"));
    }
    else {
      send(layouts[layout]);
      listener->closeMasterPage();
    }
  }
  return true;
}

bool ReadySetGoGraph::sendPages()
{
  auto listener=m_parser.getGraphicListener();
  if (!listener) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::sendPages: can not find the listener\n"));
    return false;
  }
  bool firstPage=true;
  int const vers=version();
  for (size_t layout=(vers<3 ? 0 : 2); layout<m_state->m_layouts.size(); ++layout) {
    if (!firstPage)
      listener->insertBreak(MWAWListener::PageBreak);
    send(m_state->m_layouts[layout]);
    firstPage=false;
  }
  return true;
}

bool ReadySetGoGraph::send(ReadySetGoGraphInternal::Layout const &layout)
{
  auto listener=m_parser.getGraphicListener();
  if (!listener) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::send[layout]: can not find the listener\n"));
    return false;
  }
  for (size_t i=0; i<layout.m_shapes.size();) {
    auto const &shape=layout.m_shapes[i];
    if (shape.m_groupId>0) {
      int group=shape.m_groupId;
      if (i+1<layout.m_shapes.size() && layout.m_shapes[i+1].m_groupId==group) {
        MWAWPosition pos(shape.m_box[0], shape.m_box.size(), librevenge::RVNG_POINT);
        pos.setRelativePosition(MWAWPosition::Page);
        if (listener->openGroup(pos)) {
          while (i<layout.m_shapes.size() && layout.m_shapes[i].m_groupId==group)
            send(layout.m_shapes[i++]);
          listener->closeGroup();
          continue;
        }
      }
    }
    ++i;
    send(shape);
  }
  return true;
}

bool ReadySetGoGraph::send(ReadySetGoGraphInternal::Shape const &shape)
{
  auto input=m_parser.getInput();
  auto listener=m_parser.getGraphicListener();
  if (!input || !listener) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::send: can not find the listener\n"));
    return false;
  }
  MWAWPosition pos(shape.m_box[0], shape.m_box.size(), librevenge::RVNG_POINT);
  pos.setRelativePosition(MWAWPosition::Page);
  if (shape.m_wrapRoundAround)
    pos.m_wrapping=MWAWPosition::WDynamic;
  MWAWGraphicShape gShape;
  switch (shape.m_type) {
  case ReadySetGoGraphInternal::Shape::T_Empty:
    return true;
  case ReadySetGoGraphInternal::Shape::T_Text: {
    auto subdoc=std::make_shared<ReadySetGoGraphInternal::SubDocument>(*this, input, shape);
    listener->insertTextBox(pos, subdoc, shape.m_style);
    return true;
  }
  case ReadySetGoGraphInternal::Shape::T_Line:
    gShape=MWAWGraphicShape::line(shape.m_box[0]+shape.m_points[0], shape.m_box[0]+shape.m_points[1]);
    break;
  case ReadySetGoGraphInternal::Shape::T_Oval:
    gShape=MWAWGraphicShape::circle(shape.m_box);
    break;
  case ReadySetGoGraphInternal::Shape::T_Rectangle:
    gShape=MWAWGraphicShape::rectangle(shape.m_box);
    break;
  case ReadySetGoGraphInternal::Shape::T_RectOval:
    gShape=MWAWGraphicShape::rectangle(shape.m_box, shape.m_cornerSize[0]>=0 ? 0.5f*MWAWVec2f(float(shape.m_cornerSize[0]), float(shape.m_cornerSize[1]))
                                       : 0.25f*shape.m_box.size());
    break;
  case ReadySetGoGraphInternal::Shape::T_Polygon:
    if (shape.m_vertices.size()<2) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::send[polygon]: sorry, the number of points seem bad\n"));
      return false;
    }
    if (shape.m_style.hasSurface())
      gShape=MWAWGraphicShape::polygon(shape.m_box);
    else
      gShape=MWAWGraphicShape::polyline(shape.m_box);
    gShape.m_vertices=shape.m_vertices;
    break;
  case ReadySetGoGraphInternal::Shape::T_Picture: {
    if (!shape.m_entries[0].valid() || !input->checkPosition(shape.m_entries[0].end())) {
      MWAWGraphicStyle style;
      listener->openGroup(pos);
      for (int w=0; w<3; ++w) {
        if (w==0)
          gShape=MWAWGraphicShape::rectangle(shape.m_box);
        else if (w==1)
          gShape=MWAWGraphicShape::line(shape.m_box[0],shape.m_box[1]);
        else
          gShape=MWAWGraphicShape::line(MWAWVec2f(shape.m_box[0][0],shape.m_box[1][1]), MWAWVec2f(shape.m_box[1][0],shape.m_box[0][1]));
        if (shape.m_rotate) {
          gShape=gShape.rotate(float(shape.m_rotate)/10, shape.m_box.center());
          auto box=gShape.getBdBox(shape.m_style);
          pos.setOrigin(box[0]);
          pos.setSize(box.size());
        }
        if (shape.m_style.m_flip[0]) {
          gShape.scale(MWAWVec2f(-1,1));
          pos.setOrigin(pos.origin()+MWAWVec2f(pos.size()[0],0));
        }
        if (shape.m_style.m_flip[1]) {
          gShape.scale(MWAWVec2f(1,-1));
          pos.setOrigin(pos.origin()+MWAWVec2f(0,pos.size()[1]));
        }

        listener->insertShape(pos, gShape, style);
      }
      listener->closeGroup();
      return true;
    }
    MWAWEmbeddedObject object;
    for (int w=0; w<2; w++) {
      if (!shape.m_entries[w].valid())
        continue;
      input->seek(shape.m_entries[w].begin(), librevenge::RVNG_SEEK_SET);
      std::shared_ptr<MWAWPict> pict(MWAWPictData::get(input, int(shape.m_entries[w].length())));
      MWAWEmbeddedObject image;
      if (pict && pict->getBinary(image) && !image.m_dataList.empty()) {
        object.add(image.m_dataList[0], !image.m_typeList.empty() ? image.m_typeList[0] : "image/pict");
#ifdef DEBUG_WITH_FILES
        static int volatile pictName = 0;
        libmwaw::DebugStream f2;
        f2 << "PICT-" << ++pictName << ".pct";
        libmwaw::Debug::dumpFile(object.m_dataList[0], f2.str().c_str());
        m_parser.ascii().skipZone(shape.m_entries[w].begin(), shape.m_entries[w].end()-1);
#endif
      }
      else {
        MWAW_DEBUG_MSG(("ReadySetGoGraph::send: sorry, can not retrieve a picture\n"));
      }
    }
    if (!object.isEmpty())
      listener->insertPicture(pos, object);
    return true;
  }
  case ReadySetGoGraphInternal::Shape::T_Unknown:
  default:
    MWAW_DEBUG_MSG(("ReadySetGoGraph::send: sorry sending a shape with type=%d is not implemented\n", int(shape.m_type)));
    return false;
  }
  if (shape.m_rotate) {
    gShape=gShape.rotate(float(shape.m_rotate)/10, shape.m_box.center());
    auto box=gShape.getBdBox(shape.m_style);
    pos.setOrigin(box[0]);
    pos.setSize(box.size());
  }
  if (shape.m_style.m_flip[0]) {
    gShape.scale(MWAWVec2f(-1,1));
    pos.setOrigin(pos.origin()+MWAWVec2f(pos.size()[0],0));
  }
  if (shape.m_style.m_flip[1]) {
    gShape.scale(MWAWVec2f(1,-1));
    pos.setOrigin(pos.origin()+MWAWVec2f(0,pos.size()[1]));
  }
  listener->insertShape(pos, gShape, shape.m_style);
  return true;
}

bool ReadySetGoGraph::sendText(ReadySetGoGraphInternal::Shape const &shape)
{
  auto input=m_parser.getInput();
  auto listener=m_parser.getGraphicListener();
  int const vers=version();
  bool const isDesign=m_parser.isDesignStudioFile();
  if (!input || !listener) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::sendText: can not find the listener\n"));
    return false;
  }
  if (shape.m_type!=shape.T_Text) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::sendText: unexpected type\n"));
    return false;
  }
  if (!shape.m_entries[0].valid() || shape.m_entries[0].length()<4 || !input->checkPosition(shape.m_entries[0].end())) {
    if (shape.m_linkIds[0]<0) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::sendText: can not find the character zone\n"));
      return false;
    }
    return true;
  }
  input->seek(shape.m_entries[0].begin(), librevenge::RVNG_SEEK_SET);
  libmwaw::DebugFile &ascFile = m_parser.ascii();
  libmwaw::DebugStream f;
  int const lengthSize=vers<3 ? 2 : 4;
  int len=int(input->readULong(lengthSize));
  long begTextPos=shape.m_entries[0].begin()+(vers<3 ? 2 : vers<6 ? 20 : 58);
  if (len+(vers<3 ? 2*lengthSize : vers<6 ? 20 : 58)>shape.m_entries[0].length()) {
    MWAW_DEBUG_MSG(("ReadySetGoGraph::sendText: can not find the character zone\n"));
    f << "###";
    ascFile.addPos(shape.m_entries[0].begin());
    ascFile.addNote("Text-text:###");
    return false;
  }

  int minCPos=0, maxCPos=len;

  // first try to read the pararagraph style: v1-v2 or the list of style v3
  auto fontConverter=m_parser.getFontConverter();
  std::map<int,MWAWFont> posToFont;
  std::map<int,MWAWParagraph> posToPara;
  std::map<int, std::vector<MWAWTabStop> > posToTabs;
  if (vers<3) {
    MWAWParagraph para=shape.m_paragraph;
    if (!shape.m_entries[1].valid() || shape.m_entries[1].length()!=0x1e || !input->checkPosition(shape.m_entries[1].end())) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::sendText: can not find the paragraph zone\n"));
    }
    else {
      input->seek(shape.m_entries[1].begin(), librevenge::RVNG_SEEK_SET);
      long pos=input->tell();
      f.str("");
      // unsure the first line's style is sometimes different than the
      // other lines', but the interface is so weird that it is
      // difficult to understand what happens
      for (int i=0; i<2; ++i) { // left and right margins from left,
        int val=int(input->readLong(2));
        if (val) f << "margins[" << (i==0 ? "left" : "right") << "]=" << val << ",";
      }
      int val=int(input->readLong(1));
      switch (val & 3) {
      case 1:
        para.m_justify = MWAWParagraph::JustificationCenter;
        break;
      case 2:
        para.m_justify = MWAWParagraph::JustificationRight;
        break;
      case 3:
        para.m_justify = MWAWParagraph::JustificationFull;
        break;
      case 0: // left
      default:
        break;
      }
      if (val&0xfc) f << "fl=" << std::hex << (val&0xfc) << std::dec << ",";
      int interline=0;
      for (int i=0; i<3; ++i) { // small number maybe another justification
        val=int(input->readLong(1));
        if (!val) continue;
        if ((i==0 && vers==1) || (i==2 && vers==2))
          interline=val;
        else
          f << "f" << i << "=" << val << ",";
      }
      switch (interline) {
      case 0: // normal
      case 1:
      case 2:
        para.setInterline(1+double(interline)/2, librevenge::RVNG_PERCENT);
        break;
      default:
        MWAW_DEBUG_MSG(("ReadySetGoGraph::sendText: unknown interline\n"));
        f << "interline=###" << interline << ",";
        break;
      }
      int dim[4];
      for (auto &d : dim) d=int(input->readLong(2));
      f << "box?=" << MWAWBox2i(MWAWVec2i(dim[0],dim[1]),MWAWVec2i(dim[2],dim[3])) << ",";
      f << para;
      ascFile.addDelimiter(input->tell(),'|');
      ascFile.addPos(pos-lengthSize);
      ascFile.addNote(f.str().c_str());
    }
    listener->setParagraph(para);

    // now read the list of char style
    input->seek(shape.m_entries[0].begin()+lengthSize+len+(len%2), librevenge::RVNG_SEEK_SET);
    long pos=input->tell();
    int cLen=int(input->readULong(lengthSize));
    f.str("");
    f << "Text-font:";
    if (pos+2+cLen>shape.m_entries[0].end() || (cLen%6)) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::sendText: can not find the find the number of fonts\n"));
      f << "###";
      cLen=0;
    }
    ascFile.addPos(pos);
    ascFile.addNote(f.str().c_str());
    for (int s=0; s<(cLen/6); ++s) {
      pos=input->tell();
      f.str("");
      f << "Text-font" << s << ":";
      int cPos=int(input->readULong(2));
      if (cPos) f << "pos=" << cPos << ",";
      MWAWFont font;
      font.setSize(float(input->readULong(1)));
      uint32_t flags=0;
      int val=int(input->readULong(1));
      if (val&0x1) flags |= MWAWFont::boldBit;
      if (val&0x2) flags |= MWAWFont::italicBit;
      if (val&0x4) font.setUnderlineStyle(MWAWFont::Line::Simple);
      if (val&0x8) flags |= MWAWFont::embossBit;
      if (val&0x10) flags |= MWAWFont::shadowBit;
      if (val&0xe0) f << "fl=#" << std::hex << (val&0xe0) << std::dec << ",";
      font.setFlags(flags);
      font.setId(int(input->readULong(2)));
      f << font.getDebugString(fontConverter)  << ",";
      if (posToFont.find(cPos)==posToFont.end())
        posToFont[cPos]=font;
      else {
        MWAW_DEBUG_MSG(("ReadySetGoGraph::sendText: find duplicated position for font's style\n"));
        f << "###";
      }
      ascFile.addPos(pos);
      ascFile.addNote(f.str().c_str());
      input->seek(pos+6, librevenge::RVNG_SEEK_SET);
    }


  }
  else {
    if (shape.m_entries[2].valid() && shape.m_entries[2].length()>2) {
      input->seek(shape.m_entries[2].begin(), librevenge::RVNG_SEEK_SET);

      int numPara=1;
      if (vers>3) {
        f.str("");
        numPara=int(input->readLong(2));
        f << "N=" << numPara << ",";
        if (2+(isDesign ? 218 : 148)*numPara>shape.m_entries[2].length()) {
          MWAW_DEBUG_MSG(("ReadySetGoGraph::sendText: can not determine the number of differents tabulation\n"));
          f << "###";
          numPara=0;
        }
        ascFile.addPos(shape.m_entries[2].begin()-4);
        ascFile.addNote(f.str().c_str());
      }

      for (int p=0; p<numPara; ++p) {
        int cPos=0;
        std::vector<MWAWTabStop> tabs;
        if (!m_styleManager->readTabulations(tabs, vers==3 ? shape.m_entries[2].length() : (isDesign ? 218 : 148), vers==3 ? nullptr : &cPos))
          break;
        posToTabs[cPos]=tabs;
      }
    }

    if (!shape.m_entries[1].valid() || shape.m_entries[1].length()<4 || !input->checkPosition(shape.m_entries[1].end())) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::sendText: can not find the style zone\n"));
    }
    else {
      input->seek(shape.m_entries[1].begin(), librevenge::RVNG_SEEK_SET);
      f.str("");
      int N=int(input->readLong(4));
      f << "N=" << N << ",";
      int const dataSize=vers==3 ? 26 : vers==4 ? 26 : vers==5 ? 34 : vers==6 ? 44 : 50;
      if (N<0 || (shape.m_entries[1].length()-4)/dataSize<N || 4+N*dataSize>shape.m_entries[1].length()) {
        f << "###";
        MWAW_DEBUG_MSG(("ReadySetGoGraph::sendText: can not find the number of styles\n"));
        N=0;
      }
      ascFile.addPos(shape.m_entries[1].begin()-4);
      ascFile.addNote(f.str().c_str());
      for (int s=0; s<N; ++s) {
        int cPos;
        MWAWFont font;
        MWAWParagraph para;
        if (!m_styleManager->readStyle(font,para,&cPos))
          break;
        if (vers>6)
          input->seek(6, librevenge::RVNG_SEEK_CUR);
        // the position can be sometimes dupplicated, so use the latter
        posToFont[cPos]=font;
        posToPara[cPos]=para;
      }
    }
    if (shape.m_entries[0].valid() && shape.m_entries[0].length()>=20) {
      input->seek(shape.m_entries[0].begin()+4, librevenge::RVNG_SEEK_SET);
      f.str("");
      f << "N=" << len << ",";
      for (int i=0; i<2; ++i) { // probably the selection
        int val=int(input->readLong(4));
        if (val!=len)
          f << "N" << i+1 << "=" << val << ",";
      }
      f << "IDS=[";
      for (int i=0; i<2; ++i) {
        auto val=input->readULong(4);
        if (val)
          f << std::hex << val << std::dec << ",";
        else
          f << "_,";
      }
      f << "],";
      ascFile.addPos(shape.m_entries[0].begin());
      ascFile.addNote(f.str().c_str());
    }
    if (vers>3) {
      // time to use the text limit
      if (shape.m_textPositions[0]<0 || shape.m_textPositions[0]>len) {
        MWAW_DEBUG_MSG(("ReadySetGoGraph::sendText: the minimum position seems bad\n"));
      }
      else
        minCPos=shape.m_textPositions[0];
      if (shape.m_textPositions[1]<minCPos || shape.m_textPositions[1]>len) {
        MWAW_DEBUG_MSG(("ReadySetGoGraph::sendText: the maximum position seems bad\n"));
      }
      // min=max=0 means all data
      // if there is not a next frame, we do not want to cut the text
      else if (shape.m_textPositions[1]>0 && shape.m_textPositions[1]+1<len && shape.m_linkIds[1]>=0)
        maxCPos=shape.m_textPositions[1]+1;
    }
  }

  f.str("");
  f << "Text-text:";
  input->seek(begTextPos+minCPos, librevenge::RVNG_SEEK_SET);
  std::vector<MWAWTabStop> tabs;
  MWAWParagraph para;
  if (minCPos!=0) {
    // we need to retrieve the current style
    auto tIt=posToTabs.lower_bound(minCPos);
    if (tIt!=posToTabs.begin()) {
      --tIt;
      tabs=tIt->second;
      para.m_tabs=tabs;
      listener->setParagraph(para);
    }
    auto pIt=posToPara.lower_bound(minCPos);
    if (pIt!=posToPara.begin()) {
      --pIt;
      para=pIt->second;
      para.m_tabs=tabs;
      listener->setParagraph(para);
    }
    auto fIt=posToFont.lower_bound(minCPos);
    if (fIt!=posToFont.begin()) {
      --fIt;
      listener->setFont(fIt->second);
    }
  }
  for (int c=minCPos; c<maxCPos; ++c) {
    auto tIt=posToTabs.find(c);
    if (tIt!=posToTabs.end()) {
      tabs=tIt->second;
      para.m_tabs=tabs;
      listener->setParagraph(para);
    }
    auto pIt=posToPara.find(c);
    if (pIt!=posToPara.end()) {
      para=pIt->second;
      para.m_tabs=tabs;
      listener->setParagraph(para);
    }
    auto fIt=posToFont.find(c);
    if (fIt!=posToFont.end())
      listener->setFont(fIt->second);
    if (input->isEnd()) {
      MWAW_DEBUG_MSG(("ReadySetGoGraph::sendText: find end of input at pos=%d\n", c));
      f << "###";
      break;
    }
    unsigned char ch=(unsigned char)(input->readULong(1));
    if (ch)
      f << ch;
    else
      f << "[#page]";
    switch (ch) {
    case 0:
      listener->insertField(MWAWField(MWAWField::PageNumber));
      break;
    case 5:
      listener->insertField(MWAWField(MWAWField::PageCount));
      break;
    case 0x9:
      listener->insertTab();
      break;
    // case 0xb: column break, useme
    case 0xd:
      listener->insertEOL();
      break;
    case 0x1f: // soft hyphen
      break;
    default:
      if (ch<=0x1f) {
        MWAW_DEBUG_MSG(("ReadySetGoGraph::sendText: find unknown char=%d at pos=%d\n", int(ch), c));
        f << "###";
        break;
      }
      listener->insertCharacter(ch);
    }
  }
  ascFile.addPos(shape.m_entries[0].begin());
  ascFile.addNote(f.str().c_str());
  return true;
}
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab:
