<commit_before>/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* libvisio
 * Version: MPL 1.1 / GPLv2+ / LGPLv2+
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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) 2011 <NAME> <<EMAIL>>
 * Copyright (C) 2011 <NAME> <<EMAIL>>
 *
 *
 * All Rights Reserved.
 *
 * For minor contributions see the git repository.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
 * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
 * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
 * instead of those above.
 */

#include <libwpd-stream/libwpd-stream.h>
#include <locale.h>
#include <sstream>
#include <string>
#include <cmath>
#include <set>
#include "libvisio_utils.h"
#include "VSDParser.h"
#include "VSDInternalStream.h"
#include "VSDDocumentStructure.h"
#include "VSDContentCollector.h"
#include "VSDStylesCollector.h"

libvisio::VSDParser::VSDParser(WPXInputStream *input, libwpg::WPGPaintInterface *painter)
  : m_input(input), m_painter(painter), m_header(), m_collector(0), m_geomList(new VSDGeometryList()),
    m_geomListVector(), m_fieldList(), m_charList(new VSDCharacterList()),
    m_paraList(new VSDParagraphList()), m_charListVector(), m_paraListVector(),
    m_shapeList(), m_currentLevel(0), m_stencils(), m_currentStencil(0),
    m_stencilShape(), m_isStencilStarted(false), m_isInStyles(false), m_currentShapeLevel(0),
    m_currentShapeID((unsigned)-1),
    m_extractStencils(false), m_colours()
{}

libvisio::VSDParser::~VSDParser()
{
  if (m_geomList)
  {
    m_geomList->clear();
    delete m_geomList;
  }
  if (m_charList)
  {
    m_charList->clear();
    delete m_charList;
  }
  if (m_paraList)
  {
    m_paraList->clear();
    delete m_paraList;
  }
}

bool libvisio::VSDParser::parseMain()
{
  if (!m_input)
  {
    return false;
  }
  // Seek to trailer stream pointer
  m_input->seek(0x24, WPX_SEEK_SET);

  m_input->seek(8, WPX_SEEK_CUR);
  unsigned offset = readU32(m_input);
  unsigned length = readU32(m_input);
  unsigned short format = readU16(m_input);
  bool compressed = ((format & 2) == 2);

  m_input->seek(offset, WPX_SEEK_SET);
  VSDInternalStream trailerStream(m_input, length, compressed);

  std::vector<std::map<unsigned, XForm> > groupXFormsSequence;
  std::vector<std::map<unsigned, unsigned> > groupMembershipsSequence;
  std::vector<std::list<unsigned> > documentPageShapeOrders;

  VSDStylesCollector stylesCollector(groupXFormsSequence, groupMembershipsSequence, documentPageShapeOrders);
  m_collector = &stylesCollector;
  if (!parseDocument(&trailerStream))
    return false;

  VSDStyles styles = stylesCollector.getStyleSheets();

  VSDContentCollector contentCollector(m_painter, groupXFormsSequence, groupMembershipsSequence, documentPageShapeOrders, styles, m_stencils);
  m_collector = &contentCollector;
  if (!parseDocument(&trailerStream))
    return false;

  return true;
}

bool libvisio::VSDParser::parseDocument(WPXInputStream *input)
{
  try
  {
    handleStreams(input, 4, 0);
    return true;
  }
  catch (...)
  {
    return false;
  }
}

bool libvisio::VSDParser::extractStencils()
{
  m_extractStencils = true;
  return parseMain();
}

void libvisio::VSDParser::handleStreams(WPXInputStream *input, unsigned shift, unsigned level)
{
  // Parse out pointers to streams
  input->seek(shift, WPX_SEEK_SET);
  unsigned offset = readU32(input);
  input->seek(offset+shift-4, WPX_SEEK_SET);
  unsigned listSize = readU32(input);
  unsigned pointerCount = readU32(input);
  input->seek(4, WPX_SEEK_CUR);
  std::map<unsigned, libvisio::Pointer> PtrList;
  std::map<unsigned, libvisio::Pointer> FontFaces;
  unsigned i = 0;
  for (i = 0; i < pointerCount; i++)
  {
    Pointer ptr;
    ptr.Type = readU32(input);
    input->seek(4, WPX_SEEK_CUR); // Skip dword
    ptr.Offset = readU32(input);
    ptr.Length = readU32(input);
    ptr.Format = readU16(input);
    if (ptr.Type == VSD_FONTFACES)
      FontFaces[i] = ptr;
    else if (ptr.Type != 0)
      PtrList[i] = ptr;
  }
  std::vector<unsigned> pointerOrder;
  for (i = 0; i < listSize; ++i)
    pointerOrder.push_back(readU32(input));

  std::map<unsigned, libvisio::Pointer>::iterator iter;

  for (iter = FontFaces.begin(); iter != FontFaces.end(); ++iter)
    handleStream(iter->second, iter->first, level+1);

  if (!pointerOrder.empty())
  {
    for (i=0; i < pointerOrder.size(); ++i)
    {
      iter = PtrList.find(pointerOrder[i]);
      if (iter != PtrList.end())
      {
        handleStream(iter->second, iter->first, level+1);
        PtrList.erase(iter);
      }
    }
  }
  for (iter = PtrList.begin(); iter != PtrList.end(); ++iter)
    handleStream(iter->second, iter->first, level+1);

}


void libvisio::VSDParser::handleStream(const Pointer &ptr, unsigned idx, unsigned level)
{
  m_header.level = level;
  m_header.id = idx;
  m_header.chunkType = ptr.Type;
  _handleLevelChange(level);
  VSDStencil tmpStencil;
  bool compressed = ((ptr.Format & 2) == 2);
  m_input->seek(ptr.Offset, WPX_SEEK_SET);
  VSDInternalStream tmpInput(m_input, ptr.Length, compressed);
  unsigned shift = compressed ? 4 : 0;

  VSD_DEBUG_MSG(("VSDParser::handleStream: level %i, ptr.Type 0x%.8x, ptr.Offset 0x%.8x, ptr.Length 0x%.8x, ptr.Format 0x%.4x\n",
                 level, ptr.Type, ptr.Offset, ptr.Length, ptr.Format));

  switch (ptr.Type)
  {
  case VSD_STYLES:<commit_msg>Our assumptions about stream formats are a bit fragile, so don't fail if we are not right<commit_after>/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* libvisio
 * Version: MPL 1.1 / GPLv2+ / LGPLv2+
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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) 2011 <NAME> <<EMAIL>>
 * Copyright (C) 2011 <NAME> <<EMAIL>>
 *
 *
 * All Rights Reserved.
 *
 * For minor contributions see the git repository.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
 * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
 * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
 * instead of those above.
 */

#include <libwpd-stream/libwpd-stream.h>
#include <locale.h>
#include <sstream>
#include <string>
#include <cmath>
#include <set>
#include "libvisio_utils.h"
#include "VSDParser.h"
#include "VSDInternalStream.h"
#include "VSDDocumentStructure.h"
#include "VSDContentCollector.h"
#include "VSDStylesCollector.h"

libvisio::VSDParser::VSDParser(WPXInputStream *input, libwpg::WPGPaintInterface *painter)
  : m_input(input), m_painter(painter), m_header(), m_collector(0), m_geomList(new VSDGeometryList()),
    m_geomListVector(), m_fieldList(), m_charList(new VSDCharacterList()),
    m_paraList(new VSDParagraphList()), m_charListVector(), m_paraListVector(),
    m_shapeList(), m_currentLevel(0), m_stencils(), m_currentStencil(0),
    m_stencilShape(), m_isStencilStarted(false), m_isInStyles(false), m_currentShapeLevel(0),
    m_currentShapeID((unsigned)-1),
    m_extractStencils(false), m_colours()
{}

libvisio::VSDParser::~VSDParser()
{
  if (m_geomList)
  {
    m_geomList->clear();
    delete m_geomList;
  }
  if (m_charList)
  {
    m_charList->clear();
    delete m_charList;
  }
  if (m_paraList)
  {
    m_paraList->clear();
    delete m_paraList;
  }
}

bool libvisio::VSDParser::parseMain()
{
  if (!m_input)
  {
    return false;
  }
  // Seek to trailer stream pointer
  m_input->seek(0x24, WPX_SEEK_SET);

  m_input->seek(8, WPX_SEEK_CUR);
  unsigned offset = readU32(m_input);
  unsigned length = readU32(m_input);
  unsigned short format = readU16(m_input);
  bool compressed = ((format & 2) == 2);

  m_input->seek(offset, WPX_SEEK_SET);
  VSDInternalStream trailerStream(m_input, length, compressed);

  std::vector<std::map<unsigned, XForm> > groupXFormsSequence;
  std::vector<std::map<unsigned, unsigned> > groupMembershipsSequence;
  std::vector<std::list<unsigned> > documentPageShapeOrders;

  VSDStylesCollector stylesCollector(groupXFormsSequence, groupMembershipsSequence, documentPageShapeOrders);
  m_collector = &stylesCollector;
  if (!parseDocument(&trailerStream))
    return false;

  VSDStyles styles = stylesCollector.getStyleSheets();

  VSDContentCollector contentCollector(m_painter, groupXFormsSequence, groupMembershipsSequence, documentPageShapeOrders, styles, m_stencils);
  m_collector = &contentCollector;
  if (!parseDocument(&trailerStream))
    return false;

  return true;
}

bool libvisio::VSDParser::parseDocument(WPXInputStream *input)
{
  try
  {
    handleStreams(input, 4, 0);
    return true;
  }
  catch (...)
  {
    return false;
  }
}

bool libvisio::VSDParser::extractStencils()
{
  m_extractStencils = true;
  return parseMain();
}

void libvisio::VSDParser::handleStreams(WPXInputStream *input, unsigned shift, unsigned level)
{
  try
  {
    // Parse out pointers to streams
    input->seek(shift, WPX_SEEK_SET);
    unsigned offset = readU32(input);
    input->seek(offset+shift-4, WPX_SEEK_SET);
    unsigned listSize = readU32(input);
    unsigned pointerCount = readU32(input);
    input->seek(4, WPX_SEEK_CUR);
    std::map<unsigned, libvisio::Pointer> PtrList;
    std::map<unsigned, libvisio::Pointer> FontFaces;
    unsigned i = 0;
    for (i = 0; i < pointerCount; i++)
    {
      Pointer ptr;
      ptr.Type = readU32(input);
      input->seek(4, WPX_SEEK_CUR); // Skip dword
      ptr.Offset = readU32(input);
      ptr.Length = readU32(input);
      ptr.Format = readU16(input);
      if (ptr.Type == VSD_FONTFACES)
        FontFaces[i] = ptr;
      else if (ptr.Type != 0)
        PtrList[i] = ptr;
    }
    std::vector<unsigned> pointerOrder;
    for (i = 0; i < listSize; ++i)
      pointerOrder.push_back(readU32(input));

    std::map<unsigned, libvisio::Pointer>::iterator iter;

    for (iter = FontFaces.begin(); iter != FontFaces.end(); ++iter)
      handleStream(iter->second, iter->first, level+1);

    if (!pointerOrder.empty())
    {
      for (i=0; i < pointerOrder.size(); ++i)
      {
        iter = PtrList.find(pointerOrder[i]);
        if (iter != PtrList.end())
        {
          handleStream(iter->second, iter->first, level+1);
          PtrList.erase(iter);
        }
      }
    }
    for (iter = PtrList.begin(); iter != PtrList.end(); ++iter)
      handleStream(iter->second, iter->first, level+1);
  }
  catch (...)
  {
  }

}


void libvisio::VSDParser::handleStream(const Pointer &ptr, unsigned idx, unsigned level)
{
  m_header.level = level;
  m_header.id = idx;
  m_header.chunkType = ptr.Type;
  _handleLevelChange(level);
  VSDStencil tmpStencil;
  bool compressed = ((ptr.Format & 2) == 2);
  m_input->seek(ptr.Offset, WPX_SEEK_SET);
  VSDInternalStream tmpInput(m_input, ptr.Length, compressed);
  unsigned shift = compressed ? 4 : 0;

  VSD_DEBUG_MSG(("VSDParser::handleStream: level %i, ptr.Type 0x%.8x, ptr.Offset 0x%.8x, ptr.Length 0x%.8x, ptr.Format 0x%.4x\n",
                 level, ptr.Type, ptr.Offset, ptr.Length, ptr.Format));

  switch (ptr.Type)
  {
  case VSD_STYLES:
{'fraction_non_alphanumeric': 0.13267148014440433, 'fraction_numerical': 0.013127666557269446, 'mean_word_length': 4.189016602809707, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 81, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3789027', 'n_tokens_mistral': 4315, 'n_tokens_neox': 4166, 'n_words': 1007}