<commit_before>/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
 * This file is part of the libabw project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <string.h>
#include <libxml/xmlIO.h>
#include <libxml/xmlstring.h>
#include <librevenge-stream/librevenge-stream.h>
#include <boost/algorithm/string.hpp>
#include "ABWParser.h"
#include "ABWCollector.h"
#include "libabw_internal.h"
#include "ABWXMLHelper.h"
#include "ABWXMLTokenMap.h"

libabw::ABWParser::ABWParser(librevenge::RVNGInputStream *input, librevenge::RVNGTextInterface *iface)
  : m_input(input), m_iface(iface), m_collector(0), m_inParagraph(false)
{
}

libabw::ABWParser::~ABWParser()
{
}

bool libabw::ABWParser::parse()
{
  if (!m_input)
    return false;

  try
  {
    ABWCollector collector(m_iface);
    m_collector = &collector;
    m_input->seek(0, librevenge::RVNG_SEEK_SET);
    if (!processXmlDocument(m_input))
      return false;

    return true;
  }
  catch (...)
  {
    return false;
  }
}

bool libabw::ABWParser::processXmlDocument(librevenge::RVNGInputStream *input)
{
  if (!input)
    return false;

  xmlTextReaderPtr reader = xmlReaderForStream(input, 0, 0, XML_PARSE_NOBLANKS|XML_PARSE_NOENT|XML_PARSE_NONET|XML_PARSE_RECOVER);
  if (!reader)
    return false;
  int ret = xmlTextReaderRead(reader);
  while (1 == ret)
  {
    int tokenType = xmlTextReaderNodeType(reader);
    if (XML_READER_TYPE_SIGNIFICANT_WHITESPACE != tokenType)
      processXmlNode(reader);

    ret = xmlTextReaderRead(reader);
  }
  xmlFreeTextReader(reader);

  if (m_collector)
    m_collector->endDocument();
  return true;
}

void libabw::ABWParser::processXmlNode(xmlTextReaderPtr reader)
{
  if (!reader)
    return;
  int tokenId = getElementToken(reader);
  int tokenType = xmlTextReaderNodeType(reader);
  if (XML_READER_TYPE_TEXT == tokenType)
  {
    librevenge::RVNGString text((const char *)xmlTextReaderConstValue(reader));
    ABW_DEBUG_MSG(("ABWParser::processXmlNode: text %s\n", text.cstr()));
    if (m_inParagraph && m_collector)
      m_collector->insertText(text);
  }
  switch (tokenId)
  {
  case XML_METADATA:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readMetadata(reader);
    break;
  case XML_HISTORY:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readHistory(reader);
    break;
  case XML_REVISIONS:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readRevisions(reader);
    break;
  case XML_IGNOREDWORDS:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readIgnoredWords(reader);
    break;
  case XML_S:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readS(reader);
    break;
  case XML_LISTS:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readLists(reader);
    break;
  case XML_PAGESIZE:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readPageSize(reader);
    break;
  case XML_SECTION:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readSection(reader);
    else if (XML_READER_TYPE_END_ELEMENT == tokenType)
      if (m_collector)
        m_collector->endSection();
    break;
  case XML_DATA:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readData(reader);
    break;
  case XML_P:
    if (XML_READER_TYPE_ELEMENT == tokenType)
    {
      readP(reader);
      m_inParagraph = true;
    }
    else if (XML_READER_TYPE_END_ELEMENT == tokenType)
    {
      m_inParagraph = false;
      if (m_collector)
        m_collector->closeParagraph();
    }
    break;
#if 0
  case XML_TABLE:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readTable(reader);
    break;
  case XML_FRAME:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readFrame(reader);
    break;
#endif
  case XML_C:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readC(reader);
    else if (XML_READER_TYPE_END_ELEMENT == tokenType)
      if (m_collector)
        m_collector->closeSpan();
    break;
  case XML_CBR:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      m_collector->insertColumnBreak();
    break;
  case XML_PBR:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      m_collector->insertPageBreak();
    break;
  case XML_BR:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      m_collector->insertLineBreak();
    break;
  case XML_A:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readA(reader);
    else if (XML_READER_TYPE_END_ELEMENT == tokenType)
      m_collector->closeLink();
    break;
  case XML_FOOT:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readFoot(reader);
    else if (XML_READER_TYPE_END_ELEMENT == tokenType)
      m_collector->closeFoot();
    break;
  case XML_ENDNOTE:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readEndnote(reader);
    else if (XML_READER_TYPE_END_ELEMENT == tokenType)
      m_collector->closeEndnote();
    break;
  default:
    break;
  }

#ifdef DEBUG
  const xmlChar *name = xmlTextReaderConstName(reader);
  const xmlChar *value = xmlTextReaderConstValue(reader);
  int isEmptyElement = xmlTextReaderIsEmptyElement(reader);

  ABW_DEBUG_MSG(("%i %i %s", isEmptyElement, tokenType, name ? (const char *)name : ""));
  if (xmlTextReaderNodeType(reader) == 1)
  {
    while (xmlTextReaderMoveToNextAttribute(reader))
    {
      const xmlChar *name1 = xmlTextReaderConstName(reader);
      const xmlChar *value1 = xmlTextReaderConstValue(reader);
      printf(" %s=\"%s\"", name1, value1);
    }
  }

  if (!value)
    ABW_DEBUG_MSG(("\n"));
  else
  {
    ABW_DEBUG_MSG((" %s\n", value));
  }
#endif
}

int libabw::ABWParser::getElementToken(xmlTextReaderPtr reader)
{
  return ABWXMLTokenMap::getTokenId(xmlTextReaderConstName(reader));
}

void libabw::ABWParser::readMetadata(xmlTextReaderPtr reader)
{
  int ret = 1;
  int tokenId = XML_TOKEN_INVALID;
  int tokenType = -1;
  do
  {
    ret = xmlTextReaderRead(reader);
    tokenId = getElementToken(reader);
    if (XML_TOKEN_INVALID == tokenId)
    {
      ABW_DEBUG_MSG(("ABWParser::readMetadata: unknown token %s\n", xmlTextReaderConstName(reader)));
    }
    tokenType = xmlTextReaderNodeType(reader);
    switch (tokenId)
    {
    default:
      break;
    }
  }
  while ((XML_METADATA != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
}

void libabw::ABWParser::readHistory(xmlTextReaderPtr reader)
{
  int ret = 1;
  int tokenId = XML_TOKEN_INVALID;
  int tokenType = -1;
  do
  {
    ret = xmlTextReaderRead(reader);
    tokenId = getElementToken(reader);
    if (XML_TOKEN_INVALID == tokenId)
    {
      ABW_DEBUG_MSG(("ABWParser::readHistory: unknown token %s\n", xmlTextReaderConstName(reader)));
    }
    tokenType = xmlTextReaderNodeType(reader);
    switch (tokenId)
    {
    default:
      break;
    }
  }
  while ((XML_HISTORY != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
}

void libabw::ABWParser::readRevisions(xmlTextReaderPtr reader)
{
  int ret = 1;
  int tokenId = XML_TOKEN_INVALID;
  int tokenType = -1;
  do
  {
    ret = xmlTextReaderRead(reader);
    tokenId = getElementToken(reader);
    if (XML_TOKEN_INVALID == tokenId)
    {
      ABW_DEBUG_MSG(("ABWParser::readRevisions: unknown token %s\n", xmlTextReaderConstName(reader)));
    }
    tokenType = xmlTextReaderNodeType(reader);
    (void)tokenType;
    switch (tokenId)
    {
    default:
      break;
    }
  }
  while ((XML_REVISIONS != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
}

void libabw::ABWParser::readIgnoredWords(xmlTextReaderPtr reader)
{
  int ret = 1;
  int tokenId = XML_TOKEN_INVALID;
  int tokenType = -1;
  do
  {
    ret = xmlTextReaderRead(reader);
    tokenId = getElementToken(reader);
    if (XML_TOKEN_INVALID == tokenId)
    {
      ABW_DEBUG_MSG(("ABWParser::readIgnoreWords: unknown token %s\n", xmlTextReaderConstName(reader)));
    }
    tokenType = xmlTextReaderNodeType(reader);
    switch (tokenId)
    {
    default:
      break;
    }
  }
  while ((XML_IGNOREDWORDS != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
}

void libabw::ABWParser::readLists(xmlTextReaderPtr reader)
{
  int ret = 1;
  int tokenId = XML_TOKEN_INVALID;
  int tokenType = -1;
  do
  {
    ret = xmlTextReaderRead(reader);
    tokenId = getElementToken(reader);
    if (XML_TOKEN_INVALID == tokenId)
    {
      ABW_DEBUG_MSG(("ABWParser::readLists: unknown token %s\n", xmlTextReaderConstName(reader)));
    }
    tokenType = xmlTextReaderNodeType(reader);
    switch (tokenId)
    {
    default:
      break;
    }
  }
  while ((XML_LISTS != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
}

void libabw::ABWParser::readPageSize(xmlTextReaderPtr reader)
{
  xmlChar *width = xmlTextReaderGetAttribute(reader, BAD_CAST("width"));
  xmlChar *height = xmlTextReaderGetAttribute(reader, BAD_CAST("height"));
  xmlChar *units = xmlTextReaderGetAttribute(reader, BAD_CAST("units"));
  xmlChar *pageScale = xmlTextReaderGetAttribute(reader, BAD_CAST("page-scale"));
  if (m_collector)
    m_collector->collectPageSize((const char *)width, (const char *)height, (const char *)units, (const char *)pageScale);
  if (width)
    xmlFree(width);
  if (height)
    xmlFree(height);
  if (units)
    xmlFree(units);
  if (pageScale)
    xmlFree(pageScale);
}

void libabw::ABWParser::readSection(xmlTextReaderPtr reader)
{
  xmlChar *props = xmlTextReaderGetAttribute(reader, BAD_CAST("props"));
  if (m_collector)
    m_collector->collectSectionProperties((const char *)props);
  if (props)
    xmlFree(props);
}

void libabw::ABWParser::readData(xmlTextReaderPtr reader)
{
  int ret = 1;
  int tokenId = XML_TOKEN_INVALID;
  int tokenType = -1;
  do
  {
    ret = xmlTextReaderRead(reader);
    tokenId = getElementToken(reader);
    if (XML_TOKEN_INVALID == tokenId)
    {
      ABW_DEBUG_MSG(("ABWParser::readData: unknown token %s\n", xmlTextReaderConstName(reader)));
    }
    tokenType = xmlTextReaderNodeType(reader);
    switch (tokenId)
    {
    default:
      break;
    }
  }
  while ((XML_DATA != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
}

void libabw::ABWParser::readS(xmlTextReaderPtr reader)
{
  xmlChar *type = xmlTextReaderGetAttribute(reader, BAD_CAST("type"));
  xmlChar *name = xmlTextReaderGetAttribute(reader, BAD_CAST("name"));
  xmlChar *basedon = xmlTextReaderGetAttribute(reader, BAD_CAST("basedon"));
  xmlChar *followedby = xmlTextReaderGetAttribute(reader, BAD_CAST("followedby"));
  xmlChar *props = xmlTextReaderGetAttribute(reader, BAD_CAST("props"));
  if (type)
  {
    if (m_collector)
    {
      switch (type[0])
      {
      case 'P':
      case 'C':
        m_collector->collectTextStyle((const char *)name, (const char *)basedon, (const char *)followedby, (const char *)props);
        break;
      default:
        break;
      }
    }
    xmlFree(type);
  }
  if (name)
    xmlFree(name);
  if (basedon)
    xmlFree(basedon);
  if (followedby)
    xmlFree(followedby);
  if (props)
    xmlFree(props);
}

void libabw::ABWParser::readA(xmlTextReaderPtr reader)
{
  xmlChar *href = xmlTextReaderGetAttribute(reader, BAD_CAST("xlink:href"));
  if (m_collector)
    m_collector->openLink((const char *)href);
  if (href)
    xmlFree(href);
}

void libabw::ABWParser::readP(xmlTextReaderPtr reader)
{
  xmlChar *style = xmlTextReaderGetAttribute(reader, BAD_CAST("style"));
  xmlChar *props = xmlTextReaderGetAttribute(reader, BAD_CAST("props"));
  if (m_collector)
    m_collector->collectParagraphProperties((const char *)style, (const char *)props);
  if (style)
    xmlFree(style);
  if (props)
    xmlFree(props);
}

void libabw::ABWParser::readC(xmlTextReaderPtr reader)
{
  xmlChar *style = xmlTextReaderGetAttribute(reader, BAD_CAST("style"));
  xmlChar *props = xmlTextReaderGetAttribute(reader, BAD_CAST("props"));
  if (m_collector)
    m_collector->collectCharacterProperties((const char *)style, (const char *)props);
  if (style)
    xmlFree(style);
  if (props)
    xmlFree(props);

}

void libabw::ABWParser::readEndnote(xmlTextReaderPtr reader)
{
  xmlChar *id = xmlTextReaderGetAttribute(reader, BAD_CAST("endnote-id"));
  if (m_collector)
    m_collector->openEndnote((const char *)id);
  if (id)
    xmlFree(id);
}

void libabw::ABWParser::readFoot(xmlTextReaderPtr reader)
{
  xmlChar *id = xmlTextReaderGetAttribute(reader, BAD_CAST("footnote-id"));
  if (m_collector)
    m_collector->openFoot((const char *)id);
  if (id)
    xmlFree(id);
}

/* vim:set shiftwidth=2 softtabstop=2 expandtab: */
<commit_msg>Handle empty elements<commit_after>/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
 * This file is part of the libabw project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <string.h>
#include <libxml/xmlIO.h>
#include <libxml/xmlstring.h>
#include <librevenge-stream/librevenge-stream.h>
#include <boost/algorithm/string.hpp>
#include "ABWParser.h"
#include "ABWCollector.h"
#include "libabw_internal.h"
#include "ABWXMLHelper.h"
#include "ABWXMLTokenMap.h"

libabw::ABWParser::ABWParser(librevenge::RVNGInputStream *input, librevenge::RVNGTextInterface *iface)
  : m_input(input), m_iface(iface), m_collector(0), m_inParagraph(false)
{
}

libabw::ABWParser::~ABWParser()
{
}

bool libabw::ABWParser::parse()
{
  if (!m_input)
    return false;

  try
  {
    ABWCollector collector(m_iface);
    m_collector = &collector;
    m_input->seek(0, librevenge::RVNG_SEEK_SET);
    if (!processXmlDocument(m_input))
      return false;

    return true;
  }
  catch (...)
  {
    return false;
  }
}

bool libabw::ABWParser::processXmlDocument(librevenge::RVNGInputStream *input)
{
  if (!input)
    return false;

  xmlTextReaderPtr reader = xmlReaderForStream(input, 0, 0, XML_PARSE_NOBLANKS|XML_PARSE_NOENT|XML_PARSE_NONET|XML_PARSE_RECOVER);
  if (!reader)
    return false;
  int ret = xmlTextReaderRead(reader);
  while (1 == ret)
  {
    int tokenType = xmlTextReaderNodeType(reader);
    if (XML_READER_TYPE_SIGNIFICANT_WHITESPACE != tokenType)
      processXmlNode(reader);

    ret = xmlTextReaderRead(reader);
  }
  xmlFreeTextReader(reader);

  if (m_collector)
    m_collector->endDocument();
  return true;
}

void libabw::ABWParser::processXmlNode(xmlTextReaderPtr reader)
{
  if (!reader)
    return;
  int tokenId = getElementToken(reader);
  int tokenType = xmlTextReaderNodeType(reader);
  int emptyToken = xmlTextReaderIsEmptyElement(reader);
  if (XML_READER_TYPE_TEXT == tokenType)
  {
    librevenge::RVNGString text((const char *)xmlTextReaderConstValue(reader));
    ABW_DEBUG_MSG(("ABWParser::processXmlNode: text %s\n", text.cstr()));
    if (m_inParagraph && m_collector)
      m_collector->insertText(text);
  }
  switch (tokenId)
  {
  case XML_METADATA:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readMetadata(reader);
    break;
  case XML_HISTORY:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readHistory(reader);
    break;
  case XML_REVISIONS:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readRevisions(reader);
    break;
  case XML_IGNOREDWORDS:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readIgnoredWords(reader);
    break;
  case XML_S:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readS(reader);
    break;
  case XML_LISTS:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readLists(reader);
    break;
  case XML_PAGESIZE:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readPageSize(reader);
    break;
  case XML_SECTION:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readSection(reader);
    if (XML_READER_TYPE_END_ELEMENT == tokenType || emptyToken > 0)
      if (m_collector)
        m_collector->endSection();
    break;
  case XML_DATA:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readData(reader);
    break;
  case XML_P:
    if (XML_READER_TYPE_ELEMENT == tokenType)
    {
      readP(reader);
      m_inParagraph = true;
    }
    if (XML_READER_TYPE_END_ELEMENT == tokenType || emptyToken > 0)
    {
      m_inParagraph = false;
      if (m_collector)
        m_collector->closeParagraph();
    }
    break;
  case XML_C:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readC(reader);
    if (XML_READER_TYPE_END_ELEMENT == tokenType || emptyToken > 0)
      if (m_collector)
        m_collector->closeSpan();
    break;
  case XML_CBR:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      m_collector->insertColumnBreak();
    break;
  case XML_PBR:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      m_collector->insertPageBreak();
    break;
  case XML_BR:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      m_collector->insertLineBreak();
    break;
  case XML_A:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readA(reader);
    if (XML_READER_TYPE_END_ELEMENT == tokenType || emptyToken > 0)
      m_collector->closeLink();
    break;
  case XML_FOOT:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readFoot(reader);
    if (XML_READER_TYPE_END_ELEMENT == tokenType || emptyToken > 0)
      m_collector->closeFoot();
    break;
  case XML_ENDNOTE:
    if (XML_READER_TYPE_ELEMENT == tokenType)
      readEndnote(reader);
    if (XML_READER_TYPE_END_ELEMENT == tokenType || emptyToken > 0)
      m_collector->closeEndnote();
    break;
  default:
    break;
  }

#ifdef DEBUG
  const xmlChar *name = xmlTextReaderConstName(reader);
  const xmlChar *value = xmlTextReaderConstValue(reader);
  int isEmptyElement = xmlTextReaderIsEmptyElement(reader);

  ABW_DEBUG_MSG(("%i %i %s", isEmptyElement, tokenType, name ? (const char *)name : ""));
  if (xmlTextReaderNodeType(reader) == 1)
  {
    while (xmlTextReaderMoveToNextAttribute(reader))
    {
      const xmlChar *name1 = xmlTextReaderConstName(reader);
      const xmlChar *value1 = xmlTextReaderConstValue(reader);
      printf(" %s=\"%s\"", name1, value1);
    }
  }

  if (!value)
    ABW_DEBUG_MSG(("\n"));
  else
  {
    ABW_DEBUG_MSG((" %s\n", value));
  }
#endif
}

int libabw::ABWParser::getElementToken(xmlTextReaderPtr reader)
{
  return ABWXMLTokenMap::getTokenId(xmlTextReaderConstName(reader));
}

void libabw::ABWParser::readMetadata(xmlTextReaderPtr reader)
{
  int ret = 1;
  int tokenId = XML_TOKEN_INVALID;
  int tokenType = -1;
  do
  {
    ret = xmlTextReaderRead(reader);
    tokenId = getElementToken(reader);
    if (XML_TOKEN_INVALID == tokenId)
    {
      ABW_DEBUG_MSG(("ABWParser::readMetadata: unknown token %s\n", xmlTextReaderConstName(reader)));
    }
    tokenType = xmlTextReaderNodeType(reader);
    switch (tokenId)
    {
    default:
      break;
    }
  }
  while ((XML_METADATA != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
}

void libabw::ABWParser::readHistory(xmlTextReaderPtr reader)
{
  int ret = 1;
  int tokenId = XML_TOKEN_INVALID;
  int tokenType = -1;
  do
  {
    ret = xmlTextReaderRead(reader);
    tokenId = getElementToken(reader);
    if (XML_TOKEN_INVALID == tokenId)
    {
      ABW_DEBUG_MSG(("ABWParser::readHistory: unknown token %s\n", xmlTextReaderConstName(reader)));
    }
    tokenType = xmlTextReaderNodeType(reader);
    switch (tokenId)
    {
    default:
      break;
    }
  }
  while ((XML_HISTORY != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
}

void libabw::ABWParser::readRevisions(xmlTextReaderPtr reader)
{
  int ret = 1;
  int tokenId = XML_TOKEN_INVALID;
  int tokenType = -1;
  do
  {
    ret = xmlTextReaderRead(reader);
    tokenId = getElementToken(reader);
    if (XML_TOKEN_INVALID == tokenId)
    {
      ABW_DEBUG_MSG(("ABWParser::readRevisions: unknown token %s\n", xmlTextReaderConstName(reader)));
    }
    tokenType = xmlTextReaderNodeType(reader);
    (void)tokenType;
    switch (tokenId)
    {
    default:
      break;
    }
  }
  while ((XML_REVISIONS != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
}

void libabw::ABWParser::readIgnoredWords(xmlTextReaderPtr reader)
{
  int ret = 1;
  int tokenId = XML_TOKEN_INVALID;
  int tokenType = -1;
  do
  {
    ret = xmlTextReaderRead(reader);
    tokenId = getElementToken(reader);
    if (XML_TOKEN_INVALID == tokenId)
    {
      ABW_DEBUG_MSG(("ABWParser::readIgnoreWords: unknown token %s\n", xmlTextReaderConstName(reader)));
    }
    tokenType = xmlTextReaderNodeType(reader);
    switch (tokenId)
    {
    default:
      break;
    }
  }
  while ((XML_IGNOREDWORDS != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
}

void libabw::ABWParser::readLists(xmlTextReaderPtr reader)
{
  int ret = 1;
  int tokenId = XML_TOKEN_INVALID;
  int tokenType = -1;
  do
  {
    ret = xmlTextReaderRead(reader);
    tokenId = getElementToken(reader);
    if (XML_TOKEN_INVALID == tokenId)
    {
      ABW_DEBUG_MSG(("ABWParser::readLists: unknown token %s\n", xmlTextReaderConstName(reader)));
    }
    tokenType = xmlTextReaderNodeType(reader);
    switch (tokenId)
    {
    default:
      break;
    }
  }
  while ((XML_LISTS != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
}

void libabw::ABWParser::readPageSize(xmlTextReaderPtr reader)
{
  xmlChar *width = xmlTextReaderGetAttribute(reader, BAD_CAST("width"));
  xmlChar *height = xmlTextReaderGetAttribute(reader, BAD_CAST("height"));
  xmlChar *units = xmlTextReaderGetAttribute(reader, BAD_CAST("units"));
  xmlChar *pageScale = xmlTextReaderGetAttribute(reader, BAD_CAST("page-scale"));
  if (m_collector)
    m_collector->collectPageSize((const char *)width, (const char *)height, (const char *)units, (const char *)pageScale);
  if (width)
    xmlFree(width);
  if (height)
    xmlFree(height);
  if (units)
    xmlFree(units);
  if (pageScale)
    xmlFree(pageScale);
}

void libabw::ABWParser::readSection(xmlTextReaderPtr reader)
{
  xmlChar *props = xmlTextReaderGetAttribute(reader, BAD_CAST("props"));
  if (m_collector)
    m_collector->collectSectionProperties((const char *)props);
  if (props)
    xmlFree(props);
}

void libabw::ABWParser::readData(xmlTextReaderPtr reader)
{
  int ret = 1;
  int tokenId = XML_TOKEN_INVALID;
  int tokenType = -1;
  do
  {
    ret = xmlTextReaderRead(reader);
    tokenId = getElementToken(reader);
    if (XML_TOKEN_INVALID == tokenId)
    {
      ABW_DEBUG_MSG(("ABWParser::readData: unknown token %s\n", xmlTextReaderConstName(reader)));
    }
    tokenType = xmlTextReaderNodeType(reader);
    switch (tokenId)
    {
    default:
      break;
    }
  }
  while ((XML_DATA != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
}

void libabw::ABWParser::readS(xmlTextReaderPtr reader)
{
  xmlChar *type = xmlTextReaderGetAttribute(reader, BAD_CAST("type"));
  xmlChar *name = xmlTextReaderGetAttribute(reader, BAD_CAST("name"));
  xmlChar *basedon = xmlTextReaderGetAttribute(reader, BAD_CAST("basedon"));
  xmlChar *followedby = xmlTextReaderGetAttribute(reader, BAD_CAST("followedby"));
  xmlChar *props = xmlTextReaderGetAttribute(reader, BAD_CAST("props"));
  if (type)
  {
    if (m_collector)
    {
      switch (type[0])
      {
      case 'P':
      case 'C':
        m_collector->collectTextStyle((const char *)name, (const char *)basedon, (const char *)followedby, (const char *)props);
        break;
      default:
        break;
      }
    }
    xmlFree(type);
  }
  if (name)
    xmlFree(name);
  if (basedon)
    xmlFree(basedon);
  if (followedby)
    xmlFree(followedby);
  if (props)
    xmlFree(props);
}

void libabw::ABWParser::readA(xmlTextReaderPtr reader)
{
  xmlChar *href = xmlTextReaderGetAttribute(reader, BAD_CAST("xlink:href"));
  if (m_collector)
    m_collector->openLink((const char *)href);
  if (href)
    xmlFree(href);
}

void libabw::ABWParser::readP(xmlTextReaderPtr reader)
{
  xmlChar *style = xmlTextReaderGetAttribute(reader, BAD_CAST("style"));
  xmlChar *props = xmlTextReaderGetAttribute(reader, BAD_CAST("props"));
  if (m_collector)
    m_collector->collectParagraphProperties((const char *)style, (const char *)props);
  if (style)
    xmlFree(style);
  if (props)
    xmlFree(props);
}

void libabw::ABWParser::readC(xmlTextReaderPtr reader)
{
  xmlChar *style = xmlTextReaderGetAttribute(reader, BAD_CAST("style"));
  xmlChar *props = xmlTextReaderGetAttribute(reader, BAD_CAST("props"));
  if (m_collector)
    m_collector->collectCharacterProperties((const char *)style, (const char *)props);
  if (style)
    xmlFree(style);
  if (props)
    xmlFree(props);

}

void libabw::ABWParser::readEndnote(xmlTextReaderPtr reader)
{
  xmlChar *id = xmlTextReaderGetAttribute(reader, BAD_CAST("endnote-id"));
  if (m_collector)
    m_collector->openEndnote((const char *)id);
  if (id)
    xmlFree(id);
}

void libabw::ABWParser::readFoot(xmlTextReaderPtr reader)
{
  xmlChar *id = xmlTextReaderGetAttribute(reader, BAD_CAST("footnote-id"));
  if (m_collector)
    m_collector->openFoot((const char *)id);
  if (id)
    xmlFree(id);
}

/* vim:set shiftwidth=2 softtabstop=2 expandtab: */
<|endoftext|>


<commit_before>#include "Organizer.hpp"
#include "json.hpp"

Organizer::Organizer() {
    thread_running = false;
    queueThread = NULL;
}

Organizer::~Organizer() {
    delete queueThread;
}

void Organizer::setHostname(const string& hostname) {
    settings.hostname = hostname;
}

void Organizer::setId(const string& id) {
    settings.id = id;
}

void Organizer::addEvent(const string& data) {
    /* Start a worker thread here if its not already running */

    event_mtx.lock();
    em.addEvent(data);
    event_mtx.unlock();

    if (!thread_running) {
        // Start thread!
        thread_running = true;

        if (queueThread) {
            delete queueThread;
        }

        queueThread = new boost::thread(boost::bind(&Organizer::processEventQueue, this));
    }
}

void Organizer::processEventQueue() {
    /* Supposed to run from an independent thread.
     This method should recursively spawn a httpClient until EventManager is empty*/
    int failCounter = 0;

    do {
        cout << "sending " << boost::lexical_cast<string>(em.count()) << " events" << endl;
        if (failCounter > 30) {
            break;  // Stop attempting to send. Retry at a later point in time when there is new data to send. Keep old data buffered
        }

        event_mtx.lock();
        string json_out = em.getJson();
        em.clearEvents();
        event_mtx.unlock();

        #ifdef debug
            httpClient client = httpClient(settings.hostname, "/post.php", json_out);
        #else
            httpClient client = httpClient(settings.hostname, ("/api/missions/" + boost::lexical_cast<string>(settings.id) + "/events"), json_out);
        #endif

        if (client.status != httpClient::OK) {
            failCounter++;
        }

        /* Sleep thread to let events queue up */
        boost::this_thread::sleep(boost::posix_time::milliseconds(THREAD_SLEEP_DELAY));

    } while (!em.isEmpty());

    thread_running = false;
}

Organizer::status_t Organizer::getStatus(const string& mission, const string& ip) {
    status_t result;

    json missionJson;
    missionJson["mission"] = mission;
    missionJson["ip"] = ip;

    httpClient client = httpClient(settings.hostname, "/api/missions", missionJson.dump());
    if (client.status == httpClient::OK) {
        /* Read json response */
        json missionResponseJson = json::parse(client.getResult());

        result.id = missionResponseJson["_id"];
        result.status = Organizer::OK;
    } else if (client.status == httpClient::CONNECTION_FAILED) {
        result.status = Organizer::CONNECTION_FAILED;
    } else {
        result.status = Organizer::UNKNOWN;
    }

    return result;
}
<commit_msg>Change mission name to new parameter<commit_after>#include "Organizer.hpp"
#include "json.hpp"

Organizer::Organizer() {
    thread_running = false;
    queueThread = NULL;
}

Organizer::~Organizer() {
    delete queueThread;
}

void Organizer::setHostname(const string& hostname) {
    settings.hostname = hostname;
}

void Organizer::setId(const string& id) {
    settings.id = id;
}

void Organizer::addEvent(const string& data) {
    /* Start a worker thread here if its not already running */

    event_mtx.lock();
    em.addEvent(data);
    event_mtx.unlock();

    if (!thread_running) {
        // Start thread!
        thread_running = true;

        if (queueThread) {
            delete queueThread;
        }

        queueThread = new boost::thread(boost::bind(&Organizer::processEventQueue, this));
    }
}

void Organizer::processEventQueue() {
    /* Supposed to run from an independent thread.
     This method should recursively spawn a httpClient until EventManager is empty*/
    int failCounter = 0;

    do {
        cout << "sending " << boost::lexical_cast<string>(em.count()) << " events" << endl;
        if (failCounter > 30) {
            break;  // Stop attempting to send. Retry at a later point in time when there is new data to send. Keep old data buffered
        }

        event_mtx.lock();
        string json_out = em.getJson();
        em.clearEvents();
        event_mtx.unlock();

        #ifdef debug
            httpClient client = httpClient(settings.hostname, "/post.php", json_out);
        #else
            httpClient client = httpClient(settings.hostname, ("/api/missions/" + boost::lexical_cast<string>(settings.id) + "/events"), json_out);
        #endif

        if (client.status != httpClient::OK) {
            failCounter++;
        }

        /* Sleep thread to let events queue up */
        boost::this_thread::sleep(boost::posix_time::milliseconds(THREAD_SLEEP_DELAY));

    } while (!em.isEmpty());

    thread_running = false;
}

Organizer::status_t Organizer::getStatus(const string& mission, const string& world) {
    status_t result;

    json missionJson;
    missionJson["name"] = mission;
    missionJson["world"] = world;

    httpClient client = httpClient(settings.hostname, "/api/missions", missionJson.dump());
    if (client.status == httpClient::OK) {
        /* Read json response */
        json missionResponseJson = json::parse(client.getResult());

        result.id = missionResponseJson["_id"];
        result.status = Organizer::OK;
    } else if (client.status == httpClient::CONNECTION_FAILED) {
        result.status = Organizer::CONNECTION_FAILED;
    } else {
        result.status = Organizer::UNKNOWN;
    }

    return result;
}
<|endoftext|>


<commit_before>#include "Iop_Stdio.h"
#include <boost/lexical_cast.hpp>
#include "lexical_cast_ex.h"
#include "../Log.h"

#define LOG_NAME			"iop_stdio"

#define FUNCTION_PRINTF		"printf"

using namespace Iop;

CStdio::CStdio(uint8* ram)
: m_ram(ram)
{

}

CStdio::~CStdio()
{

}

std::string CStdio::GetId() const
{
	return "stdio";
}

std::string CStdio::GetFunctionName(unsigned int functionId) const
{
	switch(functionId)
	{
	case 4:
		return FUNCTION_PRINTF;
		break;
	default:
		return "unknown";
		break;
	}
}

void CStdio::Invoke(CMIPS& context, unsigned int functionId)
{
	switch(functionId)
	{
	case 4:
		__printf(context);
		break;
	default:
		CLog::GetInstance().Print(LOG_NAME, "Unknown function (%d) called. PC = (%0.8X).",
			functionId, context.m_State.nPC);
		break;
	}
}

std::string CStdio::PrintFormatted(CArgumentIterator& args)
{
	std::string output;
	const char* format = reinterpret_cast<const char*>(&m_ram[args.GetNext()]);
	while(*format != 0)
	{
		char character = *(format++);
		if(character == '%')
		{
			bool paramDone = false;
			bool inPrecision = false;
			char fillChar = ' ';
			std::string precision;
			while(!paramDone && *format != 0)
			{
				char type = *(format++);
				if(type == 's')
				{
					const char* text = reinterpret_cast<const char*>(&m_ram[args.GetNext()]);
					output += text;
					paramDone = true;
				}
				else if(type == 'c')
				{
					char character = static_cast<char>(args.GetNext());
					output += character;
					paramDone = true;
				}
				else if(type == 'd' || type == 'i')
				{
					int number = args.GetNext();
					unsigned int precisionValue = precision.length() ? boost::lexical_cast<unsigned int>(precision) : 1;
					output += lexical_cast_int<std::string>(number, precisionValue, fillChar);
					paramDone = true;
				}
				else if(type == 'u')
				{
					unsigned int number = args.GetNext();
					unsigned int precisionValue = precision.length() ? boost::lexical_cast<unsigned int>(precision) : 1;
					output += lexical_cast_uint<std::string>(number, precisionValue);
					paramDone = true;
				}
				else if(type == 'x' || type == 'X' || type == 'p')
				{
					uint32 number = args.GetNext();
					unsigned int precisionValue = precision.length() ? boost::lexical_cast<unsigned int>(precision) : 0;
					output += lexical_cast_hex<std::string>(number, precisionValue);
					paramDone = true;
				}
				else if(type == 'l')
				{
					//Length specifier, don't bother about it.
				}
				else if(type == '.')
				{
					inPrecision = true;
				}
				else
				{
					assert(isdigit(type));
					if(inPrecision)
					{
						precision += type;
					}
					else
					{
						fillChar = type;
						inPrecision = true;
					}
				}
			}
		}
		else
		{
			output += character;
		}
	}
	return output;
}

void CStdio::__printf(CMIPS& context)
{
	CArgumentIterator args(context);
	std::string output = PrintFormatted(args);
	printf("%s", output.c_str());
}
<commit_msg>deal with %% in printf format string<commit_after>#include "Iop_Stdio.h"
#include <boost/lexical_cast.hpp>
#include "lexical_cast_ex.h"
#include "../Log.h"

#define LOG_NAME			"iop_stdio"

#define FUNCTION_PRINTF		"printf"

using namespace Iop;

CStdio::CStdio(uint8* ram)
: m_ram(ram)
{

}

CStdio::~CStdio()
{

}

std::string CStdio::GetId() const
{
	return "stdio";
}

std::string CStdio::GetFunctionName(unsigned int functionId) const
{
	switch(functionId)
	{
	case 4:
		return FUNCTION_PRINTF;
		break;
	default:
		return "unknown";
		break;
	}
}

void CStdio::Invoke(CMIPS& context, unsigned int functionId)
{
	switch(functionId)
	{
	case 4:
		__printf(context);
		break;
	default:
		CLog::GetInstance().Print(LOG_NAME, "Unknown function (%d) called. PC = (%0.8X).",
			functionId, context.m_State.nPC);
		break;
	}
}

std::string CStdio::PrintFormatted(CArgumentIterator& args)
{
	std::string output;
	const char* format = reinterpret_cast<const char*>(&m_ram[args.GetNext()]);
	while(*format != 0)
	{
		char character = *(format++);
		if(character == '%')
		{
			bool paramDone = false;
			bool inPrecision = false;
			char fillChar = ' ';
			std::string precision;
			while(!paramDone && *format != 0)
			{
				char type = *(format++);
				if (type == '%'){
					output += type;
					paramDone = true;
				}
				else if(type == 's')
				{
					const char* text = reinterpret_cast<const char*>(&m_ram[args.GetNext()]);
					output += text;
					paramDone = true;
				}
				else if(type == 'c')
				{
					char character = static_cast<char>(args.GetNext());
					output += character;
					paramDone = true;
				}
				else if(type == 'd' || type == 'i')
				{
					int number = args.GetNext();
					unsigned int precisionValue = precision.length() ? boost::lexical_cast<unsigned int>(precision) : 1;
					output += lexical_cast_int<std::string>(number, precisionValue, fillChar);
					paramDone = true;
				}
				else if(type == 'u')
				{
					unsigned int number = args.GetNext();
					unsigned int precisionValue = precision.length() ? boost::lexical_cast<unsigned int>(precision) : 1;
					output += lexical_cast_uint<std::string>(number, precisionValue);
					paramDone = true;
				}
				else if(type == 'x' || type == 'X' || type == 'p')
				{
					uint32 number = args.GetNext();
					unsigned int precisionValue = precision.length() ? boost::lexical_cast<unsigned int>(precision) : 0;
					output += lexical_cast_hex<std::string>(number, precisionValue);
					paramDone = true;
				}
				else if(type == 'l')
				{
					//Length specifier, don't bother about it.
				}
				else if(type == '.')
				{
					inPrecision = true;
				}
				else
				{
					assert(isdigit(type));
					if(inPrecision)
					{
						precision += type;
					}
					else
					{
						fillChar = type;
						inPrecision = true;
					}
				}
			}
		}
		else
		{
			output += character;
		}
	}
	return output;
}

void CStdio::__printf(CMIPS& context)
{
	CArgumentIterator args(context);
	std::string output = PrintFormatted(args);
	printf("%s", output.c_str());
}
<|endoftext|>


<commit_before>#ifndef VAST_LOGGER_HPP
#define VAST_LOGGER_HPP

#include <sstream>
#include <type_traits>

#include "vast/config.hpp"
#include "vast/detail/pp.hpp"

#define CAF_LOG_COMPONENT "vast"
#include <caf/logger.hpp>
#include <caf/stateful_actor.hpp>

namespace vast {
namespace detail {

struct formatter {
  template <class T>
  auto operator<<(T const& x)
  -> std::enable_if_t<!std::is_pointer<T>::value, formatter&> {
    message << x;
    return *this;
  }

  template <class T, class... Ts>
  formatter& operator<<(caf::stateful_actor<T, Ts...>* a) {
    message << a->name() << '#' << a->id();
    return *this;
  }

  formatter& operator<<(caf::actor const& a) {
    message << "actor#" << a->id();
    return *this;
  }

  formatter& operator<<(caf::actor_addr const& a) {
    message << a.id();
    return *this;
  }

  // E.g., self->current_sender()
  formatter& operator<<(caf::strong_actor_ptr const& a) {
    if (a)
      message << a->id();
    else
      message << "invalid";
    return *this;
  }

  std::ostringstream message;
};

} // namespace detail
} // namespace vast

#if defined(CAF_LOG_LEVEL)
  #define VAST_LOG_IMPL(lvl, msg)                                              \
    do {                                                                       \
      vast::detail::formatter __vast_fmt;                                      \
      __vast_fmt << msg;                                                       \
      CAF_LOG_IMPL(lvl, __vast_fmt.message.str());                             \
    } while (false)

  #define VAST_LOG_2(lvl, m1) VAST_LOG_IMPL(lvl, m1)
  #define VAST_LOG_3(lvl, m1, m2) VAST_LOG_2(lvl, m1 << ' ' << m2)
  #define VAST_LOG_4(lvl, m1, m2, m3) VAST_LOG_3(lvl, m1, m2 << ' ' << m3)
  #define VAST_LOG_5(lvl, m1, m2, m3, m4)                                      \
    VAST_LOG_4(lvl, m1, m2, m3 << ' ' << m4)
  #define VAST_LOG_6(lvl, m1, m2, m3, m4, m5)                                  \
    VAST_LOG_5(lvl, m1, m2, m3, m4 << ' ' << m5)
  #define VAST_LOG_7(lvl, m1, m2, m3, m4, m5, m6)                              \
    VAST_LOG_6(lvl, m1, m2, m3, m4, m5 << ' ' << m6)
  #define VAST_LOG_8(lvl, m1, m2, m3, m4, m5, m6, m7)                          \
    VAST_LOG_7(lvl, m1, m2, m3, m4, m5, m6 << ' ' << m7)
  #define VAST_LOG_9(lvl, m1, m2, m3, m4, m5, m6, m7, m8)                      \
    VAST_LOG_8(lvl, m1, m2, m3, m4, m5, m6, m7 << ' ' << m8)
  #define VAST_LOG_10(lvl, m1, m2, m3, m4, m5, m6, m7, m8, m9)                 \
    VAST_LOG_9(lvl, m1, m2, m3, m4, m5, m6, m7, m8 << ' ' << m9)
  #define VAST_LOG(...)                                                        \
    VAST_PP_OVERLOAD(VAST_LOG_, __VA_ARGS__)(__VA_ARGS__)

  #if VAST_LOG_LEVEL >= CAF_LOG_LEVEL_ERROR
    #define VAST_ERROR(...) VAST_LOG(CAF_LOG_LEVEL_ERROR, __VA_ARGS__)
  #else
    #define VAST_ERROR(...) CAF_VOID_STMT
  #endif

  #if VAST_LOG_LEVEL >= CAF_LOG_LEVEL_WARNING
    #define VAST_WARNING(...) VAST_LOG(CAF_LOG_LEVEL_WARNING, __VA_ARGS__)
  #else
    #define VAST_WARNING(...) CAF_VOID_STMT
  #endif

  #if VAST_LOG_LEVEL >= CAF_LOG_LEVEL_INFO
    #define VAST_INFO(...) VAST_LOG(CAF_LOG_LEVEL_INFO, __VA_ARGS__)
  #else
    #define VAST_INFO(...) CAF_VOID_STMT
  #endif

  #if VAST_LOG_LEVEL >= CAF_LOG_LEVEL_DEBUG
    #define VAST_DEBUG(...) VAST_LOG(CAF_LOG_LEVEL_DEBUG, __VA_ARGS__)
  #else
    #define VAST_DEBUG(...) CAF_VOID_STMT
  #endif

  #if VAST_LOG_LEVEL >= CAF_LOG_LEVEL_TRACE
    #define VAST_TRACE(...) VAST_LOG(CAF_LOG_LEVEL_TRACE, __VA_ARGS__)
  #else
    #define VAST_TRACE(...) CAF_VOID_STMT
  #endif
#else
  #define VAST_ERROR(...) CAF_VOID_STMT
  #define VAST_WARNING(...) CAF_VOID_STMT
  #define VAST_INFO(...) CAF_VOID_STMT
  #define VAST_DEBUG(...) CAF_VOID_STMT
  #define VAST_TRACE(...) CAF_VOID_STMT
#endif

#endif
<commit_msg>Support string logging natively<commit_after>#ifndef VAST_LOGGER_HPP
#define VAST_LOGGER_HPP

#include <sstream>
#include <type_traits>

#include "vast/config.hpp"
#include "vast/detail/pp.hpp"

#define CAF_LOG_COMPONENT "vast"
#include <caf/logger.hpp>
#include <caf/stateful_actor.hpp>

namespace vast {
namespace detail {

struct formatter {
  template <class T>
  auto operator<<(T const& x)
  -> std::enable_if_t<
       !std::is_pointer<T>::value || std::is_convertible<T, std::string>::value,
       formatter&
     > {
    message << x;
    return *this;
  }

  template <class T, class... Ts>
  formatter& operator<<(caf::stateful_actor<T, Ts...>* a) {
    message << a->name() << '#' << a->id();
    return *this;
  }

  formatter& operator<<(caf::actor const& a) {
    message << "actor#" << a->id();
    return *this;
  }

  formatter& operator<<(caf::actor_addr const& a) {
    message << a.id();
    return *this;
  }

  // E.g., self->current_sender()
  formatter& operator<<(caf::strong_actor_ptr const& a) {
    if (a)
      message << a->id();
    else
      message << "invalid";
    return *this;
  }

  std::ostringstream message;
};

} // namespace detail
} // namespace vast

#if defined(CAF_LOG_LEVEL)
  #define VAST_LOG_IMPL(lvl, msg)                                              \
    do {                                                                       \
      vast::detail::formatter __vast_fmt;                                      \
      __vast_fmt << msg;                                                       \
      CAF_LOG_IMPL(lvl, __vast_fmt.message.str());                             \
    } while (false)

  #define VAST_LOG_2(lvl, m1) VAST_LOG_IMPL(lvl, m1)
  #define VAST_LOG_3(lvl, m1, m2) VAST_LOG_2(lvl, m1 << ' ' << m2)
  #define VAST_LOG_4(lvl, m1, m2, m3) VAST_LOG_3(lvl, m1, m2 << ' ' << m3)
  #define VAST_LOG_5(lvl, m1, m2, m3, m4)                                      \
    VAST_LOG_4(lvl, m1, m2, m3 << ' ' << m4)
  #define VAST_LOG_6(lvl, m1, m2, m3, m4, m5)                                  \
    VAST_LOG_5(lvl, m1, m2, m3, m4 << ' ' << m5)
  #define VAST_LOG_7(lvl, m1, m2, m3, m4, m5, m6)                              \
    VAST_LOG_6(lvl, m1, m2, m3, m4, m5 << ' ' << m6)
  #define VAST_LOG_8(lvl, m1, m2, m3, m4, m5, m6, m7)                          \
    VAST_LOG_7(lvl, m1, m2, m3, m4, m5, m6 << ' ' << m7)
  #define VAST_LOG_9(lvl, m1, m2, m3, m4, m5, m6, m7, m8)                      \
    VAST_LOG_8(lvl, m1, m2, m3, m4, m5, m6, m7 << ' ' << m8)
  #define VAST_LOG_10(lvl, m1, m2, m3, m4, m5, m6, m7, m8, m9)                 \
    VAST_LOG_9(lvl, m1, m2, m3, m4, m5, m6, m7, m8 << ' ' << m9)
  #define VAST_LOG(...)                                                        \
    VAST_PP_OVERLOAD(VAST_LOG_, __VA_ARGS__)(__VA_ARGS__)

  #if VAST_LOG_LEVEL >= CAF_LOG_LEVEL_ERROR
    #define VAST_ERROR(...) VAST_LOG(CAF_LOG_LEVEL_ERROR, __VA_ARGS__)
  #else
    #define VAST_ERROR(...) CAF_VOID_STMT
  #endif

  #if VAST_LOG_LEVEL >= CAF_LOG_LEVEL_WARNING
    #define VAST_WARNING(...) VAST_LOG(CAF_LOG_LEVEL_WARNING, __VA_ARGS__)
  #else
    #define VAST_WARNING(...) CAF_VOID_STMT
  #endif

  #if VAST_LOG_LEVEL >= CAF_LOG_LEVEL_INFO
    #define VAST_INFO(...) VAST_LOG(CAF_LOG_LEVEL_INFO, __VA_ARGS__)
  #else
    #define VAST_INFO(...) CAF_VOID_STMT
  #endif

  #if VAST_LOG_LEVEL >= CAF_LOG_LEVEL_DEBUG
    #define VAST_DEBUG(...) VAST_LOG(CAF_LOG_LEVEL_DEBUG, __VA_ARGS__)
  #else
    #define VAST_DEBUG(...) CAF_VOID_STMT
  #endif

  #if VAST_LOG_LEVEL >= CAF_LOG_LEVEL_TRACE
    #define VAST_TRACE(...) VAST_LOG(CAF_LOG_LEVEL_TRACE, __VA_ARGS__)
  #else
    #define VAST_TRACE(...) CAF_VOID_STMT
  #endif
#else
  #define VAST_ERROR(...) CAF_VOID_STMT
  #define VAST_WARNING(...) CAF_VOID_STMT
  #define VAST_INFO(...) CAF_VOID_STMT
  #define VAST_DEBUG(...) CAF_VOID_STMT
  #define VAST_TRACE(...) CAF_VOID_STMT
#endif

#endif
<|endoftext|>


<commit_before>// Copyright 2016 The RE2 Authors.  All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#include <fuzzer/FuzzedDataProvider.h>
#include <stddef.h>
#include <stdint.h>
#include <algorithm>
#include <string>
#include <vector>

#include "re2/re2.h"
#include "re2/regexp.h"
#include "re2/walker-inl.h"

using re2::StringPiece;

// NOT static, NOT signed.
uint8_t dummy = 0;

// Walks substrings (i.e. kRegexpLiteralString subexpressions)
// to determine their maximum length... in runes, but avoiding
// overheads due to UTF-8 encoding is worthwhile when fuzzing.
class SubstringWalker : public re2::Regexp::Walker<int> {
 public:
  SubstringWalker() = default;
  ~SubstringWalker() override = default;

  int PostVisit(re2::Regexp* re, int parent_arg, int pre_arg,
                int* child_args, int nchild_args) override {
    switch (re->op()) {
      case re2::kRegexpConcat:
      case re2::kRegexpAlternate:
      case re2::kRegexpStar:
      case re2::kRegexpPlus:
      case re2::kRegexpQuest:
      case re2::kRegexpRepeat:
      case re2::kRegexpCapture: {
        int max = -1;
        for (int i = 0; i < nchild_args; i++)
          max = std::max(max, child_args[i]);
        return max;
      }

      case re2::kRegexpLiteralString:
        return re->nrunes();

      default:
        break;
    }
    return -1;
  }

  // Should never be called: we use Walk(), not WalkExponential().
  int ShortVisit(re2::Regexp* re, int parent_arg) override {
    return parent_arg;
  }

 private:
  SubstringWalker(const SubstringWalker&) = delete;
  SubstringWalker& operator=(const SubstringWalker&) = delete;
};

void TestOneInput(StringPiece pattern, const RE2::Options& options,
                  StringPiece text) {
  // Crudely limit the use of ., \p, \P, \d, \D, \s, \S, \w and \W.
  // Otherwise, we will waste time on inputs that have long runs of various
  // character classes. The fuzzer has shown itself to be easily capable of
  // generating such patterns that fall within the other limits, but result
  // in timeouts nonetheless. The marginal cost is high - even more so when
  // counted repetition is involved - whereas the marginal benefit is zero.
  // TODO(junyer): Handle [:isalnum:] et al. when they start to cause pain.
  int char_class = 0;
  int backslash_p = 0;  // very expensive, so handle specially
  for (size_t i = 0; i < pattern.size(); i++) {
    if (pattern[i] == '.')
      char_class++;
    if (pattern[i] != '\\')
      continue;
    i++;
    if (i >= pattern.size())
      break;
    if (pattern[i] == 'p' || pattern[i] == 'P' ||
        pattern[i] == 'd' || pattern[i] == 'D' ||
        pattern[i] == 's' || pattern[i] == 'S' ||
        pattern[i] == 'w' || pattern[i] == 'W')
      char_class++;
    if (pattern[i] == 'p' || pattern[i] == 'P')
      backslash_p++;
  }
  if (char_class > 9)
    return;
  if (backslash_p > 1)
    return;

  // The default is 1000. Even 100 turned out to be too generous
  // for fuzzing, empirically speaking, so let's try 10 instead.
  re2::Regexp::FUZZING_ONLY_set_maximum_repeat_count(10);

  RE2 re(pattern, options);
  if (!re.ok())
    return;

  // Don't waste time fuzzing programs with large substrings.
  // They can cause bug reports due to fuzzer timeouts when they
  // are repetitions (e.g. hundreds of NUL bytes) and matching is
  // unanchored. And they aren't interesting for fuzzing purposes.
  SubstringWalker w;
  if (w.Walk(re.Regexp(), -1) > 9)
    return;

  // Don't waste time fuzzing high-size programs.
  // They can cause bug reports due to fuzzer timeouts.
  int size = re.ProgramSize();
  if (size > 9999)
    return;
  int rsize = re.ReverseProgramSize();
  if (rsize > 9999)
    return;

  // Don't waste time fuzzing high-fanout programs.
  // They can cause bug reports due to fuzzer timeouts.
  std::vector<int> histogram;
  int fanout = re.ProgramFanout(&histogram);
  if (fanout > 9)
    return;
  int rfanout = re.ReverseProgramFanout(&histogram);
  if (rfanout > 9)
    return;

  if (re.NumberOfCapturingGroups() == 0) {
    // Avoid early return due to too many arguments.
    StringPiece sp = text;
    RE2::FullMatch(sp, re);
    RE2::PartialMatch(sp, re);
    RE2::Consume(&sp, re);
    sp = text;  // Reset.
    RE2::FindAndConsume(&sp, re);
  } else {
    // Okay, we have at least one capturing group...
    // Try conversion for variously typed arguments.
    StringPiece sp = text;
    short s;
    RE2::FullMatch(sp, re, &s);
    long l;
    RE2::PartialMatch(sp, re, &l);
    float f;
    RE2::Consume(&sp, re, &f);
    sp = text;  // Reset.
    double d;
    RE2::FindAndConsume(&sp, re, &d);
  }

  std::string s = std::string(text);
  RE2::Replace(&s, re, "");
  s = std::string(text);  // Reset.
  RE2::GlobalReplace(&s, re, "");

  std::string min, max;
  re.PossibleMatchRange(&min, &max, /*maxlen=*/9);

  // Exercise some other API functionality.
  dummy += re.NamedCapturingGroups().size();
  dummy += re.CapturingGroupNames().size();
  dummy += RE2::QuoteMeta(pattern).size();
}

// Entry point for libFuzzer.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  // An input larger than 4 KiB probably isn't interesting. (This limit
  // allows for fdp.ConsumeRandomLengthString()'s backslash behaviour.)
  if (size == 0 || size > 4096)
    return 0;

  FuzzedDataProvider fdp(data, size);

  // The convention here is that fdp.ConsumeBool() returning false sets
  // the default value whereas returning true sets the alternate value:
  // most options default to false and so can be set directly; encoding
  // defaults to UTF-8; case_sensitive defaults to true. We do NOT want
  // to log errors. max_mem is 64 MiB because we can afford to use more
  // RAM in exchange for (hopefully) faster fuzzing.
  RE2::Options options;
  options.set_encoding(fdp.ConsumeBool() ? RE2::Options::EncodingLatin1
                                         : RE2::Options::EncodingUTF8);
  options.set_posix_syntax(fdp.ConsumeBool());
  options.set_longest_match(fdp.ConsumeBool());
  options.set_log_errors(false);
  options.set_max_mem(64 << 20);
  options.set_literal(fdp.ConsumeBool());
  options.set_never_nl(fdp.ConsumeBool());
  options.set_dot_nl(fdp.ConsumeBool());
  options.set_never_capture(fdp.ConsumeBool());
  options.set_case_sensitive(!fdp.ConsumeBool());
  options.set_perl_classes(fdp.ConsumeBool());
  options.set_word_boundary(fdp.ConsumeBool());
  options.set_one_line(fdp.ConsumeBool());

  std::string pattern = fdp.ConsumeRandomLengthString(999);
  std::string text = fdp.ConsumeRandomLengthString(999);

  TestOneInput(pattern, options, text);
  return 0;
}
<commit_msg>Crudely limit the use of 'k', 'K', 's' and 'S' when fuzzing.<commit_after>// Copyright 2016 The RE2 Authors.  All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#include <fuzzer/FuzzedDataProvider.h>
#include <stddef.h>
#include <stdint.h>
#include <algorithm>
#include <string>
#include <vector>

#include "re2/re2.h"
#include "re2/regexp.h"
#include "re2/walker-inl.h"

using re2::StringPiece;

// NOT static, NOT signed.
uint8_t dummy = 0;

// Walks substrings (i.e. kRegexpLiteralString subexpressions)
// to determine their maximum length... in runes, but avoiding
// overheads due to UTF-8 encoding is worthwhile when fuzzing.
class SubstringWalker : public re2::Regexp::Walker<int> {
 public:
  SubstringWalker() = default;
  ~SubstringWalker() override = default;

  int PostVisit(re2::Regexp* re, int parent_arg, int pre_arg,
                int* child_args, int nchild_args) override {
    switch (re->op()) {
      case re2::kRegexpConcat:
      case re2::kRegexpAlternate:
      case re2::kRegexpStar:
      case re2::kRegexpPlus:
      case re2::kRegexpQuest:
      case re2::kRegexpRepeat:
      case re2::kRegexpCapture: {
        int max = -1;
        for (int i = 0; i < nchild_args; i++)
          max = std::max(max, child_args[i]);
        return max;
      }

      case re2::kRegexpLiteralString:
        return re->nrunes();

      default:
        break;
    }
    return -1;
  }

  // Should never be called: we use Walk(), not WalkExponential().
  int ShortVisit(re2::Regexp* re, int parent_arg) override {
    return parent_arg;
  }

 private:
  SubstringWalker(const SubstringWalker&) = delete;
  SubstringWalker& operator=(const SubstringWalker&) = delete;
};

void TestOneInput(StringPiece pattern, const RE2::Options& options,
                  StringPiece text) {
  // Crudely limit the use of ., \p, \P, \d, \D, \s, \S, \w and \W.
  // Otherwise, we will waste time on inputs that have long runs of various
  // character classes. The fuzzer has shown itself to be easily capable of
  // generating such patterns that fall within the other limits, but result
  // in timeouts nonetheless. The marginal cost is high - even more so when
  // counted repetition is involved - whereas the marginal benefit is zero.
  // Crudely limit the use of 'k', 'K', 's' and 'S' too because they become
  // three-element character classes when case-insensitive and using UTF-8.
  // TODO(junyer): Handle [:isalnum:] et al. when they start to cause pain.
  int char_class = 0;
  int backslash_p = 0;  // very expensive, so handle specially
  for (size_t i = 0; i < pattern.size(); i++) {
    if (pattern[i] == '.' ||
        pattern[i] == 'k' || pattern[i] == 'K' ||
        pattern[i] == 's' || pattern[i] == 'S')
      char_class++;
    if (pattern[i] != '\\')
      continue;
    i++;
    if (i >= pattern.size())
      break;
    if (pattern[i] == 'p' || pattern[i] == 'P' ||
        pattern[i] == 'd' || pattern[i] == 'D' ||
        pattern[i] == 's' || pattern[i] == 'S' ||
        pattern[i] == 'w' || pattern[i] == 'W')
      char_class++;
    if (pattern[i] == 'p' || pattern[i] == 'P')
      backslash_p++;
  }
  if (char_class > 9)
    return;
  if (backslash_p > 1)
    return;

  // The default is 1000. Even 100 turned out to be too generous
  // for fuzzing, empirically speaking, so let's try 10 instead.
  re2::Regexp::FUZZING_ONLY_set_maximum_repeat_count(10);

  RE2 re(pattern, options);
  if (!re.ok())
    return;

  // Don't waste time fuzzing programs with large substrings.
  // They can cause bug reports due to fuzzer timeouts when they
  // are repetitions (e.g. hundreds of NUL bytes) and matching is
  // unanchored. And they aren't interesting for fuzzing purposes.
  SubstringWalker w;
  if (w.Walk(re.Regexp(), -1) > 9)
    return;

  // Don't waste time fuzzing high-size programs.
  // They can cause bug reports due to fuzzer timeouts.
  int size = re.ProgramSize();
  if (size > 9999)
    return;
  int rsize = re.ReverseProgramSize();
  if (rsize > 9999)
    return;

  // Don't waste time fuzzing high-fanout programs.
  // They can cause bug reports due to fuzzer timeouts.
  std::vector<int> histogram;
  int fanout = re.ProgramFanout(&histogram);
  if (fanout > 9)
    return;
  int rfanout = re.ReverseProgramFanout(&histogram);
  if (rfanout > 9)
    return;

  if (re.NumberOfCapturingGroups() == 0) {
    // Avoid early return due to too many arguments.
    StringPiece sp = text;
    RE2::FullMatch(sp, re);
    RE2::PartialMatch(sp, re);
    RE2::Consume(&sp, re);
    sp = text;  // Reset.
    RE2::FindAndConsume(&sp, re);
  } else {
    // Okay, we have at least one capturing group...
    // Try conversion for variously typed arguments.
    StringPiece sp = text;
    short s;
    RE2::FullMatch(sp, re, &s);
    long l;
    RE2::PartialMatch(sp, re, &l);
    float f;
    RE2::Consume(&sp, re, &f);
    sp = text;  // Reset.
    double d;
    RE2::FindAndConsume(&sp, re, &d);
  }

  std::string s = std::string(text);
  RE2::Replace(&s, re, "");
  s = std::string(text);  // Reset.
  RE2::GlobalReplace(&s, re, "");

  std::string min, max;
  re.PossibleMatchRange(&min, &max, /*maxlen=*/9);

  // Exercise some other API functionality.
  dummy += re.NamedCapturingGroups().size();
  dummy += re.CapturingGroupNames().size();
  dummy += RE2::QuoteMeta(pattern).size();
}

// Entry point for libFuzzer.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  // An input larger than 4 KiB probably isn't interesting. (This limit
  // allows for fdp.ConsumeRandomLengthString()'s backslash behaviour.)
  if (size == 0 || size > 4096)
    return 0;

  FuzzedDataProvider fdp(data, size);

  // The convention here is that fdp.ConsumeBool() returning false sets
  // the default value whereas returning true sets the alternate value:
  // most options default to false and so can be set directly; encoding
  // defaults to UTF-8; case_sensitive defaults to true. We do NOT want
  // to log errors. max_mem is 64 MiB because we can afford to use more
  // RAM in exchange for (hopefully) faster fuzzing.
  RE2::Options options;
  options.set_encoding(fdp.ConsumeBool() ? RE2::Options::EncodingLatin1
                                         : RE2::Options::EncodingUTF8);
  options.set_posix_syntax(fdp.ConsumeBool());
  options.set_longest_match(fdp.ConsumeBool());
  options.set_log_errors(false);
  options.set_max_mem(64 << 20);
  options.set_literal(fdp.ConsumeBool());
  options.set_never_nl(fdp.ConsumeBool());
  options.set_dot_nl(fdp.ConsumeBool());
  options.set_never_capture(fdp.ConsumeBool());
  options.set_case_sensitive(!fdp.ConsumeBool());
  options.set_perl_classes(fdp.ConsumeBool());
  options.set_word_boundary(fdp.ConsumeBool());
  options.set_one_line(fdp.ConsumeBool());

  std::string pattern = fdp.ConsumeRandomLengthString(999);
  std::string text = fdp.ConsumeRandomLengthString(999);

  TestOneInput(pattern, options, text);
  return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/wm/partial_screenshot_view.h"

#include "ash/screenshot_delegate.h"
#include "ash/shell.h"
#include "ash/shell_window_ids.h"
#include "ash/wm/partial_screenshot_event_filter.h"
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
#include "ui/base/events.h"
#include "ui/base/cursor/cursor.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/rect.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"

namespace ash {

PartialScreenshotView::PartialScreenshotView(
    ScreenshotDelegate* screenshot_delegate)
    : is_dragging_(false),
      screenshot_delegate_(screenshot_delegate),
      window_(NULL) {
}

PartialScreenshotView::~PartialScreenshotView() {
  screenshot_delegate_ = NULL;
  // Do not delete the |window_| here because |window_| has the
  // ownership to this object. In case that finishing browser happens
  // while |window_| != NULL, |window_| is still removed correctly by
  // its parent container.
  window_ = NULL;
}

// static
void PartialScreenshotView::StartPartialScreenshot(
    ScreenshotDelegate* screenshot_delegate) {
  views::Widget* widget = new views::Widget;
  PartialScreenshotView* view = new PartialScreenshotView(
      screenshot_delegate);
  aura::RootWindow* root_window = Shell::GetActiveRootWindow();
  views::Widget::InitParams params(
      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
  params.transparent = true;
  params.delegate = view;
  // The partial screenshot rectangle has to be at the real top of
  // the screen.
  params.parent = Shell::GetContainer(
      root_window,
      internal::kShellWindowId_OverlayContainer);

  widget->Init(params);
  widget->SetContentsView(view);
  widget->SetBounds(root_window->bounds());
  widget->GetNativeView()->SetName("PartialScreenshotView");
  widget->StackAtTop();
  widget->Show();
  // Captures mouse events in case that context menu already captures the
  // events.  This will close the context menu.
  widget->GetNativeView()->SetCapture();

  view->set_window(widget->GetNativeWindow());
  Shell::GetInstance()->partial_screenshot_filter()->Activate(view);
}

void PartialScreenshotView::Cancel() {
  DCHECK(window_);
  window_->Hide();
  Shell::GetInstance()->partial_screenshot_filter()->Deactivate();
  MessageLoop::current()->DeleteSoon(FROM_HERE, window_);
}

gfx::NativeCursor PartialScreenshotView::GetCursor(
    const views::MouseEvent& event) {
  // Always use "crosshair" cursor.
  return ui::kCursorCross;
}

void PartialScreenshotView::OnPaint(gfx::Canvas* canvas) {
  if (is_dragging_) {
    // Screenshot area representation: black rectangle with white
    // rectangle inside.
    gfx::Rect screenshot_rect = GetScreenshotRect();
    canvas->DrawRect(screenshot_rect, SK_ColorBLACK);
    screenshot_rect.Inset(1, 1, 1, 1);
    canvas->DrawRect(screenshot_rect, SK_ColorWHITE);
  }
}

void PartialScreenshotView::OnMouseCaptureLost() {
  Cancel();
}

bool PartialScreenshotView::OnMousePressed(const views::MouseEvent& event) {
  start_position_ = event.location();
  return true;
}

bool PartialScreenshotView::OnMouseDragged(const views::MouseEvent& event) {
  current_position_ = event.location();
  SchedulePaint();
  is_dragging_ = true;
  return true;
}

bool PartialScreenshotView::OnMouseWheel(const views::MouseWheelEvent& event) {
  // Do nothing but do not propagate events futhermore.
  return true;
}

void PartialScreenshotView::OnMouseReleased(const views::MouseEvent& event) {
  Cancel();
  if (!is_dragging_)
    return;

  is_dragging_ = false;
  if (screenshot_delegate_) {
    aura::RootWindow *root_window = Shell::GetPrimaryRootWindow();
    screenshot_delegate_->HandleTakePartialScreenshot(
        root_window, root_window->bounds().Intersect(GetScreenshotRect()));
  }
}

gfx::Rect PartialScreenshotView::GetScreenshotRect() const {
  int left = std::min(start_position_.x(), current_position_.x());
  int top = std::min(start_position_.y(), current_position_.y());
  int width = ::abs(start_position_.x() - current_position_.x());
  int height = ::abs(start_position_.y() - current_position_.y());
  return gfx::Rect(left, top, width, height);
}

}  // namespace ash
<commit_msg>Do not capture the partial screenshot region selector boundary.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/wm/partial_screenshot_view.h"

#include "ash/screenshot_delegate.h"
#include "ash/shell.h"
#include "ash/shell_window_ids.h"
#include "ash/wm/partial_screenshot_event_filter.h"
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
#include "ui/base/events.h"
#include "ui/base/cursor/cursor.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/rect.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"

namespace ash {

PartialScreenshotView::PartialScreenshotView(
    ScreenshotDelegate* screenshot_delegate)
    : is_dragging_(false),
      screenshot_delegate_(screenshot_delegate),
      window_(NULL) {
}

PartialScreenshotView::~PartialScreenshotView() {
  screenshot_delegate_ = NULL;
  // Do not delete the |window_| here because |window_| has the
  // ownership to this object. In case that finishing browser happens
  // while |window_| != NULL, |window_| is still removed correctly by
  // its parent container.
  window_ = NULL;
}

// static
void PartialScreenshotView::StartPartialScreenshot(
    ScreenshotDelegate* screenshot_delegate) {
  views::Widget* widget = new views::Widget;
  PartialScreenshotView* view = new PartialScreenshotView(
      screenshot_delegate);
  aura::RootWindow* root_window = Shell::GetActiveRootWindow();
  views::Widget::InitParams params(
      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
  params.transparent = true;
  params.delegate = view;
  // The partial screenshot rectangle has to be at the real top of
  // the screen.
  params.parent = Shell::GetContainer(
      root_window,
      internal::kShellWindowId_OverlayContainer);

  widget->Init(params);
  widget->SetContentsView(view);
  widget->SetBounds(root_window->bounds());
  widget->GetNativeView()->SetName("PartialScreenshotView");
  widget->StackAtTop();
  widget->Show();
  // Captures mouse events in case that context menu already captures the
  // events.  This will close the context menu.
  widget->GetNativeView()->SetCapture();

  view->set_window(widget->GetNativeWindow());
  Shell::GetInstance()->partial_screenshot_filter()->Activate(view);
}

void PartialScreenshotView::Cancel() {
  DCHECK(window_);
  window_->Hide();
  Shell::GetInstance()->partial_screenshot_filter()->Deactivate();
  MessageLoop::current()->DeleteSoon(FROM_HERE, window_);
}

gfx::NativeCursor PartialScreenshotView::GetCursor(
    const views::MouseEvent& event) {
  // Always use "crosshair" cursor.
  return ui::kCursorCross;
}

void PartialScreenshotView::OnPaint(gfx::Canvas* canvas) {
  if (is_dragging_) {
    // Screenshot area representation: black rectangle with white
    // rectangle inside.  To avoid capturing these rectangles when mouse
    // release, they should be outside of the actual capturing area.
    gfx::Rect screenshot_rect = GetScreenshotRect();
    screenshot_rect.Inset(-1, -1, -1, -1);
    canvas->DrawRect(screenshot_rect, SK_ColorWHITE);
    screenshot_rect.Inset(-1, -1, -1, -1);
    canvas->DrawRect(screenshot_rect, SK_ColorBLACK);
  }
}

void PartialScreenshotView::OnMouseCaptureLost() {
  Cancel();
}

bool PartialScreenshotView::OnMousePressed(const views::MouseEvent& event) {
  start_position_ = event.location();
  return true;
}

bool PartialScreenshotView::OnMouseDragged(const views::MouseEvent& event) {
  current_position_ = event.location();
  SchedulePaint();
  is_dragging_ = true;
  return true;
}

bool PartialScreenshotView::OnMouseWheel(const views::MouseWheelEvent& event) {
  // Do nothing but do not propagate events futhermore.
  return true;
}

void PartialScreenshotView::OnMouseReleased(const views::MouseEvent& event) {
  Cancel();
  if (!is_dragging_)
    return;

  is_dragging_ = false;
  if (screenshot_delegate_) {
    aura::RootWindow *root_window = Shell::GetPrimaryRootWindow();
    screenshot_delegate_->HandleTakePartialScreenshot(
        root_window, root_window->bounds().Intersect(GetScreenshotRect()));
  }
}

gfx::Rect PartialScreenshotView::GetScreenshotRect() const {
  int left = std::min(start_position_.x(), current_position_.x());
  int top = std::min(start_position_.y(), current_position_.y());
  int width = ::abs(start_position_.x() - current_position_.x());
  int height = ::abs(start_position_.y() - current_position_.y());
  return gfx::Rect(left, top, width, height);
}

}  // namespace ash
<|endoftext|>


<commit_before>/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <memory>
#include <oboe/Definitions.h>
#include "FFMpegExtractor.h"
#include "utils/logging.h"

constexpr int kInternalBufferSize = 1152; // Use MP3 block size. https://wiki.hydrogenaud.io/index.php?title=MP3

int read(void *opaque, uint8_t *buf, int buf_size) {

    auto asset = (AAsset *) opaque;
    int bytesRead = AAsset_read(asset, buf, (size_t)buf_size);
    return bytesRead;
}

int64_t seek(void *opaque, int64_t offset, int whence){

    auto asset = (AAsset*)opaque;

    // See https://www.ffmpeg.org/doxygen/3.0/avio_8h.html#a427ff2a881637b47ee7d7f9e368be63f
    if (whence == AVSEEK_SIZE) return AAsset_getLength(asset);
    if (AAsset_seek(asset, offset, whence) == -1){
        return -1;
    } else {
        return 0;
    }
}

bool FFMpegExtractor::createAVIOContext(AAsset *asset, uint8_t *buffer, uint32_t bufferSize,
                                        AVIOContext **avioContext) {

    constexpr int isBufferWriteable = 0;

    *avioContext = avio_alloc_context(
            buffer, // internal buffer for FFmpeg to use
            bufferSize, // For optimal decoding speed this should be the protocol block size
            isBufferWriteable,
            asset, // Will be passed to our callback functions as a (void *)
            read, // Read callback function
            nullptr, // Write callback function (not used)
            seek); // Seek callback function

    if (*avioContext == nullptr){
        LOGE("Failed to create AVIO context");
        return false;
    } else {
        return true;
    }
}

bool
FFMpegExtractor::createAVFormatContext(AVIOContext *avioContext, AVFormatContext **avFormatContext) {

    *avFormatContext = avformat_alloc_context();
    (*avFormatContext)->pb = avioContext;

    if (*avFormatContext == nullptr){
        LOGE("Failed to create AVFormatContext");
        return false;
    } else {
        return true;
    }
}

bool FFMpegExtractor::openAVFormatContext(AVFormatContext *avFormatContext) {

    int result = avformat_open_input(&avFormatContext,
                                     "", /* URL is left empty because we're providing our own I/O */
                                     nullptr /* AVInputFormat *fmt */,
                                     nullptr /* AVDictionary **options */
    );

    if (result == 0) {
        return true;
    } else {
        LOGE("Failed to open file. Error code %s", av_err2str(result));
        return false;
    }
}

bool FFMpegExtractor::getStreamInfo(AVFormatContext *avFormatContext) {

    int result = avformat_find_stream_info(avFormatContext, nullptr);
    if (result == 0 ){
        return true;
    } else {
        LOGE("Failed to find stream info. Error code %s", av_err2str(result));
        return false;
    }
}

AVStream *FFMpegExtractor::getBestAudioStream(AVFormatContext *avFormatContext) {

    int streamIndex = av_find_best_stream(avFormatContext, AVMEDIA_TYPE_AUDIO, -1, -1, nullptr, 0);

    if (streamIndex < 0){
        LOGE("Could not find stream");
        return nullptr;
    } else {
        return avFormatContext->streams[streamIndex];
    }
}

int64_t FFMpegExtractor::decode(
        AAsset *asset,
        uint8_t *targetData,
        AudioProperties targetProperties) {

    int returnValue = -1; // -1 indicates error

    // Create a buffer for FFmpeg to use for decoding (freed in the custom deleter below)
    auto buffer = reinterpret_cast<uint8_t*>(av_malloc(kInternalBufferSize));

    // Create an AVIOContext with a custom deleter
    std::unique_ptr<AVIOContext, void(*)(AVIOContext *)> ioContext {
            nullptr,
            [](AVIOContext *c) {
                av_free(c->buffer);
                avio_context_free(&c);
            }
    };
    {
        AVIOContext *tmp = nullptr;
        if (!createAVIOContext(asset, buffer, kInternalBufferSize, &tmp)){
            LOGE("Could not create an AVIOContext");
            return returnValue;
        }
        ioContext.reset(tmp);
    }

    // Create an AVFormatContext using the avformat_free_context as the deleter function
    std::unique_ptr<AVFormatContext, decltype(&avformat_free_context)> formatContext {
            nullptr,
            &avformat_free_context
    };
    {
        AVFormatContext *tmp;
        if (!createAVFormatContext(ioContext.get(), &tmp)) return returnValue;
        formatContext.reset(tmp);
    }

    if (!openAVFormatContext(formatContext.get())) return returnValue;

    if (!getStreamInfo(formatContext.get())) return returnValue;

    // Obtain the best audio stream to decode
    AVStream *stream = getBestAudioStream(formatContext.get());
    if (stream == nullptr || stream->codecpar == nullptr){
        LOGE("Could not find a suitable audio stream to decode");
        return returnValue;
    }

    printCodecParameters(stream->codecpar);

    // Find the codec to decode this stream
    AVCodec *codec = avcodec_find_decoder(stream->codecpar->codec_id);
    if (!codec){
        LOGE("Could not find codec with ID: %d", stream->codecpar->codec_id);
        return returnValue;
    }

    // Create the codec context, specifying the deleter function
    std::unique_ptr<AVCodecContext, void(*)(AVCodecContext *)> codecContext {
            nullptr,
            [](AVCodecContext *c) { avcodec_free_context(&c); }
    };
    {
        AVCodecContext *tmp = avcodec_alloc_context3(codec);
        if (!tmp){
            LOGE("Failed to allocate codec context");
            return returnValue;
        }
        codecContext.reset(tmp);
    }

    // Copy the codec parameters into the context
    if (avcodec_parameters_to_context(codecContext.get(), stream->codecpar) < 0){
        LOGE("Failed to copy codec parameters to codec context");
        return returnValue;
    }

    // Open the codec
    if (avcodec_open2(codecContext.get(), codec, nullptr) < 0){
        LOGE("Could not open codec");
        return returnValue;
    }

    // prepare resampler
    int32_t outChannelLayout = (1 << targetProperties.channelCount) - 1;
    LOGD("Channel layout %d", outChannelLayout);

    SwrContext *swr = swr_alloc();
    av_opt_set_int(swr, "in_channel_count", stream->codecpar->channels, 0);
    av_opt_set_int(swr, "out_channel_count", targetProperties.channelCount, 0);
    av_opt_set_int(swr, "in_channel_layout", stream->codecpar->channel_layout, 0);
    av_opt_set_int(swr, "out_channel_layout", outChannelLayout, 0);
    av_opt_set_int(swr, "in_sample_rate", stream->codecpar->sample_rate, 0);
    av_opt_set_int(swr, "out_sample_rate", targetProperties.sampleRate, 0);
    av_opt_set_int(swr, "in_sample_fmt", stream->codecpar->format, 0);
    av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_FLT, 0);
    av_opt_set_int(swr, "force_resampling", 1, 0);

    // Check that resampler has been inited
    int result = swr_init(swr);
    if (result != 0){
        LOGE("swr_init failed. Error: %s", av_err2str(result));
        return returnValue;
    };
    if (!swr_is_initialized(swr)) {
        LOGE("swr_is_initialized is false\n");
        return returnValue;
    }

    // Prepare to read data
    int bytesWritten = 0;
    AVPacket avPacket; // Stores compressed audio data
    av_init_packet(&avPacket);
    AVFrame *decodedFrame = av_frame_alloc(); // Stores raw audio data
    int bytesPerSample = av_get_bytes_per_sample((AVSampleFormat)stream->codecpar->format);

    LOGD("Bytes per sample %d", bytesPerSample);

    LOGD("DECODE START");

    // While there is more data to read, read it into the avPacket
    while (av_read_frame(formatContext.get(), &avPacket) == 0){

        if (avPacket.stream_index == stream->index && avPacket.size > 0) {

            // Pass our compressed data into the codec
            result = avcodec_send_packet(codecContext.get(), &avPacket);
            if (result != 0) {
                LOGE("avcodec_send_packet error: %s", av_err2str(result));
                goto cleanup;
            }

            // Retrieve our raw data from the codec
            result = avcodec_receive_frame(codecContext.get(), decodedFrame);
            if (result == AVERROR(EAGAIN)) {
                // The codec needs more data before it can decode
                LOGI("avcodec_receive_frame returned EAGAIN");
                avPacket.size = 0;
                avPacket.data = nullptr;
                continue;
            } else if (result != 0) {
                LOGE("avcodec_receive_frame error: %s", av_err2str(result));
                goto cleanup;
            }

            // DO RESAMPLING
            auto dst_nb_samples = (int32_t) av_rescale_rnd(
                    swr_get_delay(swr, decodedFrame->sample_rate) + decodedFrame->nb_samples,
                    targetProperties.sampleRate,
                    decodedFrame->sample_rate,
                    AV_ROUND_UP);

            short *buffer1;
            av_samples_alloc(
                    (uint8_t **) &buffer1,
                    nullptr,
                    targetProperties.channelCount,
                    dst_nb_samples,
                    AV_SAMPLE_FMT_FLT,
                    0);
            int frame_count = swr_convert(
                    swr,
                    (uint8_t **) &buffer1,
                    dst_nb_samples,
                    (const uint8_t **) decodedFrame->data,
                    decodedFrame->nb_samples);

            int64_t bytesToWrite = frame_count * sizeof(float) * targetProperties.channelCount;
            memcpy(targetData + bytesWritten, buffer1, (size_t)bytesToWrite);
            bytesWritten += bytesToWrite;
            av_freep(&buffer1);

            avPacket.size = 0;
            avPacket.data = nullptr;
        }
    }

    av_frame_free(&decodedFrame);
    LOGD("DECODE END");

    returnValue = bytesWritten;

    cleanup:
    return returnValue;
}

void FFMpegExtractor::printCodecParameters(AVCodecParameters *params) {

    LOGD("Stream properties");
    LOGD("Channels: %d", params->channels);
    LOGD("Channel layout: %" PRId64, params->channel_layout);
    LOGD("Sample rate: %d", params->sample_rate);
    LOGD("Format: %s", av_get_sample_fmt_name((AVSampleFormat)params->format));
    LOGD("Frame size: %d", params->frame_size);
}

<commit_msg>RhythmGame FFMpegExtractor, for clearing packet use av_packet_unref<commit_after>/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <memory>
#include <oboe/Definitions.h>
#include "FFMpegExtractor.h"
#include "utils/logging.h"

constexpr int kInternalBufferSize = 1152; // Use MP3 block size. https://wiki.hydrogenaud.io/index.php?title=MP3

int read(void *opaque, uint8_t *buf, int buf_size) {

    auto asset = (AAsset *) opaque;
    int bytesRead = AAsset_read(asset, buf, (size_t)buf_size);
    return bytesRead;
}

int64_t seek(void *opaque, int64_t offset, int whence){

    auto asset = (AAsset*)opaque;

    // See https://www.ffmpeg.org/doxygen/3.0/avio_8h.html#a427ff2a881637b47ee7d7f9e368be63f
    if (whence == AVSEEK_SIZE) return AAsset_getLength(asset);
    if (AAsset_seek(asset, offset, whence) == -1){
        return -1;
    } else {
        return 0;
    }
}

bool FFMpegExtractor::createAVIOContext(AAsset *asset, uint8_t *buffer, uint32_t bufferSize,
                                        AVIOContext **avioContext) {

    constexpr int isBufferWriteable = 0;

    *avioContext = avio_alloc_context(
            buffer, // internal buffer for FFmpeg to use
            bufferSize, // For optimal decoding speed this should be the protocol block size
            isBufferWriteable,
            asset, // Will be passed to our callback functions as a (void *)
            read, // Read callback function
            nullptr, // Write callback function (not used)
            seek); // Seek callback function

    if (*avioContext == nullptr){
        LOGE("Failed to create AVIO context");
        return false;
    } else {
        return true;
    }
}

bool
FFMpegExtractor::createAVFormatContext(AVIOContext *avioContext, AVFormatContext **avFormatContext) {

    *avFormatContext = avformat_alloc_context();
    (*avFormatContext)->pb = avioContext;

    if (*avFormatContext == nullptr){
        LOGE("Failed to create AVFormatContext");
        return false;
    } else {
        return true;
    }
}

bool FFMpegExtractor::openAVFormatContext(AVFormatContext *avFormatContext) {

    int result = avformat_open_input(&avFormatContext,
                                     "", /* URL is left empty because we're providing our own I/O */
                                     nullptr /* AVInputFormat *fmt */,
                                     nullptr /* AVDictionary **options */
    );

    if (result == 0) {
        return true;
    } else {
        LOGE("Failed to open file. Error code %s", av_err2str(result));
        return false;
    }
}

bool FFMpegExtractor::getStreamInfo(AVFormatContext *avFormatContext) {

    int result = avformat_find_stream_info(avFormatContext, nullptr);
    if (result == 0 ){
        return true;
    } else {
        LOGE("Failed to find stream info. Error code %s", av_err2str(result));
        return false;
    }
}

AVStream *FFMpegExtractor::getBestAudioStream(AVFormatContext *avFormatContext) {

    int streamIndex = av_find_best_stream(avFormatContext, AVMEDIA_TYPE_AUDIO, -1, -1, nullptr, 0);

    if (streamIndex < 0){
        LOGE("Could not find stream");
        return nullptr;
    } else {
        return avFormatContext->streams[streamIndex];
    }
}

int64_t FFMpegExtractor::decode(
        AAsset *asset,
        uint8_t *targetData,
        AudioProperties targetProperties) {

    int returnValue = -1; // -1 indicates error

    // Create a buffer for FFmpeg to use for decoding (freed in the custom deleter below)
    auto buffer = reinterpret_cast<uint8_t*>(av_malloc(kInternalBufferSize));

    // Create an AVIOContext with a custom deleter
    std::unique_ptr<AVIOContext, void(*)(AVIOContext *)> ioContext {
            nullptr,
            [](AVIOContext *c) {
                av_free(c->buffer);
                avio_context_free(&c);
            }
    };
    {
        AVIOContext *tmp = nullptr;
        if (!createAVIOContext(asset, buffer, kInternalBufferSize, &tmp)){
            LOGE("Could not create an AVIOContext");
            return returnValue;
        }
        ioContext.reset(tmp);
    }

    // Create an AVFormatContext using the avformat_free_context as the deleter function
    std::unique_ptr<AVFormatContext, decltype(&avformat_free_context)> formatContext {
            nullptr,
            &avformat_free_context
    };
    {
        AVFormatContext *tmp;
        if (!createAVFormatContext(ioContext.get(), &tmp)) return returnValue;
        formatContext.reset(tmp);
    }

    if (!openAVFormatContext(formatContext.get())) return returnValue;

    if (!getStreamInfo(formatContext.get())) return returnValue;

    // Obtain the best audio stream to decode
    AVStream *stream = getBestAudioStream(formatContext.get());
    if (stream == nullptr || stream->codecpar == nullptr){
        LOGE("Could not find a suitable audio stream to decode");
        return returnValue;
    }

    printCodecParameters(stream->codecpar);

    // Find the codec to decode this stream
    AVCodec *codec = avcodec_find_decoder(stream->codecpar->codec_id);
    if (!codec){
        LOGE("Could not find codec with ID: %d", stream->codecpar->codec_id);
        return returnValue;
    }

    // Create the codec context, specifying the deleter function
    std::unique_ptr<AVCodecContext, void(*)(AVCodecContext *)> codecContext {
            nullptr,
            [](AVCodecContext *c) { avcodec_free_context(&c); }
    };
    {
        AVCodecContext *tmp = avcodec_alloc_context3(codec);
        if (!tmp){
            LOGE("Failed to allocate codec context");
            return returnValue;
        }
        codecContext.reset(tmp);
    }

    // Copy the codec parameters into the context
    if (avcodec_parameters_to_context(codecContext.get(), stream->codecpar) < 0){
        LOGE("Failed to copy codec parameters to codec context");
        return returnValue;
    }

    // Open the codec
    if (avcodec_open2(codecContext.get(), codec, nullptr) < 0){
        LOGE("Could not open codec");
        return returnValue;
    }

    // prepare resampler
    int32_t outChannelLayout = (1 << targetProperties.channelCount) - 1;
    LOGD("Channel layout %d", outChannelLayout);

    SwrContext *swr = swr_alloc();
    av_opt_set_int(swr, "in_channel_count", stream->codecpar->channels, 0);
    av_opt_set_int(swr, "out_channel_count", targetProperties.channelCount, 0);
    av_opt_set_int(swr, "in_channel_layout", stream->codecpar->channel_layout, 0);
    av_opt_set_int(swr, "out_channel_layout", outChannelLayout, 0);
    av_opt_set_int(swr, "in_sample_rate", stream->codecpar->sample_rate, 0);
    av_opt_set_int(swr, "out_sample_rate", targetProperties.sampleRate, 0);
    av_opt_set_int(swr, "in_sample_fmt", stream->codecpar->format, 0);
    av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_FLT, 0);
    av_opt_set_int(swr, "force_resampling", 1, 0);

    // Check that resampler has been inited
    int result = swr_init(swr);
    if (result != 0){
        LOGE("swr_init failed. Error: %s", av_err2str(result));
        return returnValue;
    };
    if (!swr_is_initialized(swr)) {
        LOGE("swr_is_initialized is false\n");
        return returnValue;
    }

    // Prepare to read data
    int bytesWritten = 0;
    AVPacket avPacket; // Stores compressed audio data
    av_init_packet(&avPacket);
    AVFrame *decodedFrame = av_frame_alloc(); // Stores raw audio data
    int bytesPerSample = av_get_bytes_per_sample((AVSampleFormat)stream->codecpar->format);

    LOGD("Bytes per sample %d", bytesPerSample);

    LOGD("DECODE START");

    // While there is more data to read, read it into the avPacket
    while (av_read_frame(formatContext.get(), &avPacket) == 0){

        if (avPacket.stream_index == stream->index && avPacket.size > 0) {

            // Pass our compressed data into the codec
            result = avcodec_send_packet(codecContext.get(), &avPacket);
            if (result != 0) {
                LOGE("avcodec_send_packet error: %s", av_err2str(result));
                goto cleanup;
            }

            // Retrieve our raw data from the codec
            result = avcodec_receive_frame(codecContext.get(), decodedFrame);
            if (result == AVERROR(EAGAIN)) {
                // The codec needs more data before it can decode
                LOGI("avcodec_receive_frame returned EAGAIN");
                av_packet_unref(&avPacket);
                continue;
            } else if (result != 0) {
                LOGE("avcodec_receive_frame error: %s", av_err2str(result));
                goto cleanup;
            }

            // DO RESAMPLING
            auto dst_nb_samples = (int32_t) av_rescale_rnd(
                    swr_get_delay(swr, decodedFrame->sample_rate) + decodedFrame->nb_samples,
                    targetProperties.sampleRate,
                    decodedFrame->sample_rate,
                    AV_ROUND_UP);

            short *buffer1;
            av_samples_alloc(
                    (uint8_t **) &buffer1,
                    nullptr,
                    targetProperties.channelCount,
                    dst_nb_samples,
                    AV_SAMPLE_FMT_FLT,
                    0);
            int frame_count = swr_convert(
                    swr,
                    (uint8_t **) &buffer1,
                    dst_nb_samples,
                    (const uint8_t **) decodedFrame->data,
                    decodedFrame->nb_samples);

            int64_t bytesToWrite = frame_count * sizeof(float) * targetProperties.channelCount;
            memcpy(targetData + bytesWritten, buffer1, (size_t)bytesToWrite);
            bytesWritten += bytesToWrite;
            av_freep(&buffer1);

            av_packet_unref(&avPacket);
        }
    }

    av_frame_free(&decodedFrame);
    LOGD("DECODE END");

    returnValue = bytesWritten;

    cleanup:
    return returnValue;
}

void FFMpegExtractor::printCodecParameters(AVCodecParameters *params) {

    LOGD("Stream properties");
    LOGD("Channels: %d", params->channels);
    LOGD("Channel layout: %" PRId64, params->channel_layout);
    LOGD("Sample rate: %d", params->sample_rate);
    LOGD("Format: %s", av_get_sample_fmt_name((AVSampleFormat)params->format));
    LOGD("Frame size: %d", params->frame_size);
}

<|endoftext|>


<commit_before>#ifndef ITER_CHUNKED_HPP_
#define ITER_CHUNKED_HPP_

#include "internal/iterbase.hpp"
#include "internal/iteratoriterator.hpp"

#include <vector>
#include <algorithm>
#include <type_traits>
#include <functional>
#include <utility>
#include <iterator>
#include <initializer_list>

namespace iter {
  namespace impl {
    template <typename Container>
    class Chunker;
  }

  template <typename Container>
  impl::Chunker<Container> chunked(Container&&, std::size_t);

  template <typename T>
  impl::Chunker<std::initializer_list<T>> chunked(
      std::initializer_list<T>, std::size_t);
}

template <typename Container>
class iter::impl::Chunker {
 private:
  Container container;
  std::size_t chunk_size;

  Chunker(Container&& c, std::size_t sz)
      : container(std::forward<Container>(c)), chunk_size{sz} {}

  friend Chunker iter::chunked<Container>(Container&&, std::size_t);
  template <typename T>
  friend Chunker<std::initializer_list<T>> iter::chunked(
      std::initializer_list<T>, std::size_t);

  using IndexVector = std::vector<iterator_type<Container>>;
  using DerefVec = IterIterWrapper<IndexVector>;

 public:
  Chunker(Chunker&&) = default;
  class Iterator : public std::iterator<std::input_iterator_tag, DerefVec> {
   private:
    iterator_type<Container> sub_iter;
    iterator_type<Container> sub_end;
    DerefVec chunk;
    std::size_t chunk_size = 0;

    bool done() const {
      return this->chunk.empty();
    }

    void refill_chunk() {
      this->chunk.get().clear();
      std::size_t i{0};
      while (i < chunk_size && this->sub_iter != this->sub_end) {
        chunk.get().push_back(this->sub_iter);
        ++this->sub_iter;
        ++i;
      }
    }

   public:
    Iterator(iterator_type<Container>&& in_iter,
        iterator_type<Container>&& in_end, std::size_t s)
        : sub_iter{std::move(in_iter)},
          sub_end{std::move(in_end)},
          chunk_size{s} {
      this->chunk.get().reserve(this->chunk_size);
      this->refill_chunk();
    }

    Iterator& operator++() {
      this->refill_chunk();
      return *this;
    }

    Iterator operator++(int) {
      auto ret = *this;
      ++*this;
      return ret;
    }

    bool operator!=(const Iterator& other) const {
      return !(*this == other);
    }

    bool operator==(const Iterator& other) const {
      return this->done() == other.done()
             && (this->done() || !(this->sub_iter != other.sub_iter));
    }

    DerefVec& operator*() {
      return this->chunk;
    }

    DerefVec* operator->() {
      return &this->chunk;
    }
  };

  Iterator begin() {
    return {std::begin(this->container), std::end(this->container), chunk_size};
  }

  Iterator end() {
    return {std::end(this->container), std::end(this->container), chunk_size};
  }
};

template <typename Container>
iter::impl::Chunker<Container> iter::chunked(
    Container&& container, std::size_t chunk_size) {
  return {std::forward<Container>(container), chunk_size};
}

template <typename T>
iter::impl::Chunker<std::initializer_list<T>> iter::chunked(
    std::initializer_list<T> il, std::size_t chunk_size) {
  return {std::move(il), chunk_size};
}

#endif
<commit_msg>drops init list support from chunked<commit_after>#ifndef ITER_CHUNKED_HPP_
#define ITER_CHUNKED_HPP_

#include "internal/iterbase.hpp"
#include "internal/iteratoriterator.hpp"

#include <vector>
#include <algorithm>
#include <type_traits>
#include <functional>
#include <utility>
#include <iterator>

namespace iter {
  namespace impl {
    template <typename Container>
    class Chunker;
  }

  template <typename Container>
  impl::Chunker<Container> chunked(Container&&, std::size_t);

}

template <typename Container>
class iter::impl::Chunker {
 private:
  Container container;
  std::size_t chunk_size;

  Chunker(Container&& c, std::size_t sz)
      : container(std::forward<Container>(c)), chunk_size{sz} {}

  friend Chunker iter::chunked<Container>(Container&&, std::size_t);

  using IndexVector = std::vector<iterator_type<Container>>;
  using DerefVec = IterIterWrapper<IndexVector>;

 public:
  Chunker(Chunker&&) = default;
  class Iterator : public std::iterator<std::input_iterator_tag, DerefVec> {
   private:
    iterator_type<Container> sub_iter;
    iterator_type<Container> sub_end;
    DerefVec chunk;
    std::size_t chunk_size = 0;

    bool done() const {
      return this->chunk.empty();
    }

    void refill_chunk() {
      this->chunk.get().clear();
      std::size_t i{0};
      while (i < chunk_size && this->sub_iter != this->sub_end) {
        chunk.get().push_back(this->sub_iter);
        ++this->sub_iter;
        ++i;
      }
    }

   public:
    Iterator(iterator_type<Container>&& in_iter,
        iterator_type<Container>&& in_end, std::size_t s)
        : sub_iter{std::move(in_iter)},
          sub_end{std::move(in_end)},
          chunk_size{s} {
      this->chunk.get().reserve(this->chunk_size);
      this->refill_chunk();
    }

    Iterator& operator++() {
      this->refill_chunk();
      return *this;
    }

    Iterator operator++(int) {
      auto ret = *this;
      ++*this;
      return ret;
    }

    bool operator!=(const Iterator& other) const {
      return !(*this == other);
    }

    bool operator==(const Iterator& other) const {
      return this->done() == other.done()
             && (this->done() || !(this->sub_iter != other.sub_iter));
    }

    DerefVec& operator*() {
      return this->chunk;
    }

    DerefVec* operator->() {
      return &this->chunk;
    }
  };

  Iterator begin() {
    return {std::begin(this->container), std::end(this->container), chunk_size};
  }

  Iterator end() {
    return {std::end(this->container), std::end(this->container), chunk_size};
  }
};

template <typename Container>
iter::impl::Chunker<Container> iter::chunked(
    Container&& container, std::size_t chunk_size) {
  return {std::forward<Container>(container), chunk_size};
}

#endif
<|endoftext|>