<commit_before>// Copyright (c) 2011-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include "bitcoin-config.h"
#endif

#include "optionsdialog.h"
#include "ui_optionsdialog.h"

#include "bitcoinunits.h"
#include "guiutil.h"
#include "monitoreddatamapper.h"
#include "optionsmodel.h"

#include "main.h" // for CTransaction::nMinTxFee
#include "netbase.h"
#include "txdb.h" // for -dbcache defaults

#include <QDir>
#include <QIntValidator>
#include <QLocale>
#include <QMessageBox>
#include <QTimer>

OptionsDialog::OptionsDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::OptionsDialog),
    model(0),
    mapper(0),
    fProxyIpValid(true)
{
    ui->setupUi(this);
    GUIUtil::restoreWindowGeometry("nOptionsDialogWindow", this->size(), this);

    /* Main elements init */
    ui->databaseCache->setMinimum(nMinDbCache);
    ui->databaseCache->setMaximum(nMaxDbCache);

    /* Network elements init */
#ifndef USE_UPNP
    ui->mapPortUpnp->setEnabled(false);
#endif

    ui->proxyIp->setEnabled(false);
    ui->proxyPort->setEnabled(false);
    ui->proxyPort->setValidator(new QIntValidator(1, 65535, this));

    /** SOCKS version is only selectable for default proxy and is always 5 for IPv6 and Tor */
    ui->socksVersion->setEnabled(false);
    ui->socksVersion->addItem("5", 5);
    ui->socksVersion->addItem("4", 4);
    ui->socksVersion->setCurrentIndex(0);

    connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyIp, SLOT(setEnabled(bool)));
    connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyPort, SLOT(setEnabled(bool)));
    connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->socksVersion, SLOT(setEnabled(bool)));

    ui->proxyIp->installEventFilter(this);

    /* Window elements init */
#ifdef Q_OS_MAC
    /* remove Window tab on Mac */
    ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->tabWindow));
#endif

    /* Display elements init */
    QDir translations(":translations");
    ui->lang->addItem(QString("(") + tr("default") + QString(")"), QVariant(""));
    foreach(const QString &langStr, translations.entryList())
    {
        QLocale locale(langStr);

        /** check if the locale name consists of 2 parts (language_country) */
        if(langStr.contains("_"))
        {
#if QT_VERSION >= 0x040800
            /** display language strings as "native language - native country (locale name)", e.g. "Deutsch - Deutschland (de)" */
            ui->lang->addItem(locale.nativeLanguageName() + QString(" - ") + locale.nativeCountryName() + QString(" (") + langStr + QString(")"), QVariant(langStr));
#else
            /** display language strings as "language - country (locale name)", e.g. "German - Germany (de)" */
            ui->lang->addItem(QLocale::languageToString(locale.language()) + QString(" - ") + QLocale::countryToString(locale.country()) + QString(" (") + langStr + QString(")"), QVariant(langStr));
#endif
        }
        else
        {
#if QT_VERSION >= 0x040800
            /** display language strings as "native language (locale name)", e.g. "Deutsch (de)" */
            ui->lang->addItem(locale.nativeLanguageName() + QString(" (") + langStr + QString(")"), QVariant(langStr));
#else
            /** display language strings as "language (locale name)", e.g. "German (de)" */
            ui->lang->addItem(QLocale::languageToString(locale.language()) + QString(" (") + langStr + QString(")"), QVariant(langStr));
#endif
        }
    }

    ui->unit->setModel(new BitcoinUnits(this));
    ui->transactionFee->setSingleStep(CTransaction::nMinTxFee);

    /* Widget-to-option mapper */
    mapper = new MonitoredDataMapper(this);
    mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
    mapper->setOrientation(Qt::Vertical);

    /* setup/change UI elements when proxy IP is invalid/valid */
    connect(this, SIGNAL(proxyIpChecks(QValidatedLineEdit *, int)), this, SLOT(doProxyIpChecks(QValidatedLineEdit *, int)));
}

OptionsDialog::~OptionsDialog()
{
    GUIUtil::saveWindowGeometry("nOptionsDialogWindow", this);
    delete ui;
}

void OptionsDialog::setModel(OptionsModel *model)
{
    this->model = model;

    if(model)
    {
        /* check if client restart is needed and show persistent message */
        if (model->isRestartRequired())
            showRestartWarning(true);

        QString strLabel = model->getOverriddenByCommandLine();
        if (strLabel.isEmpty())
            strLabel = tr("none");
        ui->overriddenByCommandLineLabel->setText(strLabel);

        connect(model, SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));

        mapper->setModel(model);
        setMapper();
        mapper->toFirst();
    }

    /* update the display unit, to not use the default ("DOGE") */
    updateDisplayUnit();

    /* warn when one of the following settings changes by user action (placed here so init via mapper doesn't trigger them) */

    /* Main */
    connect(ui->databaseCache, SIGNAL(valueChanged(int)), this, SLOT(showRestartWarning()));
    connect(ui->threadsScriptVerif, SIGNAL(valueChanged(int)), this, SLOT(showRestartWarning()));
    /* Network */
    connect(ui->connectSocks, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning()));
    /* Display */
    connect(ui->lang, SIGNAL(valueChanged()), this, SLOT(showRestartWarning()));
}

void OptionsDialog::setMapper()
{
    /* Main */
    mapper->addMapping(ui->bitcoinAtStartup, OptionsModel::StartAtStartup);
    mapper->addMapping(ui->threadsScriptVerif, OptionsModel::ThreadsScriptVerif);
    mapper->addMapping(ui->databaseCache, OptionsModel::DatabaseCache);

    /* Wallet */
    mapper->addMapping(ui->transactionFee, OptionsModel::Fee);
    mapper->addMapping(ui->spendZeroConfChange, OptionsModel::SpendZeroConfChange);

    /* Network */
    mapper->addMapping(ui->mapPortUpnp, OptionsModel::MapPortUPnP);

    mapper->addMapping(ui->connectSocks, OptionsModel::ProxyUse);
    mapper->addMapping(ui->proxyIp, OptionsModel::ProxyIP);
    mapper->addMapping(ui->proxyPort, OptionsModel::ProxyPort);
    mapper->addMapping(ui->socksVersion, OptionsModel::ProxySocksVersion);

    /* Window */
#ifndef Q_OS_MAC
    mapper->addMapping(ui->minimizeToTray, OptionsModel::MinimizeToTray);
    mapper->addMapping(ui->minimizeOnClose, OptionsModel::MinimizeOnClose);
#endif

    /* Display */
    mapper->addMapping(ui->lang, OptionsModel::Language);
    mapper->addMapping(ui->unit, OptionsModel::DisplayUnit);
    mapper->addMapping(ui->displayAddresses, OptionsModel::DisplayAddresses);
    mapper->addMapping(ui->coinControlFeatures, OptionsModel::CoinControlFeatures);
}

void OptionsDialog::enableOkButton()
{
    /* prevent enabling of the OK button when data modified, if there is an invalid proxy address present */
    if(fProxyIpValid)
        setOkButtonState(true);
}

void OptionsDialog::disableOkButton()
{
    setOkButtonState(false);
}

void OptionsDialog::setOkButtonState(bool fState)
{
    ui->okButton->setEnabled(fState);
}

void OptionsDialog::on_resetButton_clicked()
{
    if(model)
    {
        // confirmation dialog
        QMessageBox::StandardButton btnRetVal = QMessageBox::question(this, tr("Confirm options reset"),
            tr("Client restart required to activate changes.") + "

" + tr("Client will be shutdown, do you want to proceed?"),
            QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);

        if(btnRetVal == QMessageBox::Cancel)
            return;

        /* reset all options and close GUI */
        model->Reset();
        QApplication::quit();
    }
}

void OptionsDialog::on_okButton_clicked()
{
    mapper->submit();
    accept();
}

void OptionsDialog::on_cancelButton_clicked()
{
    reject();
}

void OptionsDialog::showRestartWarning(bool fPersistent)
{
    ui->statusLabel->setStyleSheet("QLabel { color: red; }");

    if(fPersistent)
    {
        ui->statusLabel->setText(tr("Client restart required to activate changes."));
    }
    else
    {
        ui->statusLabel->setText(tr("This change would require a client restart."));
        // clear non-persistent status label after 10 seconds
        // Todo: should perhaps be a class attribute, if we extend the use of statusLabel
        QTimer::singleShot(10000, this, SLOT(clearStatusLabel()));
    }
}

void OptionsDialog::clearStatusLabel()
{
    ui->statusLabel->clear();
}

void OptionsDialog::updateDisplayUnit()
{
    if(model)
    {
        /* Update transactionFee with the current unit */
        ui->transactionFee->setDisplayUnit(model->getDisplayUnit());
    }
}

void OptionsDialog::doProxyIpChecks(QValidatedLineEdit *pUiProxyIp, int nProxyPort)
{
    Q_UNUSED(nProxyPort);

    const std::string strAddrProxy = pUiProxyIp->text().toStdString();
    CService addrProxy;

    /* Check for a valid IPv4 / IPv6 address */
    if (!(fProxyIpValid = LookupNumeric(strAddrProxy.c_str(), addrProxy)))
    {
        disableOkButton();
        pUiProxyIp->setValid(false);
        ui->statusLabel->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel->setText(tr("The supplied proxy address is invalid."));
    }
    else
    {
        enableOkButton();
        ui->statusLabel->clear();
    }
}

bool OptionsDialog::eventFilter(QObject *object, QEvent *event)
{
    if(event->type() == QEvent::FocusOut)
    {
        if(object == ui->proxyIp)
        {
            emit proxyIpChecks(ui->proxyIp, ui->proxyPort->text().toInt());
        }
    }
    return QDialog::eventFilter(object, event);
}
<commit_msg>Notify user about a required restart, when he changes the ZeroConf option.<commit_after>// Copyright (c) 2011-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include "bitcoin-config.h"
#endif

#include "optionsdialog.h"
#include "ui_optionsdialog.h"

#include "bitcoinunits.h"
#include "guiutil.h"
#include "monitoreddatamapper.h"
#include "optionsmodel.h"

#include "main.h" // for CTransaction::nMinTxFee
#include "netbase.h"
#include "txdb.h" // for -dbcache defaults

#include <QDir>
#include <QIntValidator>
#include <QLocale>
#include <QMessageBox>
#include <QTimer>

OptionsDialog::OptionsDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::OptionsDialog),
    model(0),
    mapper(0),
    fProxyIpValid(true)
{
    ui->setupUi(this);
    GUIUtil::restoreWindowGeometry("nOptionsDialogWindow", this->size(), this);

    /* Main elements init */
    ui->databaseCache->setMinimum(nMinDbCache);
    ui->databaseCache->setMaximum(nMaxDbCache);

    /* Network elements init */
#ifndef USE_UPNP
    ui->mapPortUpnp->setEnabled(false);
#endif

    ui->proxyIp->setEnabled(false);
    ui->proxyPort->setEnabled(false);
    ui->proxyPort->setValidator(new QIntValidator(1, 65535, this));

    /** SOCKS version is only selectable for default proxy and is always 5 for IPv6 and Tor */
    ui->socksVersion->setEnabled(false);
    ui->socksVersion->addItem("5", 5);
    ui->socksVersion->addItem("4", 4);
    ui->socksVersion->setCurrentIndex(0);

    connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyIp, SLOT(setEnabled(bool)));
    connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyPort, SLOT(setEnabled(bool)));
    connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->socksVersion, SLOT(setEnabled(bool)));

    ui->proxyIp->installEventFilter(this);

    /* Window elements init */
#ifdef Q_OS_MAC
    /* remove Window tab on Mac */
    ui->tabWidget->removeTab(ui->tabWidget->indexOf(ui->tabWindow));
#endif

    /* Display elements init */
    QDir translations(":translations");
    ui->lang->addItem(QString("(") + tr("default") + QString(")"), QVariant(""));
    foreach(const QString &langStr, translations.entryList())
    {
        QLocale locale(langStr);

        /** check if the locale name consists of 2 parts (language_country) */
        if(langStr.contains("_"))
        {
#if QT_VERSION >= 0x040800
            /** display language strings as "native language - native country (locale name)", e.g. "Deutsch - Deutschland (de)" */
            ui->lang->addItem(locale.nativeLanguageName() + QString(" - ") + locale.nativeCountryName() + QString(" (") + langStr + QString(")"), QVariant(langStr));
#else
            /** display language strings as "language - country (locale name)", e.g. "German - Germany (de)" */
            ui->lang->addItem(QLocale::languageToString(locale.language()) + QString(" - ") + QLocale::countryToString(locale.country()) + QString(" (") + langStr + QString(")"), QVariant(langStr));
#endif
        }
        else
        {
#if QT_VERSION >= 0x040800
            /** display language strings as "native language (locale name)", e.g. "Deutsch (de)" */
            ui->lang->addItem(locale.nativeLanguageName() + QString(" (") + langStr + QString(")"), QVariant(langStr));
#else
            /** display language strings as "language (locale name)", e.g. "German (de)" */
            ui->lang->addItem(QLocale::languageToString(locale.language()) + QString(" (") + langStr + QString(")"), QVariant(langStr));
#endif
        }
    }

    ui->unit->setModel(new BitcoinUnits(this));
    ui->transactionFee->setSingleStep(CTransaction::nMinTxFee);

    /* Widget-to-option mapper */
    mapper = new MonitoredDataMapper(this);
    mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
    mapper->setOrientation(Qt::Vertical);

    /* setup/change UI elements when proxy IP is invalid/valid */
    connect(this, SIGNAL(proxyIpChecks(QValidatedLineEdit *, int)), this, SLOT(doProxyIpChecks(QValidatedLineEdit *, int)));
}

OptionsDialog::~OptionsDialog()
{
    GUIUtil::saveWindowGeometry("nOptionsDialogWindow", this);
    delete ui;
}

void OptionsDialog::setModel(OptionsModel *model)
{
    this->model = model;

    if(model)
    {
        /* check if client restart is needed and show persistent message */
        if (model->isRestartRequired())
            showRestartWarning(true);

        QString strLabel = model->getOverriddenByCommandLine();
        if (strLabel.isEmpty())
            strLabel = tr("none");
        ui->overriddenByCommandLineLabel->setText(strLabel);

        connect(model, SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));

        mapper->setModel(model);
        setMapper();
        mapper->toFirst();
    }

    /* update the display unit, to not use the default ("DOGE") */
    updateDisplayUnit();

    /* warn when one of the following settings changes by user action (placed here so init via mapper doesn't trigger them) */

    /* Main */
    connect(ui->databaseCache, SIGNAL(valueChanged(int)), this, SLOT(showRestartWarning()));
    connect(ui->threadsScriptVerif, SIGNAL(valueChanged(int)), this, SLOT(showRestartWarning()));
    /* Wallet */
    connect(ui->spendZeroConfChange, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning()));
    /* Network */
    connect(ui->connectSocks, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning()));
    /* Display */
    connect(ui->lang, SIGNAL(valueChanged()), this, SLOT(showRestartWarning()));
}

void OptionsDialog::setMapper()
{
    /* Main */
    mapper->addMapping(ui->bitcoinAtStartup, OptionsModel::StartAtStartup);
    mapper->addMapping(ui->threadsScriptVerif, OptionsModel::ThreadsScriptVerif);
    mapper->addMapping(ui->databaseCache, OptionsModel::DatabaseCache);

    /* Wallet */
    mapper->addMapping(ui->transactionFee, OptionsModel::Fee);
    mapper->addMapping(ui->spendZeroConfChange, OptionsModel::SpendZeroConfChange);

    /* Network */
    mapper->addMapping(ui->mapPortUpnp, OptionsModel::MapPortUPnP);

    mapper->addMapping(ui->connectSocks, OptionsModel::ProxyUse);
    mapper->addMapping(ui->proxyIp, OptionsModel::ProxyIP);
    mapper->addMapping(ui->proxyPort, OptionsModel::ProxyPort);
    mapper->addMapping(ui->socksVersion, OptionsModel::ProxySocksVersion);

    /* Window */
#ifndef Q_OS_MAC
    mapper->addMapping(ui->minimizeToTray, OptionsModel::MinimizeToTray);
    mapper->addMapping(ui->minimizeOnClose, OptionsModel::MinimizeOnClose);
#endif

    /* Display */
    mapper->addMapping(ui->lang, OptionsModel::Language);
    mapper->addMapping(ui->unit, OptionsModel::DisplayUnit);
    mapper->addMapping(ui->displayAddresses, OptionsModel::DisplayAddresses);
    mapper->addMapping(ui->coinControlFeatures, OptionsModel::CoinControlFeatures);
}

void OptionsDialog::enableOkButton()
{
    /* prevent enabling of the OK button when data modified, if there is an invalid proxy address present */
    if(fProxyIpValid)
        setOkButtonState(true);
}

void OptionsDialog::disableOkButton()
{
    setOkButtonState(false);
}

void OptionsDialog::setOkButtonState(bool fState)
{
    ui->okButton->setEnabled(fState);
}

void OptionsDialog::on_resetButton_clicked()
{
    if(model)
    {
        // confirmation dialog
        QMessageBox::StandardButton btnRetVal = QMessageBox::question(this, tr("Confirm options reset"),
            tr("Client restart required to activate changes.") + "

" + tr("Client will be shutdown, do you want to proceed?"),
            QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel);

        if(btnRetVal == QMessageBox::Cancel)
            return;

        /* reset all options and close GUI */
        model->Reset();
        QApplication::quit();
    }
}

void OptionsDialog::on_okButton_clicked()
{
    mapper->submit();
    accept();
}

void OptionsDialog::on_cancelButton_clicked()
{
    reject();
}

void OptionsDialog::showRestartWarning(bool fPersistent)
{
    ui->statusLabel->setStyleSheet("QLabel { color: red; }");

    if(fPersistent)
    {
        ui->statusLabel->setText(tr("Client restart required to activate changes."));
    }
    else
    {
        ui->statusLabel->setText(tr("This change would require a client restart."));
        // clear non-persistent status label after 10 seconds
        // Todo: should perhaps be a class attribute, if we extend the use of statusLabel
        QTimer::singleShot(10000, this, SLOT(clearStatusLabel()));
    }
}

void OptionsDialog::clearStatusLabel()
{
    ui->statusLabel->clear();
}

void OptionsDialog::updateDisplayUnit()
{
    if(model)
    {
        /* Update transactionFee with the current unit */
        ui->transactionFee->setDisplayUnit(model->getDisplayUnit());
    }
}

void OptionsDialog::doProxyIpChecks(QValidatedLineEdit *pUiProxyIp, int nProxyPort)
{
    Q_UNUSED(nProxyPort);

    const std::string strAddrProxy = pUiProxyIp->text().toStdString();
    CService addrProxy;

    /* Check for a valid IPv4 / IPv6 address */
    if (!(fProxyIpValid = LookupNumeric(strAddrProxy.c_str(), addrProxy)))
    {
        disableOkButton();
        pUiProxyIp->setValid(false);
        ui->statusLabel->setStyleSheet("QLabel { color: red; }");
        ui->statusLabel->setText(tr("The supplied proxy address is invalid."));
    }
    else
    {
        enableOkButton();
        ui->statusLabel->clear();
    }
}

bool OptionsDialog::eventFilter(QObject *object, QEvent *event)
{
    if(event->type() == QEvent::FocusOut)
    {
        if(object == ui->proxyIp)
        {
            emit proxyIpChecks(ui->proxyIp, ui->proxyPort->text().toInt());
        }
    }
    return QDialog::eventFilter(object, event);
}
<|endoftext|>


<commit_before>/* This is free and unencumbered software released into the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "serd.h"
#include "../quad.h"
#include "../term.h"
#include "../triple.h"

#include <cassert>     /* for assert() */
#include <cstdarg>     /* for std::vsnprintf() */
#include <cstdio>      /* for std::fprintf(), std::snprintf() */
#include <cstring>     /* for std::strrchr() */
#include <functional>  /* for std::function */
#include <memory>      /* for std::unique_ptr */
#include <new>         /* for std::bad_alloc */

#include <serd/serd.h> /* for serd_*() */

////////////////////////////////////////////////////////////////////////////////

namespace {
  struct implementation final : public rdf::reader::implementation {
  public:
    implementation(FILE* stream,
      const char* content_type,
      const char* charset,
      const char* base_uri);
    virtual ~implementation() noexcept override;
    virtual void read_triples(std::function<void (std::unique_ptr<rdf::triple>)> callback) override;
    virtual void read_quads(std::function<void (std::unique_ptr<rdf::quad>)> callback) override;
    virtual void abort() override;

  protected:
    using serd_env_ptr = std::unique_ptr<SerdEnv, void(*)(SerdEnv*)>;
    using serd_reader_ptr = std::unique_ptr<SerdReader, void(*)(SerdReader*)>;

    void read();
    static SerdStatus base_sink(void* handle, const SerdNode* uri);
    static SerdStatus prefix_sink(void* handle, const SerdNode* name, const SerdNode* uri);
    static SerdStatus statement_sink(void* handle, SerdStatementFlags flags,
      const SerdNode* graph, const SerdNode* subject, const SerdNode* predicate,
      const SerdNode* object, const SerdNode* object_datatype, const SerdNode* object_lang);
    static SerdStatus end_sink(void* handle, const SerdNode* node);
    static SerdStatus error_sink(void* handle, const SerdError* error);
    static void throw_error(const char* func, SerdStatus status);
    static std::string expand_curie_or_uri(const char* type_label,
      const SerdEnv* env, const SerdNode* curie);
    static std::unique_ptr<rdf::term> make_term(const SerdEnv* env,
      const SerdNode* node,
      const SerdNode* node_datatype = nullptr,
      const SerdNode* node_language = nullptr);

  private:
    serd_env_ptr _env{nullptr, serd_env_free};
    serd_reader_ptr _reader{nullptr, serd_reader_free};
    std::function<void (std::unique_ptr<rdf::triple>)> _triple_callback;
    std::function<void (std::unique_ptr<rdf::quad>)> _quad_callback;
  };
}

////////////////////////////////////////////////////////////////////////////////

rdf::reader::implementation*
rdf_reader_for_serd(FILE* const stream,
                    const char* const content_type,
                    const char* const charset,
                    const char* const base_uri) {
  return new implementation(stream, content_type, charset, base_uri);
}

////////////////////////////////////////////////////////////////////////////////

implementation::implementation(FILE* const stream,
                               const char* const content_type,
                               const char* const charset,
                               const char* const base_uri_str) {
  static_cast<void>(content_type); /* not used */
  static_cast<void>(charset);      /* not used */

  assert(stream);

  if (base_uri_str) {
    SerdURI base_uri = SERD_URI_NULL;
    SerdNode base_uri_node = serd_node_new_uri_from_string(
      reinterpret_cast<const std::uint8_t*>(base_uri_str), nullptr, &base_uri);
    _env.reset(serd_env_new(&base_uri_node));
    serd_node_free(&base_uri_node);
  }
  else {
    _env.reset(serd_env_new(nullptr));
  }

  if (!_env) {
    throw std::bad_alloc(); /* out of memory */
  }

  _reader.reset(serd_reader_new(SERD_TURTLE, this, nullptr,
    implementation::base_sink,
    implementation::prefix_sink,
    implementation::statement_sink,
    implementation::end_sink));

  if (!_reader) {
    throw std::bad_alloc(); /* out of memory */
  }

  serd_reader_set_error_sink(_reader.get(), implementation::error_sink, this);
  //serd_reader_set_strict(_reader.get(), true);

  SerdStatus status;
  if ((status = serd_reader_start_stream(_reader.get(),
         stream, reinterpret_cast<const uint8_t*>("(stream)"), false)) != SERD_SUCCESS) {
    throw_error("serd_reader_start_stream", status);
  }
}

implementation::~implementation() noexcept {
  try { abort(); } catch (...) {}
}

void
implementation::read_triples(std::function<void (std::unique_ptr<rdf::triple>)> callback) {
  if (!_reader) return;

  _triple_callback = callback;
  _quad_callback   = nullptr;
  read();
}

void
implementation::read_quads(std::function<void (std::unique_ptr<rdf::quad>)> callback) {
  if (!_reader) return;

  _triple_callback = nullptr;
  _quad_callback   = callback;
  read();
}

void
implementation::abort() {
  if (!_reader) return;

  SerdStatus status;
  if ((status = serd_reader_end_stream(_reader.get())) != SERD_SUCCESS) {
    throw_error("serd_reader_end_stream", status);
  }

  _reader.reset();
}

void
implementation::read() {
  SerdStatus status = SERD_SUCCESS;
  while (status == SERD_SUCCESS) {
    status = serd_reader_read_chunk(_reader.get());
  }
}

////////////////////////////////////////////////////////////////////////////////

SerdStatus
implementation::base_sink(void* const handle,
                          const SerdNode* const uri) {
  if (0) std::fprintf(stderr, "%s: handle=%p uri=<%s>\n", __func__, handle, uri ? uri->buf : nullptr);

  assert(handle);
  const implementation& reader = *reinterpret_cast<implementation*>(handle);

  return serd_env_set_base_uri(reader._env.get(), uri);
}

SerdStatus
implementation::prefix_sink(void* const handle,
                            const SerdNode* const name,
                            const SerdNode* const uri) {
  if (0) std::fprintf(stderr, "%s: handle=%p name='%s' uri=<%s>\n", __func__, handle, name ? name->buf : nullptr, uri ? uri->buf : nullptr);

  assert(handle);
  const implementation& reader = *reinterpret_cast<implementation*>(handle);

  return serd_env_set_prefix(reader._env.get(), name, uri);
}

SerdStatus
implementation::statement_sink(void* const handle,
                               const SerdStatementFlags flags,
                               const SerdNode* const /*graph*/,
                               const SerdNode* const subject,
                               const SerdNode* const predicate,
                               const SerdNode* const object,
                               const SerdNode* const object_datatype,
                               const SerdNode* const object_lang) {
  if (0) std::fprintf(stderr, "%s: handle=%p flags=%d subject=%p predicate=%p object=%p object_datatype=%p object_lang=%p\n", __func__, handle, flags, subject, predicate, object, object_datatype, object_lang);

  assert(handle);
  const implementation& reader = *reinterpret_cast<implementation*>(handle);

  std::unique_ptr<rdf::term> subject_term{make_term(reader._env.get(), subject)};
  std::unique_ptr<rdf::term> predicate_term{make_term(reader._env.get(), predicate)};
  std::unique_ptr<rdf::term> object_term{make_term(reader._env.get(), object, object_datatype, object_lang)};

  if (reader._quad_callback) {
    std::unique_ptr<rdf::quad> quad{new rdf::quad{subject_term.release(), predicate_term.release(), object_term.release()}};
    reader._quad_callback(std::move(quad));
  }
  else if (reader._triple_callback) {
    std::unique_ptr<rdf::triple> triple{new rdf::triple{subject_term.release(), predicate_term.release(), object_term.release()}};
    reader._triple_callback(std::move(triple));
  }

  return SERD_SUCCESS;
}

SerdStatus
implementation::end_sink(void* const handle,
                         const SerdNode* const node) {
  if (0) std::fprintf(stderr, "%s: handle=%p node=%s\n", __func__, handle, node ? node->buf : nullptr);

  return SERD_SUCCESS;
}

SerdStatus
implementation::error_sink(void* const handle,
                           const SerdError* const error) {
  if (0) std::fprintf(stderr, "%s: handle=%p error=%s\n", __func__, handle, error ? error->fmt : nullptr);

  if (!error) {
    throw rdf::reader_error{"failed to parse input"};
  }

  switch (error->status) {
    case SERD_SUCCESS:        return SERD_SUCCESS;
    case SERD_FAILURE:        return SERD_SUCCESS;
    case SERD_ERR_UNKNOWN:    break;
    case SERD_ERR_BAD_SYNTAX: break;
    case SERD_ERR_BAD_ARG:    break;
    case SERD_ERR_NOT_FOUND:  break;
    case SERD_ERR_ID_CLASH:   break;
    case SERD_ERR_BAD_CURIE:  break;
    case SERD_ERR_INTERNAL:   break;
  }

  char error_detail[1024];
  std::vsnprintf(error_detail, sizeof(error_detail), error->fmt, *error->args);

  /* Trim the trailing "\n" from the Serd error detail: */
  const auto newline_ptr = std::strrchr(error_detail, '\n');
  if (newline_ptr) *newline_ptr = '\0';

  char error_message[4096];
  std::snprintf(error_message, sizeof(error_message), "%s: %s on line %u, column %u",
    error->filename ? reinterpret_cast<const char*>(error->filename) : "(stream)",
    error_detail, error->line, error->col);

  throw rdf::reader_error{error_message};

  return SERD_SUCCESS; /* never reached */
}

void
implementation::throw_error(const char* const symbol,
                            const SerdStatus status) {
  const char* status_str = nullptr;
  switch (status) {
    case SERD_SUCCESS: /* No error */
      return;
    case SERD_FAILURE: /* Non-fatal failure */
      status_str = "SERD_FAILURE";
      break;
    case SERD_ERR_UNKNOWN: /* Unknown error */
      status_str = "SERD_ERR_UNKNOWN";
      break;
    case SERD_ERR_BAD_SYNTAX: /* Invalid syntax */
      status_str = "SERD_ERR_BAD_SYNTAX";
      break;
    case SERD_ERR_BAD_ARG: /* Invalid argument */
      status_str = "SERD_ERR_BAD_ARG";
      break;
    case SERD_ERR_NOT_FOUND: /* Not found */
      status_str = "SERD_ERR_NOT_FOUND";
      break;
    case SERD_ERR_ID_CLASH: /* Encountered clashing blank node IDs */
      status_str = "SERD_ERR_ID_CLASH";
      break;
    case SERD_ERR_BAD_CURIE: /* Invalid CURIE (e.g. prefix does not exist) */
      status_str = "SERD_ERR_BAD_CURIE";
      break;
    case SERD_ERR_INTERNAL: /* Unexpected internal error (should not happen) */
      status_str = "SERD_ERR_INTERNAL";
      break;
  }
  char error_message[256];
  std::snprintf(error_message, sizeof(error_message), "%s() returned %s", symbol, status_str);
  throw rdf::reader_error{error_message};
}

////////////////////////////////////////////////////////////////////////////////

std::string
implementation::expand_curie_or_uri(const char* const type_label,
                                    const SerdEnv* const env,
                                    const SerdNode* const curie_or_uri) {
  SerdNode uri = serd_env_expand_node(env, curie_or_uri);

  if (uri.type == SERD_NOTHING) {
    char error_message[256];
    std::snprintf(error_message, sizeof(error_message),
      "failed to expand the %s node '%s'", type_label, curie_or_uri->buf);
    throw rdf::reader_error{error_message};
  }
  assert(uri.type == SERD_URI);

  std::string uri_string{const_cast<char*>(reinterpret_cast<const char*>(uri.buf))};
  serd_node_free(&uri);

  return uri_string;
}

std::unique_ptr<rdf::term>
implementation::make_term(const SerdEnv* const env,
                          const SerdNode* const node,
                          const SerdNode* const node_datatype,
                          const SerdNode* const node_language) {
  std::unique_ptr<rdf::term> term;
  if (node) {
    const char* const term_string = reinterpret_cast<const char*>(node->buf);
    switch (node->type) {
      case SERD_NOTHING: {
        assert(false && "node->type == SERD_NOTHING"); /* should never reach this */
        break;
      }
      case SERD_LITERAL: {
        if (node_datatype) {
          std::string term_datatype = expand_curie_or_uri(
            (node_datatype->type == SERD_CURIE) ? "CURIE" : "URI", env, node_datatype);
          term.reset(new rdf::typed_literal{term_string, term_datatype});
        }
        else if (node_language) {
          const char* const term_language = reinterpret_cast<const char*>(node_language->buf);
          term.reset(new rdf::plain_literal{term_string, term_language});
        }
        else {
          term.reset(new rdf::plain_literal{term_string});
        }
        break;
      }
      case SERD_URI: {
        term.reset(new rdf::uri_reference{expand_curie_or_uri("URI", env, node)});
        break;
      }
      case SERD_CURIE: {
        term.reset(new rdf::uri_reference{expand_curie_or_uri("CURIE", env, node)});
        break;
      }
      case SERD_BLANK: {
        term.reset(new rdf::blank_node{term_string});
        break;
      }
    }
  }
  return term;
}
<commit_msg>serd.cc: make calls to expand_curie_or_uri consistent<commit_after>/* This is free and unencumbered software released into the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "serd.h"
#include "../quad.h"
#include "../term.h"
#include "../triple.h"

#include <cassert>     /* for assert() */
#include <cstdarg>     /* for std::vsnprintf() */
#include <cstdio>      /* for std::fprintf(), std::snprintf() */
#include <cstring>     /* for std::strrchr() */
#include <functional>  /* for std::function */
#include <memory>      /* for std::unique_ptr */
#include <new>         /* for std::bad_alloc */

#include <serd/serd.h> /* for serd_*() */

////////////////////////////////////////////////////////////////////////////////

namespace {
  struct implementation final : public rdf::reader::implementation {
  public:
    implementation(FILE* stream,
      const char* content_type,
      const char* charset,
      const char* base_uri);
    virtual ~implementation() noexcept override;
    virtual void read_triples(std::function<void (std::unique_ptr<rdf::triple>)> callback) override;
    virtual void read_quads(std::function<void (std::unique_ptr<rdf::quad>)> callback) override;
    virtual void abort() override;

  protected:
    using serd_env_ptr = std::unique_ptr<SerdEnv, void(*)(SerdEnv*)>;
    using serd_reader_ptr = std::unique_ptr<SerdReader, void(*)(SerdReader*)>;

    void read();
    static SerdStatus base_sink(void* handle, const SerdNode* uri);
    static SerdStatus prefix_sink(void* handle, const SerdNode* name, const SerdNode* uri);
    static SerdStatus statement_sink(void* handle, SerdStatementFlags flags,
      const SerdNode* graph, const SerdNode* subject, const SerdNode* predicate,
      const SerdNode* object, const SerdNode* object_datatype, const SerdNode* object_lang);
    static SerdStatus end_sink(void* handle, const SerdNode* node);
    static SerdStatus error_sink(void* handle, const SerdError* error);
    static void throw_error(const char* func, SerdStatus status);
    static std::string expand_curie_or_uri(const char* type_label,
      const SerdEnv* env, const SerdNode* curie);
    static std::unique_ptr<rdf::term> make_term(const SerdEnv* env,
      const SerdNode* node,
      const SerdNode* node_datatype = nullptr,
      const SerdNode* node_language = nullptr);

  private:
    serd_env_ptr _env{nullptr, serd_env_free};
    serd_reader_ptr _reader{nullptr, serd_reader_free};
    std::function<void (std::unique_ptr<rdf::triple>)> _triple_callback;
    std::function<void (std::unique_ptr<rdf::quad>)> _quad_callback;
  };
}

////////////////////////////////////////////////////////////////////////////////

rdf::reader::implementation*
rdf_reader_for_serd(FILE* const stream,
                    const char* const content_type,
                    const char* const charset,
                    const char* const base_uri) {
  return new implementation(stream, content_type, charset, base_uri);
}

////////////////////////////////////////////////////////////////////////////////

implementation::implementation(FILE* const stream,
                               const char* const content_type,
                               const char* const charset,
                               const char* const base_uri_str) {
  static_cast<void>(content_type); /* not used */
  static_cast<void>(charset);      /* not used */

  assert(stream);

  if (base_uri_str) {
    SerdURI base_uri = SERD_URI_NULL;
    SerdNode base_uri_node = serd_node_new_uri_from_string(
      reinterpret_cast<const std::uint8_t*>(base_uri_str), nullptr, &base_uri);
    _env.reset(serd_env_new(&base_uri_node));
    serd_node_free(&base_uri_node);
  }
  else {
    _env.reset(serd_env_new(nullptr));
  }

  if (!_env) {
    throw std::bad_alloc(); /* out of memory */
  }

  _reader.reset(serd_reader_new(SERD_TURTLE, this, nullptr,
    implementation::base_sink,
    implementation::prefix_sink,
    implementation::statement_sink,
    implementation::end_sink));

  if (!_reader) {
    throw std::bad_alloc(); /* out of memory */
  }

  serd_reader_set_error_sink(_reader.get(), implementation::error_sink, this);
  //serd_reader_set_strict(_reader.get(), true);

  SerdStatus status;
  if ((status = serd_reader_start_stream(_reader.get(),
         stream, reinterpret_cast<const uint8_t*>("(stream)"), false)) != SERD_SUCCESS) {
    throw_error("serd_reader_start_stream", status);
  }
}

implementation::~implementation() noexcept {
  try { abort(); } catch (...) {}
}

void
implementation::read_triples(std::function<void (std::unique_ptr<rdf::triple>)> callback) {
  if (!_reader) return;

  _triple_callback = callback;
  _quad_callback   = nullptr;
  read();
}

void
implementation::read_quads(std::function<void (std::unique_ptr<rdf::quad>)> callback) {
  if (!_reader) return;

  _triple_callback = nullptr;
  _quad_callback   = callback;
  read();
}

void
implementation::abort() {
  if (!_reader) return;

  SerdStatus status;
  if ((status = serd_reader_end_stream(_reader.get())) != SERD_SUCCESS) {
    throw_error("serd_reader_end_stream", status);
  }

  _reader.reset();
}

void
implementation::read() {
  SerdStatus status = SERD_SUCCESS;
  while (status == SERD_SUCCESS) {
    status = serd_reader_read_chunk(_reader.get());
  }
}

////////////////////////////////////////////////////////////////////////////////

SerdStatus
implementation::base_sink(void* const handle,
                          const SerdNode* const uri) {
  if (0) std::fprintf(stderr, "%s: handle=%p uri=<%s>\n", __func__, handle, uri ? uri->buf : nullptr);

  assert(handle);
  const implementation& reader = *reinterpret_cast<implementation*>(handle);

  return serd_env_set_base_uri(reader._env.get(), uri);
}

SerdStatus
implementation::prefix_sink(void* const handle,
                            const SerdNode* const name,
                            const SerdNode* const uri) {
  if (0) std::fprintf(stderr, "%s: handle=%p name='%s' uri=<%s>\n", __func__, handle, name ? name->buf : nullptr, uri ? uri->buf : nullptr);

  assert(handle);
  const implementation& reader = *reinterpret_cast<implementation*>(handle);

  return serd_env_set_prefix(reader._env.get(), name, uri);
}

SerdStatus
implementation::statement_sink(void* const handle,
                               const SerdStatementFlags flags,
                               const SerdNode* const /*graph*/,
                               const SerdNode* const subject,
                               const SerdNode* const predicate,
                               const SerdNode* const object,
                               const SerdNode* const object_datatype,
                               const SerdNode* const object_lang) {
  if (0) std::fprintf(stderr, "%s: handle=%p flags=%d subject=%p predicate=%p object=%p object_datatype=%p object_lang=%p\n", __func__, handle, flags, subject, predicate, object, object_datatype, object_lang);

  assert(handle);
  const implementation& reader = *reinterpret_cast<implementation*>(handle);

  std::unique_ptr<rdf::term> subject_term{make_term(reader._env.get(), subject)};
  std::unique_ptr<rdf::term> predicate_term{make_term(reader._env.get(), predicate)};
  std::unique_ptr<rdf::term> object_term{make_term(reader._env.get(), object, object_datatype, object_lang)};

  if (reader._quad_callback) {
    std::unique_ptr<rdf::quad> quad{new rdf::quad{subject_term.release(), predicate_term.release(), object_term.release()}};
    reader._quad_callback(std::move(quad));
  }
  else if (reader._triple_callback) {
    std::unique_ptr<rdf::triple> triple{new rdf::triple{subject_term.release(), predicate_term.release(), object_term.release()}};
    reader._triple_callback(std::move(triple));
  }

  return SERD_SUCCESS;
}

SerdStatus
implementation::end_sink(void* const handle,
                         const SerdNode* const node) {
  if (0) std::fprintf(stderr, "%s: handle=%p node=%s\n", __func__, handle, node ? node->buf : nullptr);

  return SERD_SUCCESS;
}

SerdStatus
implementation::error_sink(void* const handle,
                           const SerdError* const error) {
  if (0) std::fprintf(stderr, "%s: handle=%p error=%s\n", __func__, handle, error ? error->fmt : nullptr);

  if (!error) {
    throw rdf::reader_error{"failed to parse input"};
  }

  switch (error->status) {
    case SERD_SUCCESS:        return SERD_SUCCESS;
    case SERD_FAILURE:        return SERD_SUCCESS;
    case SERD_ERR_UNKNOWN:    break;
    case SERD_ERR_BAD_SYNTAX: break;
    case SERD_ERR_BAD_ARG:    break;
    case SERD_ERR_NOT_FOUND:  break;
    case SERD_ERR_ID_CLASH:   break;
    case SERD_ERR_BAD_CURIE:  break;
    case SERD_ERR_INTERNAL:   break;
  }

  char error_detail[1024];
  std::vsnprintf(error_detail, sizeof(error_detail), error->fmt, *error->args);

  /* Trim the trailing "\n" from the Serd error detail: */
  const auto newline_ptr = std::strrchr(error_detail, '\n');
  if (newline_ptr) *newline_ptr = '\0';

  char error_message[4096];
  std::snprintf(error_message, sizeof(error_message), "%s: %s on line %u, column %u",
    error->filename ? reinterpret_cast<const char*>(error->filename) : "(stream)",
    error_detail, error->line, error->col);

  throw rdf::reader_error{error_message};

  return SERD_SUCCESS; /* never reached */
}

void
implementation::throw_error(const char* const symbol,
                            const SerdStatus status) {
  const char* status_str = nullptr;
  switch (status) {
    case SERD_SUCCESS: /* No error */
      return;
    case SERD_FAILURE: /* Non-fatal failure */
      status_str = "SERD_FAILURE";
      break;
    case SERD_ERR_UNKNOWN: /* Unknown error */
      status_str = "SERD_ERR_UNKNOWN";
      break;
    case SERD_ERR_BAD_SYNTAX: /* Invalid syntax */
      status_str = "SERD_ERR_BAD_SYNTAX";
      break;
    case SERD_ERR_BAD_ARG: /* Invalid argument */
      status_str = "SERD_ERR_BAD_ARG";
      break;
    case SERD_ERR_NOT_FOUND: /* Not found */
      status_str = "SERD_ERR_NOT_FOUND";
      break;
    case SERD_ERR_ID_CLASH: /* Encountered clashing blank node IDs */
      status_str = "SERD_ERR_ID_CLASH";
      break;
    case SERD_ERR_BAD_CURIE: /* Invalid CURIE (e.g. prefix does not exist) */
      status_str = "SERD_ERR_BAD_CURIE";
      break;
    case SERD_ERR_INTERNAL: /* Unexpected internal error (should not happen) */
      status_str = "SERD_ERR_INTERNAL";
      break;
  }
  char error_message[256];
  std::snprintf(error_message, sizeof(error_message), "%s() returned %s", symbol, status_str);
  throw rdf::reader_error{error_message};
}

////////////////////////////////////////////////////////////////////////////////

std::string
implementation::expand_curie_or_uri(const char* const type_label,
                                    const SerdEnv* const env,
                                    const SerdNode* const curie_or_uri) {
  SerdNode uri = serd_env_expand_node(env, curie_or_uri);

  if (uri.type == SERD_NOTHING) {
    char error_message[256];
    std::snprintf(error_message, sizeof(error_message),
      "failed to expand the %s node '%s'", type_label, curie_or_uri->buf);
    throw rdf::reader_error{error_message};
  }
  assert(uri.type == SERD_URI);

  std::string uri_string{const_cast<char*>(reinterpret_cast<const char*>(uri.buf))};
  serd_node_free(&uri);

  return uri_string;
}

std::unique_ptr<rdf::term>
implementation::make_term(const SerdEnv* const env,
                          const SerdNode* const node,
                          const SerdNode* const node_datatype,
                          const SerdNode* const node_language) {
  std::unique_ptr<rdf::term> term;
  if (node) {
    const char* const term_string = reinterpret_cast<const char*>(node->buf);
    switch (node->type) {
      case SERD_NOTHING: {
        assert(false && "node->type == SERD_NOTHING"); /* should never reach this */
        break;
      }
      case SERD_LITERAL: {
        if (node_datatype) {
          std::string uri_string = expand_curie_or_uri(
            (node_datatype->type == SERD_CURIE) ? "CURIE" : "URI", env, node_datatype);
          term.reset(new rdf::typed_literal{term_string, uri_string});
        }
        else if (node_language) {
          const char* const term_language = reinterpret_cast<const char*>(node_language->buf);
          term.reset(new rdf::plain_literal{term_string, term_language});
        }
        else {
          term.reset(new rdf::plain_literal{term_string});
        }
        break;
      }
      case SERD_URI: {
        std::string uri_string = expand_curie_or_uri("URI", env, node);
        term.reset(new rdf::uri_reference{uri_string});
        break;
      }
      case SERD_CURIE: {
        std::string uri_string = expand_curie_or_uri("CURIE", env, node);
        term.reset(new rdf::uri_reference{uri_string});
        break;
      }
      case SERD_BLANK: {
        term.reset(new rdf::blank_node{term_string});
        break;
      }
    }
  }
  return term;
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 Chris Pickel <sfiera@gmail.com>
//
// This file is part of librezin, a free software project.  You can redistribute it and/or modify
// it under the terms of the MIT License.

#include "rezin/BasicTypes.hpp"

#include <vector>
#include <rgos/rgos.hpp>
#include <sfz/sfz.hpp>
#include "rezin/BitsPiece.hpp"

using rgos::Json;
using rgos::StringMap;
using sfz::Bytes;
using sfz::BytesPiece;
using sfz::Exception;
using sfz::ReadSource;
using sfz::format;
using sfz::read;
using std::vector;

namespace rezin {

int16_t Rect::width() const {
    return right - left;
}

int16_t Rect::height() const {
    return bottom - top;
}

Json Rect::to_json() const {
    StringMap<Json> result;
    result["top"]       = Json::number(top);
    result["left"]      = Json::number(left);
    result["bottom"]    = Json::number(bottom);
    result["right"]     = Json::number(right);
    return Json::object(result);
}

void read_from(ReadSource in, Rect* out) {
    read(in, &out->top);
    read(in, &out->left);
    read(in, &out->bottom);
    read(in, &out->right);
}

double fixed32_t::to_double() const {
    return int_value / 65536.0;
}

Json fixed32_t::to_json() const {
    return Json::number(to_double());
}

void read_from(ReadSource in, fixed32_t* out) {
    read(in, &out->int_value);
}

Json PixMap::to_json() const {
    StringMap<Json> result;
    result["bounds"] = bounds.to_json();
    return Json::object(result);
}

void PixMap::read_pixels(ReadSource in, vector<uint8_t>* out) const {
    size_t size = row_bytes * bounds.height();
    Bytes bytes(size, '\0');
    in.shift(bytes.mutable_data(), size);

    BytesPiece remainder = bytes;
    for (int i = 0; i < bounds.height(); ++i) {
        BitsPiece bits(remainder.substr(0, row_bytes));
        for (int j = 0; j < bounds.width(); ++j) {
            uint8_t value;
            bits.shift(&value, pixel_size);
            out->push_back(value);
        }
        remainder.shift(row_bytes);
    }
}

void read_from(ReadSource in, PixMap* out) {
    read(in, &out->base_addr);
    read(in, &out->row_bytes);
    out->row_bytes &= 0x3fff;
    read(in, &out->bounds);
    read(in, &out->pm_version);
    read(in, &out->pack_type);
    read(in, &out->pack_size);
    read(in, &out->h_res);
    read(in, &out->v_res);
    read(in, &out->pixel_type);
    read(in, &out->pixel_size);
    read(in, &out->cmp_count);
    read(in, &out->cmp_size);
    read(in, &out->plane_bytes);
    read(in, &out->pm_table);
    read(in, &out->pm_reserved);

    if ((out->pixel_type != 0) || (out->pack_type != 0) || (out->pack_size != 0)
            || (out->cmp_count != 1) || (out->cmp_size != out->pixel_size)) {
        throw Exception("only indexed pixels are supported");
    }
    switch (out->pixel_size) {
      case 1:
      case 2:
      case 4:
      case 8:
        break;

      default:
        throw Exception(format("indexed pixels may not have size {0}", out->pixel_size));
    }
    if (out->plane_bytes != 0) {
        throw Exception("PixMap::plane_bytes must be 0");
    }
    if (out->base_addr != 0) {
        throw Exception("PixMap::base_addr must be 0");
    }
    if (out->pm_table != 0) {
        throw Exception("PixMap::pm_table must be 0");
    }
    if (out->pm_reserved != 0) {
        throw Exception("PixMap::pm_reserved must be 0");
    }
}

Json BitMap::to_json() const {
    StringMap<Json> result;
    result["bounds"] = bounds.to_json();
    return Json::object(result);
}

void BitMap::read_pixels(ReadSource in, vector<uint8_t>* out) const {
    size_t size = row_bytes * bounds.height();
    Bytes bytes(size, '\0');
    in.shift(bytes.mutable_data(), size);

    BytesPiece remainder = bytes;
    for (int i = 0; i < bounds.height(); ++i) {
        BitsPiece bits(remainder.substr(0, row_bytes));
        for (int j = 0; j < bounds.width(); ++j) {
            uint8_t value;
            bits.shift(&value, 1);
            out->push_back(value);
        }
        remainder.shift(row_bytes);
    }
}

void read_from(ReadSource in, BitMap* out) {
    read(in, &out->base_addr);
    read(in, &out->row_bytes);
    read(in, &out->bounds);

    if (out->base_addr != 0) {
        throw Exception("PixMap::base_addr must be 0");
    }
}

}  // namespace rezin
<commit_msg>Don't read pixels if row_bytes is 0.<commit_after>// Copyright (c) 2009 Chris Pickel <sfiera@gmail.com>
//
// This file is part of librezin, a free software project.  You can redistribute it and/or modify
// it under the terms of the MIT License.

#include "rezin/BasicTypes.hpp"

#include <vector>
#include <rgos/rgos.hpp>
#include <sfz/sfz.hpp>
#include "rezin/BitsPiece.hpp"

using rgos::Json;
using rgos::StringMap;
using sfz::Bytes;
using sfz::BytesPiece;
using sfz::Exception;
using sfz::ReadSource;
using sfz::format;
using sfz::read;
using std::vector;

namespace rezin {

int16_t Rect::width() const {
    return right - left;
}

int16_t Rect::height() const {
    return bottom - top;
}

Json Rect::to_json() const {
    StringMap<Json> result;
    result["top"]       = Json::number(top);
    result["left"]      = Json::number(left);
    result["bottom"]    = Json::number(bottom);
    result["right"]     = Json::number(right);
    return Json::object(result);
}

void read_from(ReadSource in, Rect* out) {
    read(in, &out->top);
    read(in, &out->left);
    read(in, &out->bottom);
    read(in, &out->right);
}

double fixed32_t::to_double() const {
    return int_value / 65536.0;
}

Json fixed32_t::to_json() const {
    return Json::number(to_double());
}

void read_from(ReadSource in, fixed32_t* out) {
    read(in, &out->int_value);
}

Json PixMap::to_json() const {
    StringMap<Json> result;
    result["bounds"] = bounds.to_json();
    return Json::object(result);
}

void PixMap::read_pixels(ReadSource in, vector<uint8_t>* out) const {
    if (row_bytes == 0) {
        return;
    }

    size_t size = row_bytes * bounds.height();
    Bytes bytes(size, '\0');
    in.shift(bytes.mutable_data(), size);

    BytesPiece remainder = bytes;
    for (int i = 0; i < bounds.height(); ++i) {
        BitsPiece bits(remainder.substr(0, row_bytes));
        for (int j = 0; j < bounds.width(); ++j) {
            uint8_t value;
            bits.shift(&value, pixel_size);
            out->push_back(value);
        }
        remainder.shift(row_bytes);
    }
}

void read_from(ReadSource in, PixMap* out) {
    read(in, &out->base_addr);
    read(in, &out->row_bytes);
    out->row_bytes &= 0x3fff;
    read(in, &out->bounds);
    read(in, &out->pm_version);
    read(in, &out->pack_type);
    read(in, &out->pack_size);
    read(in, &out->h_res);
    read(in, &out->v_res);
    read(in, &out->pixel_type);
    read(in, &out->pixel_size);
    read(in, &out->cmp_count);
    read(in, &out->cmp_size);
    read(in, &out->plane_bytes);
    read(in, &out->pm_table);
    read(in, &out->pm_reserved);

    if ((out->pixel_type != 0) || (out->pack_type != 0) || (out->pack_size != 0)
            || (out->cmp_count != 1) || (out->cmp_size != out->pixel_size)) {
        throw Exception("only indexed pixels are supported");
    }
    switch (out->pixel_size) {
      case 1:
      case 2:
      case 4:
      case 8:
        break;

      default:
        throw Exception(format("indexed pixels may not have size {0}", out->pixel_size));
    }
    if (out->plane_bytes != 0) {
        throw Exception("PixMap::plane_bytes must be 0");
    }
    if (out->base_addr != 0) {
        throw Exception("PixMap::base_addr must be 0");
    }
    if (out->pm_table != 0) {
        throw Exception("PixMap::pm_table must be 0");
    }
    if (out->pm_reserved != 0) {
        throw Exception("PixMap::pm_reserved must be 0");
    }
}

Json BitMap::to_json() const {
    StringMap<Json> result;
    result["bounds"] = bounds.to_json();
    return Json::object(result);
}

void BitMap::read_pixels(ReadSource in, vector<uint8_t>* out) const {
    if (row_bytes == 0) {
        return;
    }

    size_t size = row_bytes * bounds.height();
    Bytes bytes(size, '\0');
    in.shift(bytes.mutable_data(), size);

    BytesPiece remainder = bytes;
    for (int i = 0; i < bounds.height(); ++i) {
        BitsPiece bits(remainder.substr(0, row_bytes));
        for (int j = 0; j < bounds.width(); ++j) {
            uint8_t value;
            bits.shift(&value, 1);
            out->push_back(value);
        }
        remainder.shift(row_bytes);
    }
}

void read_from(ReadSource in, BitMap* out) {
    read(in, &out->base_addr);
    read(in, &out->row_bytes);
    read(in, &out->bounds);

    if (out->base_addr != 0) {
        throw Exception("PixMap::base_addr must be 0");
    }
}

}  // namespace rezin
<|endoftext|>


<commit_before>#ifndef _SEARCH_CONSTANTS_HPP_
#define _SEARCH_CONSTANTS_HPP_

const unsigned INITIAL_CLOSED_SET_SIZE = 25000000;

#endif /* !_SEARCH_CONSTANTS_HPP_ */
<commit_msg>INITIAL_CLOSED_SET_SIZE changed to 50M<commit_after>#ifndef _SEARCH_CONSTANTS_HPP_
#define _SEARCH_CONSTANTS_HPP_

const unsigned INITIAL_CLOSED_SET_SIZE = 50000000;

#endif /* !_SEARCH_CONSTANTS_HPP_ */
<|endoftext|>


<commit_before>//Copyright (c) 2017 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "sliceDataStorage.h"

#include "FffProcessor.h" //To create a mesh group with if none is provided.
#include "infill/SubDivCube.h" // For the destructor

namespace cura
{

Polygons& SliceLayerPart::getOwnInfillArea()
{
    return const_cast<Polygons&>(const_cast<const SliceLayerPart*>(this)->getOwnInfillArea());
}

const Polygons& SliceLayerPart::getOwnInfillArea() const
{
    if (infill_area_own)
    {
        return *infill_area_own;
    }
    else
    {
        return infill_area;
    }
}

bool SliceLayerPart::isUsed(const SettingsBaseVirtual& mesh_settings) const
{
    if (mesh_settings.getSettingAsCount("wall_line_count") > 0 && insets.size() > 0)
    { // note that in case wall line count is zero, the outline was pushed onto the insets
        return true;
    }
    if (skin_parts.size() > 0)
    {
        return true;
    }
    if (mesh_settings.getSettingBoolean("spaghetti_infill_enabled"))
    {
        if (spaghetti_infill_volumes.size() > 0)
        {
            return true;
        }
    }
    else if (mesh_settings.getSettingInMicrons("infill_line_distance") > 0)
    {
        for (const std::vector<Polygons>& infill_area_per_combine : infill_area_per_combine_per_density)
        {
            for (const Polygons& area : infill_area_per_combine)
            {
                if (area.size() > 0)
                {
                    return true;
                }
            }
        }
    }
    return false;
}

Polygons SliceLayer::getOutlines(bool external_polys_only) const
{
    Polygons ret;
    getOutlines(ret, external_polys_only);
    return ret;
}

void SliceLayer::getOutlines(Polygons& result, bool external_polys_only) const
{
    for (const SliceLayerPart& part : parts)
    {
        if (external_polys_only)
        {
            result.add(part.outline.outerPolygon());
        }
        else
        {
            result.add(part.print_outline);
        }
    }
}

Polygons SliceLayer::getSecondOrInnermostWalls() const
{
    Polygons ret;
    getSecondOrInnermostWalls(ret);
    return ret;
}

void SliceLayer::getSecondOrInnermostWalls(Polygons& layer_walls) const
{
    for (const SliceLayerPart& part : parts)
    {
        // we want the 2nd inner walls
        if (part.insets.size() >= 2) {
            layer_walls.add(part.insets[1]);
            continue;
        }
        // but we'll also take the inner wall if the 2nd doesn't exist
        if (part.insets.size() == 1) {
            layer_walls.add(part.insets[0]);
            continue;
        }
        // offset_from_outlines was so large that it completely destroyed our isle,
        // so we'll just use the regular outline
        layer_walls.add(part.outline);
        continue;
    }
}

SliceMeshStorage::~SliceMeshStorage()
{
    if (base_subdiv_cube)
    {
        delete base_subdiv_cube;
    }
}

bool SliceMeshStorage::getExtruderIsUsed(int extruder_nr) const
{
    if (getSettingAsCount("wall_line_count") > 0 && getSettingAsIndex("wall_0_extruder_nr") == extruder_nr)
    {
        return true;
    }
    if (getSettingAsCount("wall_line_count") > 1 && getSettingAsIndex("wall_x_extruder_nr") == extruder_nr)
    {
        return true;
    }
    if (getSettingInMicrons("infill_line_distance") > 0 && getSettingAsIndex("infill_extruder_nr") == extruder_nr)
    {
        return true;
    }
    if (getSettingAsIndex("top_bottom_extruder_nr") == extruder_nr)
    {
        return true;
    }
    return false;
}

bool SliceMeshStorage::getExtruderIsUsed(int extruder_nr, int layer_nr) const
{
    if (layer_nr < 0 || layer_nr >= static_cast<int>(layers.size()))
    {
        return false;
    }
    if (getSettingBoolean("anti_overhang_mesh")
        || getSettingBoolean("support_mesh"))
    { // object is not printed as object, but as support.
        return false;
    }
    const SliceLayer& layer = layers[layer_nr];
    if (getSettingAsCount("wall_line_count") > 0 && getSettingAsIndex("wall_0_extruder_nr") == extruder_nr)
    {
        for (const SliceLayerPart& part : layer.parts)
        {
            if (part.insets.size() > 0 && part.insets[0].size() > 0)
            {
                return true;
            }
        }
    }
    if (getSettingAsCount("wall_line_count") > 1 && getSettingAsIndex("wall_x_extruder_nr") == extruder_nr)
    {
        for (const SliceLayerPart& part : layer.parts)
        {
            if (part.insets.size() > 1 && part.insets[1].size() > 0)
            {
                return true;
            }
        }
    }
    if (getSettingInMicrons("infill_line_distance") > 0 && getSettingAsIndex("infill_extruder_nr") == extruder_nr)
    {
        for (const SliceLayerPart& part : layer.parts)
        {
            if (part.getOwnInfillArea().size() > 0)
            {
                return true;
            }
        }
    }
    if (getSettingAsIndex("top_bottom_extruder_nr") == extruder_nr)
    {
        for (const SliceLayerPart& part : layer.parts)
        {
            if (!part.skin_parts.empty())
            {
                return true;
            }
        }
    }
    return false;
}

std::vector<RetractionConfig> SliceDataStorage::initializeRetractionConfigs()
{
    std::vector<RetractionConfig> ret;
    ret.resize(meshgroup->getExtruderCount()); // initializes with constructor RetractionConfig()
    return ret;
}

SliceDataStorage::SliceDataStorage(MeshGroup* meshgroup) : SettingsMessenger(meshgroup),
    meshgroup(meshgroup != nullptr ? meshgroup : new MeshGroup(FffProcessor::getInstance())), //If no mesh group is provided, we roll our own.
    print_layer_count(0),
    retraction_config_per_extruder(initializeRetractionConfigs()),
    extruder_switch_retraction_config_per_extruder(initializeRetractionConfigs()),
    max_print_height_second_to_last_extruder(-1),
    primeTower(*this)
{
}

Polygons SliceDataStorage::getLayerOutlines(int layer_nr, bool include_helper_parts, bool external_polys_only) const
{
    if (layer_nr < 0 && layer_nr < -Raft::getFillerLayerCount(*this))
    { // when processing raft
        if (include_helper_parts)
        {
            if (external_polys_only)
            {
                std::vector<PolygonsPart> parts = raftOutline.splitIntoParts();
                Polygons result;
                for (PolygonsPart& part : parts)
                {
                    result.add(part.outerPolygon());
                }
                return result;
            }
            else
            {
                return raftOutline;
            }
        }
        else
        {
            return Polygons();
        }
    }
    else
    {
        Polygons total;
        if (layer_nr >= 0)
        {
            for (const SliceMeshStorage& mesh : meshes)
            {
                if (mesh.getSettingBoolean("infill_mesh") || mesh.getSettingBoolean("anti_overhang_mesh"))
                {
                    continue;
                }
                const SliceLayer& layer = mesh.layers[layer_nr];
                layer.getOutlines(total, external_polys_only);
                if (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL)
                {
                    total = total.unionPolygons(layer.openPolyLines.offsetPolyLine(100));
                }
            }
        }
        if (include_helper_parts)
        {
            if (support.generated)
            {
                total.add(support.supportLayers[std::max(0, layer_nr)].supportAreas);
                total.add(support.supportLayers[std::max(0, layer_nr)].support_bottom);
                total.add(support.supportLayers[std::max(0, layer_nr)].support_roof);
            }
            if (primeTower.enabled)
            {
                total.add(primeTower.ground_poly);
            }
        }
        return total;
    }
}

Polygons SliceDataStorage::getLayerSecondOrInnermostWalls(int layer_nr, bool include_helper_parts) const
{
    if (layer_nr < 0 && layer_nr < -Raft::getFillerLayerCount(*this))
    { // when processing raft
        if (include_helper_parts)
        {
            return raftOutline;
        }
        else
        {
            return Polygons();
        }
    }
    else
    {
        Polygons total;
        if (layer_nr >= 0)
        {
            for (const SliceMeshStorage& mesh : meshes)
            {
                const SliceLayer& layer = mesh.layers[layer_nr];
                layer.getSecondOrInnermostWalls(total);
                if (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL)
                {
                    total = total.unionPolygons(layer.openPolyLines.offsetPolyLine(100));
                }
            }
        }
        if (include_helper_parts)
        {
            if (support.generated)
            {
                total.add(support.supportLayers[std::max(0, layer_nr)].supportAreas);
                total.add(support.supportLayers[std::max(0, layer_nr)].support_bottom);
                total.add(support.supportLayers[std::max(0, layer_nr)].support_roof);
            }
            if (primeTower.enabled)
            {
                total.add(primeTower.ground_poly);
            }
        }
        return total;
    }

}

std::vector<bool> SliceDataStorage::getExtrudersUsed() const
{

    std::vector<bool> ret;
    ret.resize(meshgroup->getExtruderCount(), false);

    if (getSettingAsPlatformAdhesion("adhesion_type") != EPlatformAdhesion::NONE)
    {
        ret[getSettingAsIndex("adhesion_extruder_nr")] = true;
        { // process brim/skirt
            for (int extr_nr = 0; extr_nr < meshgroup->getExtruderCount(); extr_nr++)
            {
                if (skirt_brim[extr_nr].size() > 0)
                {
                    ret[extr_nr] = true;
                    continue;
                }
            }
        }
    }

    // TODO: ooze shield, draft shield ..?

    // support
    // support is presupposed to be present...
    for (const SliceMeshStorage& mesh : meshes)
    {
        if (mesh.getSettingBoolean("support_enable") || mesh.getSettingBoolean("support_mesh"))
        {
            ret[getSettingAsIndex("support_extruder_nr_layer_0")] = true;
            ret[getSettingAsIndex("support_infill_extruder_nr")] = true;
            if (getSettingBoolean("support_roof_enable"))
            {
                ret[getSettingAsIndex("support_roof_extruder_nr")] = true;
            }
            if (getSettingBoolean("support_bottom_enable"))
            {
                ret[getSettingAsIndex("support_bottom_extruder_nr")] = true;
            }
        }
    }

    // all meshes are presupposed to actually have content
    for (const SliceMeshStorage& mesh : meshes)
    {
        if (!mesh.getSettingBoolean("anti_overhang_mesh")
            && !mesh.getSettingBoolean("support_mesh")
        )
        {
            ret[mesh.getSettingAsIndex("extruder_nr")] = true;
        }
    }
    return ret;
}

std::vector<bool> SliceDataStorage::getExtrudersUsed(int layer_nr) const
{

    std::vector<bool> ret;
    ret.resize(meshgroup->getExtruderCount(), false);

    bool include_adhesion = true;
    bool include_helper_parts = true;
    bool include_models = true;
    if (layer_nr < 0)
    {
        include_models = false;
        if (layer_nr < -Raft::getFillerLayerCount(*this))
        {
            include_helper_parts = false;
        }
        else
        {
            layer_nr = 0; // because the helper parts are copied from the initial layer in the filler layer
            include_adhesion = false;
        }
    }
    else if (layer_nr > 0 || getSettingAsPlatformAdhesion("adhesion_type") == EPlatformAdhesion::RAFT)
    { // only include adhesion only for layers where platform adhesion actually occurs
        // i.e. layers < 0 are for raft, layer 0 is for brim/skirt
        include_adhesion = false;
    }
    if (include_adhesion)
    {
        ret[getSettingAsIndex("adhesion_extruder_nr")] = true;
        { // process brim/skirt
            for (int extr_nr = 0; extr_nr < meshgroup->getExtruderCount(); extr_nr++)
            {
                if (skirt_brim[extr_nr].size() > 0)
                {
                    ret[extr_nr] = true;
                    continue;
                }
            }
        }
    }

    // TODO: ooze shield, draft shield ..?

    if (include_helper_parts)
    {
        // support
        if (layer_nr < int(support.supportLayers.size()))
        {
            const SupportLayer& support_layer = support.supportLayers[layer_nr];
            if (layer_nr == 0)
            {
                if (!support_layer.supportAreas.empty())
                {
                    ret[getSettingAsIndex("support_extruder_nr_layer_0")] = true;
                }
            }
            else
            {
                if (!support_layer.supportAreas.empty())
                {
                    ret[getSettingAsIndex("support_infill_extruder_nr")] = true;
                }
            }
            if (!support_layer.support_bottom.empty())
            {
                ret[getSettingAsIndex("support_bottom_extruder_nr")] = true;
            }
            if (!support_layer.support_roof.empty())
            {
                ret[getSettingAsIndex("support_roof_extruder_nr")] = true;
            }
        }
    }

    if (include_models)
    {
        for (const SliceMeshStorage& mesh : meshes)
        {
            if (layer_nr >= int(mesh.layers.size()))
            {
                continue;
            }
            const SliceLayer& layer = mesh.layers[layer_nr];
            for (const SliceLayerPart& part : layer.parts)
            {
                if (part.isUsed(mesh))
                {
                    ret[mesh.getSettingAsIndex("extruder_nr")] = true;
                    break;
                }
            }
        }
    }
    return ret;
}

} // namespace cura<commit_msg>fix: SliceDataStorage::getExtrudersUsed no longer relies on extruder_nr (CURA-3737)<commit_after>//Copyright (c) 2017 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "sliceDataStorage.h"

#include "FffProcessor.h" //To create a mesh group with if none is provided.
#include "infill/SubDivCube.h" // For the destructor

namespace cura
{

Polygons& SliceLayerPart::getOwnInfillArea()
{
    return const_cast<Polygons&>(const_cast<const SliceLayerPart*>(this)->getOwnInfillArea());
}

const Polygons& SliceLayerPart::getOwnInfillArea() const
{
    if (infill_area_own)
    {
        return *infill_area_own;
    }
    else
    {
        return infill_area;
    }
}

bool SliceLayerPart::isUsed(const SettingsBaseVirtual& mesh_settings) const
{
    if (mesh_settings.getSettingAsCount("wall_line_count") > 0 && insets.size() > 0)
    { // note that in case wall line count is zero, the outline was pushed onto the insets
        return true;
    }
    if (skin_parts.size() > 0)
    {
        return true;
    }
    if (mesh_settings.getSettingBoolean("spaghetti_infill_enabled"))
    {
        if (spaghetti_infill_volumes.size() > 0)
        {
            return true;
        }
    }
    else if (mesh_settings.getSettingInMicrons("infill_line_distance") > 0)
    {
        for (const std::vector<Polygons>& infill_area_per_combine : infill_area_per_combine_per_density)
        {
            for (const Polygons& area : infill_area_per_combine)
            {
                if (area.size() > 0)
                {
                    return true;
                }
            }
        }
    }
    return false;
}

Polygons SliceLayer::getOutlines(bool external_polys_only) const
{
    Polygons ret;
    getOutlines(ret, external_polys_only);
    return ret;
}

void SliceLayer::getOutlines(Polygons& result, bool external_polys_only) const
{
    for (const SliceLayerPart& part : parts)
    {
        if (external_polys_only)
        {
            result.add(part.outline.outerPolygon());
        }
        else
        {
            result.add(part.print_outline);
        }
    }
}

Polygons SliceLayer::getSecondOrInnermostWalls() const
{
    Polygons ret;
    getSecondOrInnermostWalls(ret);
    return ret;
}

void SliceLayer::getSecondOrInnermostWalls(Polygons& layer_walls) const
{
    for (const SliceLayerPart& part : parts)
    {
        // we want the 2nd inner walls
        if (part.insets.size() >= 2) {
            layer_walls.add(part.insets[1]);
            continue;
        }
        // but we'll also take the inner wall if the 2nd doesn't exist
        if (part.insets.size() == 1) {
            layer_walls.add(part.insets[0]);
            continue;
        }
        // offset_from_outlines was so large that it completely destroyed our isle,
        // so we'll just use the regular outline
        layer_walls.add(part.outline);
        continue;
    }
}

SliceMeshStorage::~SliceMeshStorage()
{
    if (base_subdiv_cube)
    {
        delete base_subdiv_cube;
    }
}

bool SliceMeshStorage::getExtruderIsUsed(int extruder_nr) const
{
    if (getSettingAsCount("wall_line_count") > 0 && getSettingAsIndex("wall_0_extruder_nr") == extruder_nr)
    {
        return true;
    }
    if (getSettingAsCount("wall_line_count") > 1 && getSettingAsIndex("wall_x_extruder_nr") == extruder_nr)
    {
        return true;
    }
    if (getSettingInMicrons("infill_line_distance") > 0 && getSettingAsIndex("infill_extruder_nr") == extruder_nr)
    {
        return true;
    }
    if (getSettingAsIndex("top_bottom_extruder_nr") == extruder_nr)
    {
        return true;
    }
    return false;
}

bool SliceMeshStorage::getExtruderIsUsed(int extruder_nr, int layer_nr) const
{
    if (layer_nr < 0 || layer_nr >= static_cast<int>(layers.size()))
    {
        return false;
    }
    if (getSettingBoolean("anti_overhang_mesh")
        || getSettingBoolean("support_mesh"))
    { // object is not printed as object, but as support.
        return false;
    }
    const SliceLayer& layer = layers[layer_nr];
    if (getSettingAsCount("wall_line_count") > 0 && getSettingAsIndex("wall_0_extruder_nr") == extruder_nr)
    {
        for (const SliceLayerPart& part : layer.parts)
        {
            if (part.insets.size() > 0 && part.insets[0].size() > 0)
            {
                return true;
            }
        }
    }
    if (getSettingAsCount("wall_line_count") > 1 && getSettingAsIndex("wall_x_extruder_nr") == extruder_nr)
    {
        for (const SliceLayerPart& part : layer.parts)
        {
            if (part.insets.size() > 1 && part.insets[1].size() > 0)
            {
                return true;
            }
        }
    }
    if (getSettingInMicrons("infill_line_distance") > 0 && getSettingAsIndex("infill_extruder_nr") == extruder_nr)
    {
        for (const SliceLayerPart& part : layer.parts)
        {
            if (part.getOwnInfillArea().size() > 0)
            {
                return true;
            }
        }
    }
    if (getSettingAsIndex("top_bottom_extruder_nr") == extruder_nr)
    {
        for (const SliceLayerPart& part : layer.parts)
        {
            if (!part.skin_parts.empty())
            {
                return true;
            }
        }
    }
    return false;
}

std::vector<RetractionConfig> SliceDataStorage::initializeRetractionConfigs()
{
    std::vector<RetractionConfig> ret;
    ret.resize(meshgroup->getExtruderCount()); // initializes with constructor RetractionConfig()
    return ret;
}

SliceDataStorage::SliceDataStorage(MeshGroup* meshgroup) : SettingsMessenger(meshgroup),
    meshgroup(meshgroup != nullptr ? meshgroup : new MeshGroup(FffProcessor::getInstance())), //If no mesh group is provided, we roll our own.
    print_layer_count(0),
    retraction_config_per_extruder(initializeRetractionConfigs()),
    extruder_switch_retraction_config_per_extruder(initializeRetractionConfigs()),
    max_print_height_second_to_last_extruder(-1),
    primeTower(*this)
{
}

Polygons SliceDataStorage::getLayerOutlines(int layer_nr, bool include_helper_parts, bool external_polys_only) const
{
    if (layer_nr < 0 && layer_nr < -Raft::getFillerLayerCount(*this))
    { // when processing raft
        if (include_helper_parts)
        {
            if (external_polys_only)
            {
                std::vector<PolygonsPart> parts = raftOutline.splitIntoParts();
                Polygons result;
                for (PolygonsPart& part : parts)
                {
                    result.add(part.outerPolygon());
                }
                return result;
            }
            else
            {
                return raftOutline;
            }
        }
        else
        {
            return Polygons();
        }
    }
    else
    {
        Polygons total;
        if (layer_nr >= 0)
        {
            for (const SliceMeshStorage& mesh : meshes)
            {
                if (mesh.getSettingBoolean("infill_mesh") || mesh.getSettingBoolean("anti_overhang_mesh"))
                {
                    continue;
                }
                const SliceLayer& layer = mesh.layers[layer_nr];
                layer.getOutlines(total, external_polys_only);
                if (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL)
                {
                    total = total.unionPolygons(layer.openPolyLines.offsetPolyLine(100));
                }
            }
        }
        if (include_helper_parts)
        {
            if (support.generated)
            {
                total.add(support.supportLayers[std::max(0, layer_nr)].supportAreas);
                total.add(support.supportLayers[std::max(0, layer_nr)].support_bottom);
                total.add(support.supportLayers[std::max(0, layer_nr)].support_roof);
            }
            if (primeTower.enabled)
            {
                total.add(primeTower.ground_poly);
            }
        }
        return total;
    }
}

Polygons SliceDataStorage::getLayerSecondOrInnermostWalls(int layer_nr, bool include_helper_parts) const
{
    if (layer_nr < 0 && layer_nr < -Raft::getFillerLayerCount(*this))
    { // when processing raft
        if (include_helper_parts)
        {
            return raftOutline;
        }
        else
        {
            return Polygons();
        }
    }
    else
    {
        Polygons total;
        if (layer_nr >= 0)
        {
            for (const SliceMeshStorage& mesh : meshes)
            {
                const SliceLayer& layer = mesh.layers[layer_nr];
                layer.getSecondOrInnermostWalls(total);
                if (mesh.getSettingAsSurfaceMode("magic_mesh_surface_mode") != ESurfaceMode::NORMAL)
                {
                    total = total.unionPolygons(layer.openPolyLines.offsetPolyLine(100));
                }
            }
        }
        if (include_helper_parts)
        {
            if (support.generated)
            {
                total.add(support.supportLayers[std::max(0, layer_nr)].supportAreas);
                total.add(support.supportLayers[std::max(0, layer_nr)].support_bottom);
                total.add(support.supportLayers[std::max(0, layer_nr)].support_roof);
            }
            if (primeTower.enabled)
            {
                total.add(primeTower.ground_poly);
            }
        }
        return total;
    }

}

std::vector<bool> SliceDataStorage::getExtrudersUsed() const
{

    std::vector<bool> ret;
    ret.resize(meshgroup->getExtruderCount(), false);

    if (getSettingAsPlatformAdhesion("adhesion_type") != EPlatformAdhesion::NONE)
    {
        ret[getSettingAsIndex("adhesion_extruder_nr")] = true;
        { // process brim/skirt
            for (int extr_nr = 0; extr_nr < meshgroup->getExtruderCount(); extr_nr++)
            {
                if (skirt_brim[extr_nr].size() > 0)
                {
                    ret[extr_nr] = true;
                    continue;
                }
            }
        }
    }

    // TODO: ooze shield, draft shield ..?

    // support
    // support is presupposed to be present...
    for (const SliceMeshStorage& mesh : meshes)
    {
        if (mesh.getSettingBoolean("support_enable") || mesh.getSettingBoolean("support_mesh"))
        {
            ret[getSettingAsIndex("support_extruder_nr_layer_0")] = true;
            ret[getSettingAsIndex("support_infill_extruder_nr")] = true;
            if (getSettingBoolean("support_roof_enable"))
            {
                ret[getSettingAsIndex("support_roof_extruder_nr")] = true;
            }
            if (getSettingBoolean("support_bottom_enable"))
            {
                ret[getSettingAsIndex("support_bottom_extruder_nr")] = true;
            }
        }
    }

    // all meshes are presupposed to actually have content
    for (const SliceMeshStorage& mesh : meshes)
    {
        for (unsigned int extruder_nr = 0; extruder_nr <= ret.size(); extruder_nr++)
        {
            ret[extruder_nr] = ret[extruder_nr] || mesh.getExtruderIsUsed(extruder_nr);
        }
    }
    return ret;
}

std::vector<bool> SliceDataStorage::getExtrudersUsed(int layer_nr) const
{

    std::vector<bool> ret;
    ret.resize(meshgroup->getExtruderCount(), false);

    bool include_adhesion = true;
    bool include_helper_parts = true;
    bool include_models = true;
    if (layer_nr < 0)
    {
        include_models = false;
        if (layer_nr < -Raft::getFillerLayerCount(*this))
        {
            include_helper_parts = false;
        }
        else
        {
            layer_nr = 0; // because the helper parts are copied from the initial layer in the filler layer
            include_adhesion = false;
        }
    }
    else if (layer_nr > 0 || getSettingAsPlatformAdhesion("adhesion_type") == EPlatformAdhesion::RAFT)
    { // only include adhesion only for layers where platform adhesion actually occurs
        // i.e. layers < 0 are for raft, layer 0 is for brim/skirt
        include_adhesion = false;
    }
    if (include_adhesion)
    {
        ret[getSettingAsIndex("adhesion_extruder_nr")] = true;
        { // process brim/skirt
            for (int extr_nr = 0; extr_nr < meshgroup->getExtruderCount(); extr_nr++)
            {
                if (skirt_brim[extr_nr].size() > 0)
                {
                    ret[extr_nr] = true;
                    continue;
                }
            }
        }
    }

    // TODO: ooze shield, draft shield ..?

    if (include_helper_parts)
    {
        // support
        if (layer_nr < int(support.supportLayers.size()))
        {
            const SupportLayer& support_layer = support.supportLayers[layer_nr];
            if (layer_nr == 0)
            {
                if (!support_layer.supportAreas.empty())
                {
                    ret[getSettingAsIndex("support_extruder_nr_layer_0")] = true;
                }
            }
            else
            {
                if (!support_layer.supportAreas.empty())
                {
                    ret[getSettingAsIndex("support_infill_extruder_nr")] = true;
                }
            }
            if (!support_layer.support_bottom.empty())
            {
                ret[getSettingAsIndex("support_bottom_extruder_nr")] = true;
            }
            if (!support_layer.support_roof.empty())
            {
                ret[getSettingAsIndex("support_roof_extruder_nr")] = true;
            }
        }
    }

    if (include_models)
    {
        for (const SliceMeshStorage& mesh : meshes)
        {
            for (unsigned int extruder_nr = 0; extruder_nr <= ret.size(); extruder_nr++)
            {
                ret[extruder_nr] = ret[extruder_nr] || mesh.getExtruderIsUsed(extruder_nr, layer_nr);
            }
        }
    }
    return ret;
}

} // namespace cura<|endoftext|>