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

#include <qt/walletframe.h>

#include <fs.h>
#include <node/ui_interface.h>
#include <psbt.h>
#include <qt/guiutil.h>
#include <qt/overviewpage.h>
#include <qt/psbtoperationsdialog.h>
#include <qt/walletmodel.h>
#include <qt/walletview.h>
#include <util/system.h>

#include <cassert>
#include <fstream>
#include <string>

#include <QApplication>
#include <QClipboard>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>

WalletFrame::WalletFrame(const PlatformStyle* _platformStyle, QWidget* parent)
    : QFrame(parent),
      platformStyle(_platformStyle),
      m_size_hint(OverviewPage{platformStyle, nullptr}.sizeHint())
{
    // Leave HBox hook for adding a list view later
    QHBoxLayout *walletFrameLayout = new QHBoxLayout(this);
    setContentsMargins(0,0,0,0);
    walletStack = new QStackedWidget(this);
    walletFrameLayout->setContentsMargins(0,0,0,0);
    walletFrameLayout->addWidget(walletStack);

    // hbox for no wallet
    QGroupBox* no_wallet_group = new QGroupBox(walletStack);
    QVBoxLayout* no_wallet_layout = new QVBoxLayout(no_wallet_group);

    QLabel *noWallet = new QLabel(tr("No wallet has been loaded.\nGo to File > Open Wallet to load a wallet.\n- OR -"));
    noWallet->setAlignment(Qt::AlignCenter);
    no_wallet_layout->addWidget(noWallet, 0, Qt::AlignHCenter | Qt::AlignBottom);

    // A button for create wallet dialog
    QPushButton* create_wallet_button = new QPushButton(tr("Create a new wallet"), walletStack);
    connect(create_wallet_button, &QPushButton::clicked, this, &WalletFrame::createWalletButtonClicked);
    no_wallet_layout->addWidget(create_wallet_button, 0, Qt::AlignHCenter | Qt::AlignTop);
    no_wallet_group->setLayout(no_wallet_layout);

    walletStack->addWidget(no_wallet_group);
}

WalletFrame::~WalletFrame()
{
}

void WalletFrame::setClientModel(ClientModel *_clientModel)
{
    this->clientModel = _clientModel;

    for (auto i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) {
        i.value()->setClientModel(_clientModel);
    }
}

bool WalletFrame::addView(WalletView* walletView)
{
    if (!clientModel) return false;

    if (mapWalletViews.count(walletView->getWalletModel()) > 0) return false;

    walletView->setClientModel(clientModel);
    walletView->showOutOfSyncWarning(bOutOfSync);

    WalletView* current_wallet_view = currentWalletView();
    if (current_wallet_view) {
        walletView->setCurrentIndex(current_wallet_view->currentIndex());
    } else {
        walletView->gotoOverviewPage();
    }

    walletStack->addWidget(walletView);
    mapWalletViews[walletView->getWalletModel()] = walletView;

    return true;
}

void WalletFrame::setCurrentWallet(WalletModel* wallet_model)
{
    if (mapWalletViews.count(wallet_model) == 0) return;

    // Stop the effect of hidden widgets on the size hint of the shown one in QStackedWidget.
    WalletView* view_about_to_hide = currentWalletView();
    if (view_about_to_hide) {
        QSizePolicy sp = view_about_to_hide->sizePolicy();
        sp.setHorizontalPolicy(QSizePolicy::Ignored);
        view_about_to_hide->setSizePolicy(sp);
    }

    WalletView *walletView = mapWalletViews.value(wallet_model);
    assert(walletView);

    // Set or restore the default QSizePolicy which could be set to QSizePolicy::Ignored previously.
    QSizePolicy sp = walletView->sizePolicy();
    sp.setHorizontalPolicy(QSizePolicy::Preferred);
    walletView->setSizePolicy(sp);
    walletView->updateGeometry();

    walletStack->setCurrentWidget(walletView);

    Q_EMIT currentWalletSet();
}

void WalletFrame::removeWallet(WalletModel* wallet_model)
{
    if (mapWalletViews.count(wallet_model) == 0) return;

    WalletView *walletView = mapWalletViews.take(wallet_model);
    walletStack->removeWidget(walletView);
    delete walletView;
}

void WalletFrame::removeAllWallets()
{
    QMap<WalletModel*, WalletView*>::const_iterator i;
    for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
        walletStack->removeWidget(i.value());
    mapWalletViews.clear();
}

bool WalletFrame::handlePaymentRequest(const SendCoinsRecipient &recipient)
{
    WalletView *walletView = currentWalletView();
    if (!walletView)
        return false;

    return walletView->handlePaymentRequest(recipient);
}

void WalletFrame::showOutOfSyncWarning(bool fShow)
{
    bOutOfSync = fShow;
    QMap<WalletModel*, WalletView*>::const_iterator i;
    for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
        i.value()->showOutOfSyncWarning(fShow);
}

void WalletFrame::gotoOverviewPage()
{
    QMap<WalletModel*, WalletView*>::const_iterator i;
    for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
        i.value()->gotoOverviewPage();
}

void WalletFrame::gotoHistoryPage()
{
    QMap<WalletModel*, WalletView*>::const_iterator i;
    for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
        i.value()->gotoHistoryPage();
}

void WalletFrame::gotoReceiveCoinsPage()
{
    QMap<WalletModel*, WalletView*>::const_iterator i;
    for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
        i.value()->gotoReceiveCoinsPage();
}

void WalletFrame::gotoSendCoinsPage(QString addr)
{
    QMap<WalletModel*, WalletView*>::const_iterator i;
    for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
        i.value()->gotoSendCoinsPage(addr);
}

void WalletFrame::gotoSignMessageTab(QString addr)
{
    WalletView *walletView = currentWalletView();
    if (walletView)
        walletView->gotoSignMessageTab(addr);
}

void WalletFrame::gotoVerifyMessageTab(QString addr)
{
    WalletView *walletView = currentWalletView();
    if (walletView)
        walletView->gotoVerifyMessageTab(addr);
}

void WalletFrame::gotoLoadPSBT(bool from_clipboard)
{
    std::string data;

    if (from_clipboard) {
        std::string raw = QApplication::clipboard()->text().toStdString();
        bool invalid;
        data = DecodeBase64(raw, &invalid);
        if (invalid) {
            Q_EMIT message(tr("Error"), tr("Unable to decode PSBT from clipboard (invalid base64)"), CClientUIInterface::MSG_ERROR);
            return;
        }
    } else {
        QString filename = GUIUtil::getOpenFileName(this,
            tr("Load Transaction Data"), QString(),
            tr("Partially Signed Transaction (*.psbt)"), nullptr);
        if (filename.isEmpty()) return;
        if (GetFileSize(filename.toLocal8Bit().data(), MAX_FILE_SIZE_PSBT) == MAX_FILE_SIZE_PSBT) {
            Q_EMIT message(tr("Error"), tr("PSBT file must be smaller than 100 MiB"), CClientUIInterface::MSG_ERROR);
            return;
        }
        std::ifstream in{filename.toLocal8Bit().data(), std::ios::binary};
        data = std::string(std::istreambuf_iterator<char>{in}, {});
    }

    std::string error;
    PartiallySignedTransaction psbtx;
    if (!DecodeRawPSBT(psbtx, data, error)) {
        Q_EMIT message(tr("Error"), tr("Unable to decode PSBT") + "\n" + QString::fromStdString(error), CClientUIInterface::MSG_ERROR);
        return;
    }

    auto dlg = new PSBTOperationsDialog(this, currentWalletModel(), clientModel);
    dlg->openWithPSBT(psbtx);
    GUIUtil::ShowModalDialogAsynchronously(dlg);
}

void WalletFrame::encryptWallet()
{
    WalletView *walletView = currentWalletView();
    if (walletView)
        walletView->encryptWallet();
}

void WalletFrame::backupWallet()
{
    WalletView *walletView = currentWalletView();
    if (walletView)
        walletView->backupWallet();
}

void WalletFrame::changePassphrase()
{
    WalletView *walletView = currentWalletView();
    if (walletView)
        walletView->changePassphrase();
}

void WalletFrame::unlockWallet()
{
    WalletView *walletView = currentWalletView();
    if (walletView)
        walletView->unlockWallet();
}

void WalletFrame::usedSendingAddresses()
{
    WalletView *walletView = currentWalletView();
    if (walletView)
        walletView->usedSendingAddresses();
}

void WalletFrame::usedReceivingAddresses()
{
    WalletView *walletView = currentWalletView();
    if (walletView)
        walletView->usedReceivingAddresses();
}

WalletView* WalletFrame::currentWalletView() const
{
    return qobject_cast<WalletView*>(walletStack->currentWidget());
}

WalletModel* WalletFrame::currentWalletModel() const
{
    WalletView* wallet_view = currentWalletView();
    return wallet_view ? wallet_view->getWalletModel() : nullptr;
}
<commit_msg>gui: Load Base64 PSBT string from file<commit_after>// Copyright (c) 2011-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <qt/walletframe.h>

#include <fs.h>
#include <node/ui_interface.h>
#include <psbt.h>
#include <qt/guiutil.h>
#include <qt/overviewpage.h>
#include <qt/psbtoperationsdialog.h>
#include <qt/walletmodel.h>
#include <qt/walletview.h>
#include <util/system.h>

#include <cassert>
#include <fstream>
#include <string>

#include <QApplication>
#include <QClipboard>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>

WalletFrame::WalletFrame(const PlatformStyle* _platformStyle, QWidget* parent)
    : QFrame(parent),
      platformStyle(_platformStyle),
      m_size_hint(OverviewPage{platformStyle, nullptr}.sizeHint())
{
    // Leave HBox hook for adding a list view later
    QHBoxLayout *walletFrameLayout = new QHBoxLayout(this);
    setContentsMargins(0,0,0,0);
    walletStack = new QStackedWidget(this);
    walletFrameLayout->setContentsMargins(0,0,0,0);
    walletFrameLayout->addWidget(walletStack);

    // hbox for no wallet
    QGroupBox* no_wallet_group = new QGroupBox(walletStack);
    QVBoxLayout* no_wallet_layout = new QVBoxLayout(no_wallet_group);

    QLabel *noWallet = new QLabel(tr("No wallet has been loaded.\nGo to File > Open Wallet to load a wallet.\n- OR -"));
    noWallet->setAlignment(Qt::AlignCenter);
    no_wallet_layout->addWidget(noWallet, 0, Qt::AlignHCenter | Qt::AlignBottom);

    // A button for create wallet dialog
    QPushButton* create_wallet_button = new QPushButton(tr("Create a new wallet"), walletStack);
    connect(create_wallet_button, &QPushButton::clicked, this, &WalletFrame::createWalletButtonClicked);
    no_wallet_layout->addWidget(create_wallet_button, 0, Qt::AlignHCenter | Qt::AlignTop);
    no_wallet_group->setLayout(no_wallet_layout);

    walletStack->addWidget(no_wallet_group);
}

WalletFrame::~WalletFrame()
{
}

void WalletFrame::setClientModel(ClientModel *_clientModel)
{
    this->clientModel = _clientModel;

    for (auto i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i) {
        i.value()->setClientModel(_clientModel);
    }
}

bool WalletFrame::addView(WalletView* walletView)
{
    if (!clientModel) return false;

    if (mapWalletViews.count(walletView->getWalletModel()) > 0) return false;

    walletView->setClientModel(clientModel);
    walletView->showOutOfSyncWarning(bOutOfSync);

    WalletView* current_wallet_view = currentWalletView();
    if (current_wallet_view) {
        walletView->setCurrentIndex(current_wallet_view->currentIndex());
    } else {
        walletView->gotoOverviewPage();
    }

    walletStack->addWidget(walletView);
    mapWalletViews[walletView->getWalletModel()] = walletView;

    return true;
}

void WalletFrame::setCurrentWallet(WalletModel* wallet_model)
{
    if (mapWalletViews.count(wallet_model) == 0) return;

    // Stop the effect of hidden widgets on the size hint of the shown one in QStackedWidget.
    WalletView* view_about_to_hide = currentWalletView();
    if (view_about_to_hide) {
        QSizePolicy sp = view_about_to_hide->sizePolicy();
        sp.setHorizontalPolicy(QSizePolicy::Ignored);
        view_about_to_hide->setSizePolicy(sp);
    }

    WalletView *walletView = mapWalletViews.value(wallet_model);
    assert(walletView);

    // Set or restore the default QSizePolicy which could be set to QSizePolicy::Ignored previously.
    QSizePolicy sp = walletView->sizePolicy();
    sp.setHorizontalPolicy(QSizePolicy::Preferred);
    walletView->setSizePolicy(sp);
    walletView->updateGeometry();

    walletStack->setCurrentWidget(walletView);

    Q_EMIT currentWalletSet();
}

void WalletFrame::removeWallet(WalletModel* wallet_model)
{
    if (mapWalletViews.count(wallet_model) == 0) return;

    WalletView *walletView = mapWalletViews.take(wallet_model);
    walletStack->removeWidget(walletView);
    delete walletView;
}

void WalletFrame::removeAllWallets()
{
    QMap<WalletModel*, WalletView*>::const_iterator i;
    for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
        walletStack->removeWidget(i.value());
    mapWalletViews.clear();
}

bool WalletFrame::handlePaymentRequest(const SendCoinsRecipient &recipient)
{
    WalletView *walletView = currentWalletView();
    if (!walletView)
        return false;

    return walletView->handlePaymentRequest(recipient);
}

void WalletFrame::showOutOfSyncWarning(bool fShow)
{
    bOutOfSync = fShow;
    QMap<WalletModel*, WalletView*>::const_iterator i;
    for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
        i.value()->showOutOfSyncWarning(fShow);
}

void WalletFrame::gotoOverviewPage()
{
    QMap<WalletModel*, WalletView*>::const_iterator i;
    for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
        i.value()->gotoOverviewPage();
}

void WalletFrame::gotoHistoryPage()
{
    QMap<WalletModel*, WalletView*>::const_iterator i;
    for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
        i.value()->gotoHistoryPage();
}

void WalletFrame::gotoReceiveCoinsPage()
{
    QMap<WalletModel*, WalletView*>::const_iterator i;
    for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
        i.value()->gotoReceiveCoinsPage();
}

void WalletFrame::gotoSendCoinsPage(QString addr)
{
    QMap<WalletModel*, WalletView*>::const_iterator i;
    for (i = mapWalletViews.constBegin(); i != mapWalletViews.constEnd(); ++i)
        i.value()->gotoSendCoinsPage(addr);
}

void WalletFrame::gotoSignMessageTab(QString addr)
{
    WalletView *walletView = currentWalletView();
    if (walletView)
        walletView->gotoSignMessageTab(addr);
}

void WalletFrame::gotoVerifyMessageTab(QString addr)
{
    WalletView *walletView = currentWalletView();
    if (walletView)
        walletView->gotoVerifyMessageTab(addr);
}

void WalletFrame::gotoLoadPSBT(bool from_clipboard)
{
    std::string data;

    if (from_clipboard) {
        std::string raw = QApplication::clipboard()->text().toStdString();
        bool invalid;
        data = DecodeBase64(raw, &invalid);
        if (invalid) {
            Q_EMIT message(tr("Error"), tr("Unable to decode PSBT from clipboard (invalid base64)"), CClientUIInterface::MSG_ERROR);
            return;
        }
    } else {
        QString filename = GUIUtil::getOpenFileName(this,
            tr("Load Transaction Data"), QString(),
            tr("Partially Signed Transaction (*.psbt)"), nullptr);
        if (filename.isEmpty()) return;
        if (GetFileSize(filename.toLocal8Bit().data(), MAX_FILE_SIZE_PSBT) == MAX_FILE_SIZE_PSBT) {
            Q_EMIT message(tr("Error"), tr("PSBT file must be smaller than 100 MiB"), CClientUIInterface::MSG_ERROR);
            return;
        }
        std::ifstream in{filename.toLocal8Bit().data(), std::ios::binary};
        data = std::string(std::istreambuf_iterator<char>{in}, {});

        // Some psbt files may be base64 strings in the file rather than binary data
        bool invalid = false;
        std::string b64_dec = data;
        b64_dec.erase(b64_dec.find_last_not_of(" \t\n\r\f\v") + 1); // Trim trailing whitespace
        b64_dec = DecodeBase64(b64_dec, &invalid);
        if (!invalid) {
            data = b64_dec;
        }
    }

    std::string error;
    PartiallySignedTransaction psbtx;
    if (!DecodeRawPSBT(psbtx, data, error)) {
        Q_EMIT message(tr("Error"), tr("Unable to decode PSBT") + "\n" + QString::fromStdString(error), CClientUIInterface::MSG_ERROR);
        return;
    }

    auto dlg = new PSBTOperationsDialog(this, currentWalletModel(), clientModel);
    dlg->openWithPSBT(psbtx);
    GUIUtil::ShowModalDialogAsynchronously(dlg);
}

void WalletFrame::encryptWallet()
{
    WalletView *walletView = currentWalletView();
    if (walletView)
        walletView->encryptWallet();
}

void WalletFrame::backupWallet()
{
    WalletView *walletView = currentWalletView();
    if (walletView)
        walletView->backupWallet();
}

void WalletFrame::changePassphrase()
{
    WalletView *walletView = currentWalletView();
    if (walletView)
        walletView->changePassphrase();
}

void WalletFrame::unlockWallet()
{
    WalletView *walletView = currentWalletView();
    if (walletView)
        walletView->unlockWallet();
}

void WalletFrame::usedSendingAddresses()
{
    WalletView *walletView = currentWalletView();
    if (walletView)
        walletView->usedSendingAddresses();
}

void WalletFrame::usedReceivingAddresses()
{
    WalletView *walletView = currentWalletView();
    if (walletView)
        walletView->usedReceivingAddresses();
}

WalletView* WalletFrame::currentWalletView() const
{
    return qobject_cast<WalletView*>(walletStack->currentWidget());
}

WalletModel* WalletFrame::currentWalletModel() const
{
    WalletView* wallet_view = currentWalletView();
    return wallet_view ? wallet_view->getWalletModel() : nullptr;
}
<|endoftext|>


<commit_before>#include "SLAPrint.hpp"
#include "ClipperUtils.hpp"
#include "ExtrusionEntity.hpp"
#include "Fill/Fill.hpp"
#include "Geometry.hpp"
#include "Surface.hpp"
#include <iostream>
#include <complex>
#include <cstdio>

namespace Slic3r {

void
SLAPrint::slice()
{
    TriangleMesh mesh = this->model->mesh();
    mesh.repair();

    // align to origin taking raft into account
    this->bb = mesh.bounding_box();
    if (this->config.raft_layers > 0) {
        this->bb.min.x -= this->config.raft_offset.value;
        this->bb.min.y -= this->config.raft_offset.value;
        this->bb.max.x += this->config.raft_offset.value;
        this->bb.max.y += this->config.raft_offset.value;
    }
    mesh.translate(0, 0, -bb.min.z);
    this->bb.translate(0, 0, -bb.min.z);

    // if we are generating a raft, first_layer_height will not affect mesh slicing
    const float lh       = this->config.layer_height.value;
    const float first_lh = this->config.first_layer_height.value;

    // generate the list of Z coordinates for mesh slicing
    // (we slice each layer at half of its thickness)
    this->layers.clear();
    {
        const float first_slice_lh = (this->config.raft_layers > 0) ? lh : first_lh;
        this->layers.push_back(Layer(first_slice_lh/2, first_slice_lh));
    }
    while (this->layers.back().print_z + lh/2 <= mesh.stl.stats.max.z) {
        this->layers.push_back(Layer(this->layers.back().print_z + lh/2, this->layers.back().print_z + lh));
    }

    // perform slicing and generate layers
    {
        std::vector<float> slice_z;
        for (size_t i = 0; i < this->layers.size(); ++i)
            slice_z.push_back(this->layers[i].slice_z);

        std::vector<ExPolygons> slices;
        TriangleMeshSlicer<Z>(&mesh).slice(slice_z, &slices);

        for (size_t i = 0; i < slices.size(); ++i)
            this->layers[i].slices.expolygons = slices[i];
    }

    // generate infill
    if (this->config.fill_density < 100) {
        std::unique_ptr<Fill> fill(Fill::new_from_type(this->config.fill_pattern.value));
        fill->bounding_box.merge(Point::new_scale(bb.min.x, bb.min.y));
        fill->bounding_box.merge(Point::new_scale(bb.max.x, bb.max.y));
        fill->min_spacing   = this->config.get_abs_value("infill_extrusion_width", this->config.layer_height.value);
        fill->angle         = Geometry::deg2rad(this->config.fill_angle.value);
        fill->density       = this->config.fill_density.value/100;

        parallelize<size_t>(
            0,
            this->layers.size()-1,
            boost::bind(&SLAPrint::_infill_layer, this, _1, fill.get()),
            this->config.threads.value
        );
    }

    // generate support material
    this->sm_pillars.clear();
    ExPolygons overhangs;
    if (this->config.support_material) {
        // flatten and merge all the overhangs
        {
            Polygons pp;
            for (std::vector<Layer>::const_iterator it = this->layers.begin()+1; it != this->layers.end(); ++it)
                pp += diff(it->slices, (it - 1)->slices);
            overhangs = union_ex(pp);
        }

        // generate points following the shape of each island
        Points pillars_pos;
        const coordf_t spacing = scale_(this->config.support_material_spacing);
        const coordf_t radius  = scale_(this->sm_pillars_radius());
        for (ExPolygons::const_iterator it = overhangs.begin(); it != overhangs.end(); ++it) {
            // leave a radius/2 gap between pillars and contour to prevent lateral adhesion
            for (float inset = radius * 1.5;; inset += spacing) {
                // inset according to the configured spacing
                Polygons curr = offset(*it, -inset);
                if (curr.empty()) break;

                // generate points along the contours
                for (Polygons::const_iterator pg = curr.begin(); pg != curr.end(); ++pg) {
                    Points pp = pg->equally_spaced_points(spacing);
                    for (Points::const_iterator p = pp.begin(); p != pp.end(); ++p)
                        pillars_pos.push_back(*p);
                }
            }
        }

        // for each pillar, check which layers it applies to
        for (Points::const_iterator p = pillars_pos.begin(); p != pillars_pos.end(); ++p) {
            SupportPillar pillar(*p);
            bool object_hit = false;

            // check layers top-down
            for (int i = this->layers.size()-1; i >= 0; --i) {
                // check whether point is void in this layer
                if (!this->layers[i].slices.contains(*p)) {
                    // no slice contains the point, so it's in the void
                    if (pillar.top_layer > 0) {
                        // we have a pillar, so extend it
                        pillar.bottom_layer = i + this->config.raft_layers;
                    } else if (object_hit) {
                        // we don't have a pillar and we're below the object, so create one
                        pillar.top_layer = i + this->config.raft_layers;
                    }
                } else {
                    if (pillar.top_layer > 0) {
                        // we have a pillar which is not needed anymore, so store it and initialize a new potential pillar
                        this->sm_pillars.push_back(pillar);
                        pillar = SupportPillar(*p);
                    }
                    object_hit = true;
                }
            }
            if (pillar.top_layer > 0) this->sm_pillars.push_back(pillar);
        }
    }

    // generate a solid raft if requested
    // (do this after support material because we take support material shape into account)
    if (this->config.raft_layers > 0) {
        ExPolygons raft = this->layers.front().slices + overhangs;  // take support material into account
        raft = offset_ex(raft, scale_(this->config.raft_offset));
        for (int i = this->config.raft_layers; i >= 1; --i) {
            this->layers.insert(this->layers.begin(), Layer(0, first_lh + lh * (i-1)));
            this->layers.front().slices = raft;
        }

        // prepend total raft height to all sliced layers
        for (size_t i = this->config.raft_layers; i < this->layers.size(); ++i)
            this->layers[i].print_z += first_lh + lh * (this->config.raft_layers-1);
    }
}

void
SLAPrint::_infill_layer(size_t i, const Fill* _fill)
{
    Layer &layer = this->layers[i];

    const float shell_thickness = this->config.get_abs_value("perimeter_extrusion_width", this->config.layer_height.value);

    // In order to detect what regions of this layer need to be solid,
    // perform an intersection with layers within the requested shell thickness.
    Polygons internal = layer.slices;
    for (size_t j = 0; j < this->layers.size(); ++j) {
        const Layer &other = this->layers[j];
        if (std::abs(other.print_z - layer.print_z) > shell_thickness) continue;

        if (j == 0 || j == this->layers.size()-1) {
            internal.clear();
            break;
        } else if (i != j) {
            internal = intersection(internal, other.slices);
            if (internal.empty()) break;
        }
    }

    // If we have no internal infill, just print the whole layer as a solid slice.
    if (internal.empty()) return;
    layer.solid = false;

    const Polygons infill = offset(layer.slices, -scale_(shell_thickness));

    // Generate solid infill
    layer.solid_infill << diff_ex(infill, internal, true);

    // Generate internal infill
    {
        std::unique_ptr<Fill> fill(_fill->clone());
        fill->layer_id = i;
        fill->z        = layer.print_z;

        ExtrusionPath templ(erInternalInfill);
        templ.width = fill->spacing();
        const ExPolygons internal_ex = intersection_ex(infill, internal);
        for (ExPolygons::const_iterator it = internal_ex.begin(); it != internal_ex.end(); ++it) {
            Polylines polylines = fill->fill_surface(Surface(stInternal, *it));
            layer.infill.append(polylines, templ);
        }
    }

    // Generate perimeter(s).
    layer.perimeters << diff_ex(
        layer.slices,
        offset(layer.slices, -scale_(shell_thickness))
    );
}

void
SLAPrint::write_svg(const std::string &outputfile) const
{
    const Sizef3 size = this->bb.size();
    const double support_material_radius = sm_pillars_radius();

    FILE* f = fopen(outputfile.c_str(), "w");
    fprintf(f,
        "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
        "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n"
        "<svg width=\"%f\" height=\"%f\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:slic3r=\"http://slic3r.org/namespaces/slic3r\" viewport-fill=\"black\">\n"
        "<!-- Generated using Slic3r %s http://slic3r.org/ -->\n"
        , size.x, size.y, SLIC3R_VERSION);

    for (size_t i = 0; i < this->layers.size(); ++i) {
        const Layer &layer = this->layers[i];
        fprintf(f,
            "\t<g id=\"layer%zu\" slic3r:z=\"%0.4f\" slic3r:slice-z=\"%0.4f\" slic3r:layer-height=\"%0.4f\">\n",
            i,
            layer.print_z,
            layer.slice_z,
            layer.print_z - ((i == 0) ? 0. : this->layers[i-1].print_z)
        );

        if (layer.solid) {
            const ExPolygons &slices = layer.slices.expolygons;
            for (ExPolygons::const_iterator it = slices.begin(); it != slices.end(); ++it) {
                std::string pd = this->_SVG_path_d(*it);

                fprintf(f,"\t\t<path d=\"%s\" style=\"fill: %s; stroke: %s; stroke-width: %s; fill-type: evenodd\" slic3r:area=\"%0.4f\" />\n",
                    pd.c_str(), "white", "black", "0", unscale(unscale(it->area()))
                );
            }
        } else {
            // Perimeters.
            for (ExPolygons::const_iterator it = layer.perimeters.expolygons.begin();
                it != layer.perimeters.expolygons.end(); ++it) {
                std::string pd = this->_SVG_path_d(*it);

                fprintf(f,"\t\t<path d=\"%s\" style=\"fill: %s; stroke: %s; stroke-width: %s; fill-type: evenodd\" slic3r:type=\"perimeter\" />\n",
                    pd.c_str(), "white", "black", "0"
                );
            }

            // Solid infill.
            for (ExPolygons::const_iterator it = layer.solid_infill.expolygons.begin();
                it != layer.solid_infill.expolygons.end(); ++it) {
                std::string pd = this->_SVG_path_d(*it);

                fprintf(f,"\t\t<path d=\"%s\" style=\"fill: %s; stroke: %s; stroke-width: %s; fill-type: evenodd\" slic3r:type=\"infill\" />\n",
                    pd.c_str(), "white", "black", "0"
                );
            }

            // Internal infill.
            for (ExtrusionEntitiesPtr::const_iterator it = layer.infill.entities.begin();
                it != layer.infill.entities.end(); ++it) {
                const ExPolygons infill = union_ex((*it)->grow());

                for (ExPolygons::const_iterator e = infill.begin(); e != infill.end(); ++e) {
                    std::string pd = this->_SVG_path_d(*e);

                    fprintf(f,"\t\t<path d=\"%s\" style=\"fill: %s; stroke: %s; stroke-width: %s; fill-type: evenodd\" slic3r:type=\"infill\" />\n",
                        pd.c_str(), "white", "black", "0"
                    );
                }
            }
        }

        // don't print support material in raft layers
        if (i >= (size_t)this->config.raft_layers) {
            // look for support material pillars belonging to this layer
            for (std::vector<SupportPillar>::const_iterator it = this->sm_pillars.begin(); it != this->sm_pillars.end(); ++it) {
                if (!(it->top_layer >= i && it->bottom_layer <= i)) continue;

                // generate a conic tip
                float radius = fminf(
                    support_material_radius,
                    (it->top_layer - i + 1) * this->config.layer_height.value
                );

                fprintf(f,"\t\t<circle cx=\"%f\" cy=\"%f\" r=\"%f\" stroke-width=\"0\" fill=\"white\" slic3r:type=\"support\" />\n",
                    unscale(it->x) - this->bb.min.x,
                    size.y - (unscale(it->y) - this->bb.min.y),
                    radius
                );
            }
        }

        fprintf(f,"\t</g>\n");
    }
    fprintf(f,"</svg>\n");
}

coordf_t
SLAPrint::sm_pillars_radius() const
{
    coordf_t radius = this->config.support_material_extrusion_width.get_abs_value(this->config.support_material_spacing)/2;
    if (radius == 0) radius = this->config.support_material_spacing / 3; // auto
    return radius;
}

std::string
SLAPrint::_SVG_path_d(const Polygon &polygon) const
{
    const Sizef3 size = this->bb.size();
    std::ostringstream d;
    d << "M ";
    for (Points::const_iterator p = polygon.points.begin(); p != polygon.points.end(); ++p) {
        d << unscale(p->x) - this->bb.min.x << " ";
        d << size.y - (unscale(p->y) - this->bb.min.y) << " ";  // mirror Y coordinates as SVG uses downwards Y
    }
    d << "z";
    return d.str();
}

std::string
SLAPrint::_SVG_path_d(const ExPolygon &expolygon) const
{
    std::string pd;
    const Polygons pp = expolygon;
    for (Polygons::const_iterator mp = pp.begin(); mp != pp.end(); ++mp)
        pd += this->_SVG_path_d(*mp) + " ";
    return pd;
}

}
<commit_msg>Hotfix: Set minimum spacing to 0.3 if the provided configuration option is 0. Avoids a crash with infill density < 100% on SLA prints.<commit_after>#include "SLAPrint.hpp"
#include "ClipperUtils.hpp"
#include "ExtrusionEntity.hpp"
#include "Fill/Fill.hpp"
#include "Geometry.hpp"
#include "Surface.hpp"
#include <iostream>
#include <complex>
#include <cstdio>

namespace Slic3r {

void
SLAPrint::slice()
{
    TriangleMesh mesh = this->model->mesh();
    mesh.repair();

    // align to origin taking raft into account
    this->bb = mesh.bounding_box();
    if (this->config.raft_layers > 0) {
        this->bb.min.x -= this->config.raft_offset.value;
        this->bb.min.y -= this->config.raft_offset.value;
        this->bb.max.x += this->config.raft_offset.value;
        this->bb.max.y += this->config.raft_offset.value;
    }
    mesh.translate(0, 0, -bb.min.z);
    this->bb.translate(0, 0, -bb.min.z);

    // if we are generating a raft, first_layer_height will not affect mesh slicing
    const float lh       = this->config.layer_height.value;
    const float first_lh = this->config.first_layer_height.value;

    // generate the list of Z coordinates for mesh slicing
    // (we slice each layer at half of its thickness)
    this->layers.clear();
    {
        const float first_slice_lh = (this->config.raft_layers > 0) ? lh : first_lh;
        this->layers.push_back(Layer(first_slice_lh/2, first_slice_lh));
    }
    while (this->layers.back().print_z + lh/2 <= mesh.stl.stats.max.z) {
        this->layers.push_back(Layer(this->layers.back().print_z + lh/2, this->layers.back().print_z + lh));
    }

    // perform slicing and generate layers
    {
        std::vector<float> slice_z;
        for (size_t i = 0; i < this->layers.size(); ++i)
            slice_z.push_back(this->layers[i].slice_z);

        std::vector<ExPolygons> slices;
        TriangleMeshSlicer<Z>(&mesh).slice(slice_z, &slices);

        for (size_t i = 0; i < slices.size(); ++i)
            this->layers[i].slices.expolygons = slices[i];
    }
    this->config.get_abs_value("infill_extrusion_width", this->config.layer_height.value);

    // generate infill
    if (this->config.fill_density < 100) {
        std::unique_ptr<Fill> fill(Fill::new_from_type(this->config.fill_pattern.value));
        fill->bounding_box.merge(Point::new_scale(bb.min.x, bb.min.y));
        fill->bounding_box.merge(Point::new_scale(bb.max.x, bb.max.y));
        fill->min_spacing   = ( this->config.get_abs_value("infill_extrusion_width", this->config.layer_height.value) > 0 ? this->config.get_abs_value("infill_extrusion_width", this->config.layer_height.value) : 0.3);
        fill->angle         = Geometry::deg2rad(this->config.fill_angle.value);
        fill->density       = this->config.fill_density.value/100;

        parallelize<size_t>(
            0,
            this->layers.size()-1,
            boost::bind(&SLAPrint::_infill_layer, this, _1, fill.get()),
            this->config.threads.value
        );
    }

    // generate support material
    this->sm_pillars.clear();
    ExPolygons overhangs;
    if (this->config.support_material) {
        // flatten and merge all the overhangs
        {
            Polygons pp;
            for (std::vector<Layer>::const_iterator it = this->layers.begin()+1; it != this->layers.end(); ++it)
                pp += diff(it->slices, (it - 1)->slices);
            overhangs = union_ex(pp);
        }

        // generate points following the shape of each island
        Points pillars_pos;
        const coordf_t spacing = scale_(this->config.support_material_spacing);
        const coordf_t radius  = scale_(this->sm_pillars_radius());
        for (ExPolygons::const_iterator it = overhangs.begin(); it != overhangs.end(); ++it) {
            // leave a radius/2 gap between pillars and contour to prevent lateral adhesion
            for (float inset = radius * 1.5;; inset += spacing) {
                // inset according to the configured spacing
                Polygons curr = offset(*it, -inset);
                if (curr.empty()) break;

                // generate points along the contours
                for (Polygons::const_iterator pg = curr.begin(); pg != curr.end(); ++pg) {
                    Points pp = pg->equally_spaced_points(spacing);
                    for (Points::const_iterator p = pp.begin(); p != pp.end(); ++p)
                        pillars_pos.push_back(*p);
                }
            }
        }

        // for each pillar, check which layers it applies to
        for (Points::const_iterator p = pillars_pos.begin(); p != pillars_pos.end(); ++p) {
            SupportPillar pillar(*p);
            bool object_hit = false;

            // check layers top-down
            for (int i = this->layers.size()-1; i >= 0; --i) {
                // check whether point is void in this layer
                if (!this->layers[i].slices.contains(*p)) {
                    // no slice contains the point, so it's in the void
                    if (pillar.top_layer > 0) {
                        // we have a pillar, so extend it
                        pillar.bottom_layer = i + this->config.raft_layers;
                    } else if (object_hit) {
                        // we don't have a pillar and we're below the object, so create one
                        pillar.top_layer = i + this->config.raft_layers;
                    }
                } else {
                    if (pillar.top_layer > 0) {
                        // we have a pillar which is not needed anymore, so store it and initialize a new potential pillar
                        this->sm_pillars.push_back(pillar);
                        pillar = SupportPillar(*p);
                    }
                    object_hit = true;
                }
            }
            if (pillar.top_layer > 0) this->sm_pillars.push_back(pillar);
        }
    }

    // generate a solid raft if requested
    // (do this after support material because we take support material shape into account)
    if (this->config.raft_layers > 0) {
        ExPolygons raft = this->layers.front().slices + overhangs;  // take support material into account
        raft = offset_ex(raft, scale_(this->config.raft_offset));
        for (int i = this->config.raft_layers; i >= 1; --i) {
            this->layers.insert(this->layers.begin(), Layer(0, first_lh + lh * (i-1)));
            this->layers.front().slices = raft;
        }

        // prepend total raft height to all sliced layers
        for (size_t i = this->config.raft_layers; i < this->layers.size(); ++i)
            this->layers[i].print_z += first_lh + lh * (this->config.raft_layers-1);
    }
}

void
SLAPrint::_infill_layer(size_t i, const Fill* _fill)
{
    Layer &layer = this->layers[i];

    const float shell_thickness = this->config.get_abs_value("perimeter_extrusion_width", this->config.layer_height.value);

    // In order to detect what regions of this layer need to be solid,
    // perform an intersection with layers within the requested shell thickness.
    Polygons internal = layer.slices;
    for (size_t j = 0; j < this->layers.size(); ++j) {
        const Layer &other = this->layers[j];
        if (std::abs(other.print_z - layer.print_z) > shell_thickness) continue;

        if (j == 0 || j == this->layers.size()-1) {
            internal.clear();
            break;
        } else if (i != j) {
            internal = intersection(internal, other.slices);
            if (internal.empty()) break;
        }
    }

    // If we have no internal infill, just print the whole layer as a solid slice.
    if (internal.empty()) return;
    layer.solid = false;

    const Polygons infill = offset(layer.slices, -scale_(shell_thickness));

    // Generate solid infill
    layer.solid_infill << diff_ex(infill, internal, true);

    // Generate internal infill
    {
        std::unique_ptr<Fill> fill(_fill->clone());
        fill->layer_id = i;
        fill->z        = layer.print_z;

        ExtrusionPath templ(erInternalInfill);
        templ.width = fill->spacing();
        const ExPolygons internal_ex = intersection_ex(infill, internal);
        for (ExPolygons::const_iterator it = internal_ex.begin(); it != internal_ex.end(); ++it) {
            Polylines polylines = fill->fill_surface(Surface(stInternal, *it));
            layer.infill.append(polylines, templ);
        }
    }

    // Generate perimeter(s).
    layer.perimeters << diff_ex(
        layer.slices,
        offset(layer.slices, -scale_(shell_thickness))
    );
}

void
SLAPrint::write_svg(const std::string &outputfile) const
{
    const Sizef3 size = this->bb.size();
    const double support_material_radius = sm_pillars_radius();

    FILE* f = fopen(outputfile.c_str(), "w");
    fprintf(f,
        "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
        "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n"
        "<svg width=\"%f\" height=\"%f\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:slic3r=\"http://slic3r.org/namespaces/slic3r\" viewport-fill=\"black\">\n"
        "<!-- Generated using Slic3r %s http://slic3r.org/ -->\n"
        , size.x, size.y, SLIC3R_VERSION);

    for (size_t i = 0; i < this->layers.size(); ++i) {
        const Layer &layer = this->layers[i];
        fprintf(f,
            "\t<g id=\"layer%zu\" slic3r:z=\"%0.4f\" slic3r:slice-z=\"%0.4f\" slic3r:layer-height=\"%0.4f\">\n",
            i,
            layer.print_z,
            layer.slice_z,
            layer.print_z - ((i == 0) ? 0. : this->layers[i-1].print_z)
        );

        if (layer.solid) {
            const ExPolygons &slices = layer.slices.expolygons;
            for (ExPolygons::const_iterator it = slices.begin(); it != slices.end(); ++it) {
                std::string pd = this->_SVG_path_d(*it);

                fprintf(f,"\t\t<path d=\"%s\" style=\"fill: %s; stroke: %s; stroke-width: %s; fill-type: evenodd\" slic3r:area=\"%0.4f\" />\n",
                    pd.c_str(), "white", "black", "0", unscale(unscale(it->area()))
                );
            }
        } else {
            // Perimeters.
            for (ExPolygons::const_iterator it = layer.perimeters.expolygons.begin();
                it != layer.perimeters.expolygons.end(); ++it) {
                std::string pd = this->_SVG_path_d(*it);

                fprintf(f,"\t\t<path d=\"%s\" style=\"fill: %s; stroke: %s; stroke-width: %s; fill-type: evenodd\" slic3r:type=\"perimeter\" />\n",
                    pd.c_str(), "white", "black", "0"
                );
            }

            // Solid infill.
            for (ExPolygons::const_iterator it = layer.solid_infill.expolygons.begin();
                it != layer.solid_infill.expolygons.end(); ++it) {
                std::string pd = this->_SVG_path_d(*it);

                fprintf(f,"\t\t<path d=\"%s\" style=\"fill: %s; stroke: %s; stroke-width: %s; fill-type: evenodd\" slic3r:type=\"infill\" />\n",
                    pd.c_str(), "white", "black", "0"
                );
            }

            // Internal infill.
            for (ExtrusionEntitiesPtr::const_iterator it = layer.infill.entities.begin();
                it != layer.infill.entities.end(); ++it) {
                const ExPolygons infill = union_ex((*it)->grow());

                for (ExPolygons::const_iterator e = infill.begin(); e != infill.end(); ++e) {
                    std::string pd = this->_SVG_path_d(*e);

                    fprintf(f,"\t\t<path d=\"%s\" style=\"fill: %s; stroke: %s; stroke-width: %s; fill-type: evenodd\" slic3r:type=\"infill\" />\n",
                        pd.c_str(), "white", "black", "0"
                    );
                }
            }
        }

        // don't print support material in raft layers
        if (i >= (size_t)this->config.raft_layers) {
            // look for support material pillars belonging to this layer
            for (std::vector<SupportPillar>::const_iterator it = this->sm_pillars.begin(); it != this->sm_pillars.end(); ++it) {
                if (!(it->top_layer >= i && it->bottom_layer <= i)) continue;

                // generate a conic tip
                float radius = fminf(
                    support_material_radius,
                    (it->top_layer - i + 1) * this->config.layer_height.value
                );

                fprintf(f,"\t\t<circle cx=\"%f\" cy=\"%f\" r=\"%f\" stroke-width=\"0\" fill=\"white\" slic3r:type=\"support\" />\n",
                    unscale(it->x) - this->bb.min.x,
                    size.y - (unscale(it->y) - this->bb.min.y),
                    radius
                );
            }
        }

        fprintf(f,"\t</g>\n");
    }
    fprintf(f,"</svg>\n");
}

coordf_t
SLAPrint::sm_pillars_radius() const
{
    coordf_t radius = this->config.support_material_extrusion_width.get_abs_value(this->config.support_material_spacing)/2;
    if (radius == 0) radius = this->config.support_material_spacing / 3; // auto
    return radius;
}

std::string
SLAPrint::_SVG_path_d(const Polygon &polygon) const
{
    const Sizef3 size = this->bb.size();
    std::ostringstream d;
    d << "M ";
    for (Points::const_iterator p = polygon.points.begin(); p != polygon.points.end(); ++p) {
        d << unscale(p->x) - this->bb.min.x << " ";
        d << size.y - (unscale(p->y) - this->bb.min.y) << " ";  // mirror Y coordinates as SVG uses downwards Y
    }
    d << "z";
    return d.str();
}

std::string
SLAPrint::_SVG_path_d(const ExPolygon &expolygon) const
{
    std::string pd;
    const Polygons pp = expolygon;
    for (Polygons::const_iterator mp = pp.begin(); mp != pp.end(); ++mp)
        pd += this->_SVG_path_d(*mp) + " ";
    return pd;
}

}
<|endoftext|>


<commit_before>/**
 * @author: Jeff Thompson
 * See COPYING for copyright and distribution information.
 */

#ifndef NDN_KEY_HPP
#define NDN_KEY_HPP

#include <vector>
#include "c/key.h"
#include "Name.hpp"

namespace ndn {

class KeyLocator {
public:
  KeyLocator()
  : type_((ndn_KeyLocatorType)-1), keyNameType_((ndn_KeyNameType)-1)
  {
  }

  /**
   * Set the keyLocatorStruct to point to the values in this key locator, without copying any memory.
   * WARNING: The resulting pointers in keyLocatorStruct are invalid after a further use of this object which could reallocate memory.
   * @param keyLocatorStruct a C ndn_KeyLocator struct where the name components array is already allocated.
   */
  void get(struct ndn_KeyLocator &keyLocatorStruct) const;

  /**
   * Clear this key locator, and set the values by copying from the ndn_KeyLocator struct.
   * @param keyLocatorStruct a C ndn_KeyLocator struct
   */
  void set(const struct ndn_KeyLocator &keyLocatorStruct);

  ndn_KeyLocatorType getType() const { return type_; }

  const std::vector<unsigned char> &getKeyData() const { return keyData_; }

  const Name &getKeyName() const { return keyName_; }
  Name &getKeyName() { return keyName_; }

  ndn_KeyNameType getKeyNameType() const { return keyNameType_; }

  void setType(ndn_KeyLocatorType type) { type_ = type; }

  void setKeyData(const std::vector<unsigned char> &keyData) { keyData_ = keyData; }
  void setKeyData(const unsigned char *keyData, unsigned int keyDataLength)
  {
    setVector(keyData_, keyData, keyDataLength);
  }

  /**
   * @deprecated Use getKeyData().
   */
  const std::vector<unsigned char> &getKeyOrCertificate() const { return getKeyData(); }

  /**
   * @deprecated Use setKeyData.
   */
  void setKeyOrCertificate(const std::vector<unsigned char> &keyData) { setKeyData(keyData); }

  /**
   * @deprecated Use setKeyData.
   */
  void setKeyOrCertificate(const unsigned char *keyData, unsigned int keyDataLength) { setKeyData(keyData, keyDataLength); }

  void setKeyNameType(ndn_KeyNameType keyNameType) { keyNameType_ = keyNameType; }

private:
  ndn_KeyLocatorType type_; /**< -1 for none */
  std::vector<unsigned char> keyData_; /**< A pointer to a pre-allocated buffer for the key data as follows:
    *   If type_ is ndn_KeyLocatorType_KEY, the key data.
    *   If type_ is ndn_KeyLocatorType_CERTIFICATE, the certificate data.
    *   If type_ is ndn_KeyLocatorType_KEYNAME and keyNameType_ is ndn_KeyNameType_PUBLISHER_PUBLIC_KEY_DIGEST, the publisher public key digest.
    *   If type_ is ndn_KeyLocatorType_KEYNAME and keyNameType_ is ndn_KeyNameType_PUBLISHER_CERTIFICATE_DIGEST, the publisher certificate digest.
    *   If type_ is ndn_KeyLocatorType_KEYNAME and keyNameType_ is ndn_KeyNameType_PUBLISHER_ISSUER_KEY_DIGEST, the publisher issuer key digest.
    *   If type_ is ndn_KeyLocatorType_KEYNAME and keyNameType_ is ndn_KeyNameType_PUBLISHER_ISSUER_CERTIFICATE_DIGEST, the publisher issuer certificate digest.
                                */
  Name keyName_;                /**< The key name (only used if type_ is ndn_KeyLocatorType_KEYNAME.) */
  ndn_KeyNameType keyNameType_; /**< The type of data for keyName_ (only used if type_ is ndn_KeyLocatorType_KEYNAME.) */
};

}

#endif
<commit_msg>Fix typo for inlcude name.hpp<commit_after>/**
 * @author: Jeff Thompson
 * See COPYING for copyright and distribution information.
 */

#ifndef NDN_KEY_HPP
#define NDN_KEY_HPP

#include <vector>
#include "c/key.h"
#include "name.hpp"

namespace ndn {

class KeyLocator {
public:
  KeyLocator()
  : type_((ndn_KeyLocatorType)-1), keyNameType_((ndn_KeyNameType)-1)
  {
  }

  /**
   * Set the keyLocatorStruct to point to the values in this key locator, without copying any memory.
   * WARNING: The resulting pointers in keyLocatorStruct are invalid after a further use of this object which could reallocate memory.
   * @param keyLocatorStruct a C ndn_KeyLocator struct where the name components array is already allocated.
   */
  void get(struct ndn_KeyLocator &keyLocatorStruct) const;

  /**
   * Clear this key locator, and set the values by copying from the ndn_KeyLocator struct.
   * @param keyLocatorStruct a C ndn_KeyLocator struct
   */
  void set(const struct ndn_KeyLocator &keyLocatorStruct);

  ndn_KeyLocatorType getType() const { return type_; }

  const std::vector<unsigned char> &getKeyData() const { return keyData_; }

  const Name &getKeyName() const { return keyName_; }
  Name &getKeyName() { return keyName_; }

  ndn_KeyNameType getKeyNameType() const { return keyNameType_; }

  void setType(ndn_KeyLocatorType type) { type_ = type; }

  void setKeyData(const std::vector<unsigned char> &keyData) { keyData_ = keyData; }
  void setKeyData(const unsigned char *keyData, unsigned int keyDataLength)
  {
    setVector(keyData_, keyData, keyDataLength);
  }

  /**
   * @deprecated Use getKeyData().
   */
  const std::vector<unsigned char> &getKeyOrCertificate() const { return getKeyData(); }

  /**
   * @deprecated Use setKeyData.
   */
  void setKeyOrCertificate(const std::vector<unsigned char> &keyData) { setKeyData(keyData); }

  /**
   * @deprecated Use setKeyData.
   */
  void setKeyOrCertificate(const unsigned char *keyData, unsigned int keyDataLength) { setKeyData(keyData, keyDataLength); }

  void setKeyNameType(ndn_KeyNameType keyNameType) { keyNameType_ = keyNameType; }

private:
  ndn_KeyLocatorType type_; /**< -1 for none */
  std::vector<unsigned char> keyData_; /**< A pointer to a pre-allocated buffer for the key data as follows:
    *   If type_ is ndn_KeyLocatorType_KEY, the key data.
    *   If type_ is ndn_KeyLocatorType_CERTIFICATE, the certificate data.
    *   If type_ is ndn_KeyLocatorType_KEYNAME and keyNameType_ is ndn_KeyNameType_PUBLISHER_PUBLIC_KEY_DIGEST, the publisher public key digest.
    *   If type_ is ndn_KeyLocatorType_KEYNAME and keyNameType_ is ndn_KeyNameType_PUBLISHER_CERTIFICATE_DIGEST, the publisher certificate digest.
    *   If type_ is ndn_KeyLocatorType_KEYNAME and keyNameType_ is ndn_KeyNameType_PUBLISHER_ISSUER_KEY_DIGEST, the publisher issuer key digest.
    *   If type_ is ndn_KeyLocatorType_KEYNAME and keyNameType_ is ndn_KeyNameType_PUBLISHER_ISSUER_CERTIFICATE_DIGEST, the publisher issuer certificate digest.
                                */
  Name keyName_;                /**< The key name (only used if type_ is ndn_KeyLocatorType_KEYNAME.) */
  ndn_KeyNameType keyNameType_; /**< The type of data for keyName_ (only used if type_ is ndn_KeyLocatorType_KEYNAME.) */
};

}

#endif
<|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org

Copyright (c) 2000-2009 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/

#include "OgreGLSLESExtSupport.h"
#include "OgreLogManager.h"

namespace Ogre
{
    //-----------------------------------------------------------------------------
	String logObjectInfo(const String& msg, const GLuint obj)
	{
		String logMessage = msg;

		if (obj > 0)
		{
			GLint infologLength = 0;

            if(glIsShader(obj))
            {
                glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &infologLength);
                GL_CHECK_ERROR
            }
            else if(glIsProgram(obj))
            {
                glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &infologLength);
                GL_CHECK_ERROR
            }

			if (infologLength > 0)
			{
				GLint charsWritten  = 0;

				//GLchar * infoLog = OGRE_NEW GLchar[infologLength];
				char * infoLog = new char [infologLength];
				infoLog[0] = 0;

                if(glIsShader(obj))
                {
                    glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
                    GL_CHECK_ERROR
                }
                else if(glIsProgram(obj))
                {
                    glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
                    GL_CHECK_ERROR
                }
				if (strlen(infoLog) > 0)
				{
					logMessage += "\n" + String(infoLog);
				}

                LogManager::getSingleton().logMessage(logMessage);

				OGRE_DELETE [] infoLog;
			}
		}

		return logMessage;
	}

} // namespace Ogre
<commit_msg>GLES2 render system: removed end of line chars from the compile result to log function -  - so there will be less empty lines in the log.<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org

Copyright (c) 2000-2009 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/

#include "OgreGLSLESExtSupport.h"
#include "OgreLogManager.h"

namespace Ogre
{
    //-----------------------------------------------------------------------------
	String logObjectInfo(const String& msg, const GLuint obj)
	{
		String logMessage = msg;

		if (obj > 0)
		{
			GLint infologLength = 0;

            if(glIsShader(obj))
            {
                glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &infologLength);
                GL_CHECK_ERROR
            }
            else if(glIsProgram(obj))
            {
                glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &infologLength);
                GL_CHECK_ERROR
            }

			if (infologLength > 1)
			{
				GLint charsWritten  = 0;

				//GLchar * infoLog = OGRE_NEW GLchar[infologLength];
				char * infoLog = new char [infologLength];
				infoLog[0] = 0;

                if(glIsShader(obj))
                {
                    glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
                    GL_CHECK_ERROR
                }
                else if(glIsProgram(obj))
                {
                    glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
                    GL_CHECK_ERROR
                }
				if (strlen(infoLog) > 0)
				{
					logMessage += "\n" + String(infoLog);
				}

				OGRE_DELETE [] infoLog;

				if (logMessage.size() > 0)
				{
					// remove ends of line in the end - so there will be no empty lines in the log.
					while( logMessage[logMessage.size() - 1] == '\n' )
					{
						logMessage.erase(logMessage.size() - 1, 1);
					}
					LogManager::getSingleton().logMessage(logMessage);
				}
			}
		}

		return logMessage;
	}

} // namespace Ogre
<|endoftext|>


<commit_before>// Copyright 2014 The Crashpad Authors. All rights reserved.
//
// 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 "util/mach/mach_message_server.h"

#include <limits>

#include "base/mac/mach_logging.h"
#include "base/mac/scoped_mach_vm.h"
#include "util/misc/clock.h"

namespace crashpad {

namespace {

const int kNanosecondsPerMillisecond = 1E6;

// TimerRunning determines whether |deadline| has passed. If |deadline| is in
// the future, |*remaining_ms| is set to the number of milliseconds remaining,
// which will always be a positive value, and this function returns true. If
// |deadline| is zero (indicating that no timer is in effect), |*remaining_ms|
// is set to zero and this function returns true. Otherwise, this function
// returns false. |deadline| is specified on the same time base as is returned
// by ClockMonotonicNanoseconds().
bool TimerRunning(uint64_t deadline, mach_msg_timeout_t* remaining_ms) {
  if (!deadline) {
    *remaining_ms = MACH_MSG_TIMEOUT_NONE;
    return true;
  }

  uint64_t now = ClockMonotonicNanoseconds();

  if (now >= deadline) {
    return false;
  }

  uint64_t remaining = deadline - now;

  // Round to the nearest millisecond, taking care not to overflow.
  const int kHalfMillisecondInNanoseconds = kNanosecondsPerMillisecond / 2;
  mach_msg_timeout_t remaining_mach;
  if (remaining <=
      std::numeric_limits<uint64_t>::max() - kHalfMillisecondInNanoseconds) {
    remaining_mach = (remaining + kHalfMillisecondInNanoseconds) /
                     kNanosecondsPerMillisecond;
  } else {
    remaining_mach = remaining / kNanosecondsPerMillisecond;
  }

  if (remaining_mach == MACH_MSG_TIMEOUT_NONE) {
    return false;
  }

  *remaining_ms = remaining_mach;
  return true;
}

}  // namespace

// This implementation is based on 10.9.4
// xnu-2422.110.17/libsyscall/mach/mach_msg.c mach_msg_server_once(), but
// adapted to local style using scopers, replacing the server callback function
// and |max_size| parameter with a C++ interface, and with the addition of the
// the |persistent| parameter allowing this function to serve as a stand-in for
// mach_msg_server(), the |nonblocking| parameter to control blocking directly,
// and the |timeout_ms| parameter allowing this function to not block
// indefinitely.
//
// static
mach_msg_return_t MachMessageServer::Run(Interface* interface,
                                         mach_port_t receive_port,
                                         mach_msg_options_t options,
                                         Persistent persistent,
                                         Nonblocking nonblocking,
                                         ReceiveLarge receive_large,
                                         mach_msg_timeout_t timeout_ms) {
  options &= ~(MACH_RCV_MSG | MACH_SEND_MSG);

  mach_msg_options_t timeout_options = MACH_RCV_TIMEOUT | MACH_SEND_TIMEOUT |
                                       MACH_RCV_INTERRUPT | MACH_SEND_INTERRUPT;

  uint64_t deadline;
  if (nonblocking == kNonblocking) {
    options |= timeout_options;
    deadline = 0;
  } else if (timeout_ms != MACH_MSG_TIMEOUT_NONE) {
    options |= timeout_options;
    deadline = ClockMonotonicNanoseconds() +
               implicit_cast<uint64_t>(timeout_ms) * kNanosecondsPerMillisecond;
  } else {
    options &= ~timeout_options;
    deadline = 0;
  }

  if (receive_large == kReceiveLargeResize) {
    options |= MACH_RCV_LARGE;
  } else {
    options &= ~MACH_RCV_LARGE;
  }

  mach_msg_size_t trailer_alloc = REQUESTED_TRAILER_SIZE(options);
  mach_msg_size_t max_request_size = interface->MachMessageServerRequestSize();
  mach_msg_size_t request_alloc =
      round_page(round_msg(max_request_size) + trailer_alloc);

  // mach_msg_server() and mach_msg_server_once() invert this condition, but
  // their interpretation is incorrect. When it is desirable to retry a receive
  // attempt that returns MACH_RCV_TOO_LARGE with a larger receive buffer, it is
  // also desirable to use the full receive buffer rounded up to a page size for
  // the initial receive attempt. On the other hand, when this behavior is not
  // requested, there is no reason to attempt receiving messages any larger than
  // expected.
  mach_msg_size_t request_size =
      (receive_large == kReceiveLargeResize)
          ? round_msg(max_request_size) + trailer_alloc
          : request_alloc;

  mach_msg_size_t max_reply_size = interface->MachMessageServerReplySize();

  // mach_msg_server() and mach_msg_server_once() would consider whether
  // |options| contains MACH_SEND_TRAILER and include MAX_TRAILER_SIZE in this
  // computation if it does, but that option is ineffective on OS X.
  mach_msg_size_t reply_alloc = round_page(max_reply_size);

  kern_return_t kr;

  do {
    mach_msg_size_t this_request_alloc = request_alloc;
    mach_msg_size_t this_request_size = request_size;

    base::mac::ScopedMachVM request_scoper;
    mach_msg_header_t* request_header = nullptr;

    while (!request_scoper.address()) {
      vm_address_t request_addr;
      kr = vm_allocate(mach_task_self(),
                       &request_addr,
                       this_request_alloc,
                       VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_MACH_MSG));
      if (kr != KERN_SUCCESS) {
        return kr;
      }
      base::mac::ScopedMachVM trial_request_scoper(request_addr,
                                                   this_request_alloc);
      request_header = reinterpret_cast<mach_msg_header_t*>(request_addr);

      bool run_mach_msg_receive = false;
      do {
        // If |options| contains MACH_RCV_INTERRUPT, retry mach_msg() in a loop
        // when it returns MACH_RCV_INTERRUPTED to recompute |remaining_ms|
        // rather than allowing mach_msg() to retry using the original timeout
        // value. See 10.9.4 xnu-2422.110.17/libsyscall/mach/mach_msg.c
        // mach_msg().
        mach_msg_timeout_t remaining_ms;
        if (!TimerRunning(deadline, &remaining_ms)) {
          return MACH_RCV_TIMED_OUT;
        }

        kr = mach_msg(request_header,
                      options | MACH_RCV_MSG,
                      0,
                      this_request_size,
                      receive_port,
                      remaining_ms,
                      MACH_PORT_NULL);

        if (kr == MACH_RCV_TOO_LARGE && receive_large == kReceiveLargeIgnore) {
          MACH_LOG(WARNING, kr) << "mach_msg: ignoring large message";
          run_mach_msg_receive = true;
        } else if (kr == MACH_RCV_INTERRUPTED) {
          run_mach_msg_receive = true;
        }
      } while (run_mach_msg_receive);

      if (kr == MACH_MSG_SUCCESS) {
        request_scoper.swap(trial_request_scoper);
      } else if (kr == MACH_RCV_TOO_LARGE &&
                 receive_large == kReceiveLargeResize) {
        this_request_size =
            round_page(round_msg(request_header->msgh_size) + trailer_alloc);
        this_request_alloc = this_request_size;
      } else {
        return kr;
      }
    }

    vm_address_t reply_addr;
    kr = vm_allocate(mach_task_self(),
                     &reply_addr,
                     reply_alloc,
                     VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_MACH_MSG));
    if (kr != KERN_SUCCESS) {
      return kr;
    }

    base::mac::ScopedMachVM reply_scoper(reply_addr, reply_alloc);

    mach_msg_header_t* reply_header =
        reinterpret_cast<mach_msg_header_t*>(reply_addr);
    bool destroy_complex_request = false;
    interface->MachMessageServerFunction(
        request_header, reply_header, &destroy_complex_request);

    if (!(reply_header->msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
      // This only works if the reply message is not complex, because otherwise,
      // the location of the RetCode field is not known. It should be possible
      // to locate the RetCode field by looking beyond the descriptors in a
      // complex reply message, but this is not currently done. This behavior
      // has not proven itself necessary in practice, and it’s not done by
      // mach_msg_server() or mach_msg_server_once() either.
      mig_reply_error_t* reply_mig =
          reinterpret_cast<mig_reply_error_t*>(reply_header);
      if (reply_mig->RetCode == MIG_NO_REPLY) {
        reply_header->msgh_remote_port = MACH_PORT_NULL;
      } else if (reply_mig->RetCode != KERN_SUCCESS &&
                 request_header->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
        destroy_complex_request = true;
      }
    }

    if (destroy_complex_request &&
        request_header->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
      request_header->msgh_remote_port = MACH_PORT_NULL;
      mach_msg_destroy(request_header);
    }

    if (reply_header->msgh_remote_port != MACH_PORT_NULL) {
      // If the reply port right is a send-once right, the send won’t block even
      // if the remote side isn’t waiting for a message. No timeout is used,
      // which keeps the communication on the kernel’s fast path. If the reply
      // port right is a send right, MACH_SEND_TIMEOUT is used to avoid blocking
      // indefinitely. This duplicates the logic in 10.9.4
      // xnu-2422.110.17/libsyscall/mach/mach_msg.c mach_msg_server_once().
      mach_msg_option_t send_options =
          options | MACH_SEND_MSG |
          (MACH_MSGH_BITS_REMOTE(reply_header->msgh_bits) ==
                   MACH_MSG_TYPE_MOVE_SEND_ONCE
               ? 0
               : MACH_SEND_TIMEOUT);

      bool running;
      do {
        // If |options| contains MACH_SEND_INTERRUPT, retry mach_msg() in a loop
        // when it returns MACH_SEND_INTERRUPTED to recompute |remaining_ms|
        // rather than allowing mach_msg() to retry using the original timeout
        // value. See 10.9.4 xnu-2422.110.17/libsyscall/mach/mach_msg.c
        // mach_msg().
        mach_msg_timeout_t remaining_ms;
        running = TimerRunning(deadline, &remaining_ms);
        if (!running) {
          // Don’t return just yet. If the timer ran out in between the time the
          // request was received and now, at least try to send the response.
          remaining_ms = 0;
        }

        kr = mach_msg(reply_header,
                      send_options,
                      reply_header->msgh_size,
                      0,
                      MACH_PORT_NULL,
                      remaining_ms,
                      MACH_PORT_NULL);
      } while (kr == MACH_SEND_INTERRUPTED);

      if (kr != KERN_SUCCESS) {
        if (kr == MACH_SEND_INVALID_DEST || kr == MACH_SEND_TIMED_OUT) {
          mach_msg_destroy(reply_header);
        }
        return kr;
      }

      if (!running) {
        // The reply message was sent successfuly, so act as though the deadline
        // was reached before or during the subsequent receive operation when in
        // persistent mode, and just return success when not in persistent mode.
        return (persistent == kPersistent) ? MACH_RCV_TIMED_OUT : kr;
      }
    }
  } while (persistent == kPersistent);

  return kr;
}

}  // namespace crashpad
<commit_msg>Undo a68594234262.<commit_after>// Copyright 2014 The Crashpad Authors. All rights reserved.
//
// 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 "util/mach/mach_message_server.h"

#include <limits>

#include "base/mac/mach_logging.h"
#include "base/mac/scoped_mach_vm.h"
#include "util/misc/clock.h"

namespace crashpad {

namespace {

const int kNanosecondsPerMillisecond = 1E6;

// TimerRunning determines whether |deadline| has passed. If |deadline| is in
// the future, |*remaining_ms| is set to the number of milliseconds remaining,
// which will always be a positive value, and this function returns true. If
// |deadline| is zero (indicating that no timer is in effect), |*remaining_ms|
// is set to zero and this function returns true. Otherwise, this function
// returns false. |deadline| is specified on the same time base as is returned
// by ClockMonotonicNanoseconds().
bool TimerRunning(uint64_t deadline, mach_msg_timeout_t* remaining_ms) {
  if (!deadline) {
    *remaining_ms = MACH_MSG_TIMEOUT_NONE;
    return true;
  }

  uint64_t now = ClockMonotonicNanoseconds();

  if (now >= deadline) {
    return false;
  }

  uint64_t remaining = deadline - now;

  // Round to the nearest millisecond, taking care not to overflow.
  const int kHalfMillisecondInNanoseconds = kNanosecondsPerMillisecond / 2;
  mach_msg_timeout_t remaining_mach;
  if (remaining <=
      std::numeric_limits<uint64_t>::max() - kHalfMillisecondInNanoseconds) {
    remaining_mach = (remaining + kHalfMillisecondInNanoseconds) /
                     kNanosecondsPerMillisecond;
  } else {
    remaining_mach = remaining / kNanosecondsPerMillisecond;
  }

  if (remaining_mach == MACH_MSG_TIMEOUT_NONE) {
    return false;
  }

  *remaining_ms = remaining_mach;
  return true;
}

}  // namespace

// This implementation is based on 10.9.4
// xnu-2422.110.17/libsyscall/mach/mach_msg.c mach_msg_server_once(), but
// adapted to local style using scopers, replacing the server callback function
// and |max_size| parameter with a C++ interface, and with the addition of the
// the |persistent| parameter allowing this function to serve as a stand-in for
// mach_msg_server(), the |nonblocking| parameter to control blocking directly,
// and the |timeout_ms| parameter allowing this function to not block
// indefinitely.
//
// static
mach_msg_return_t MachMessageServer::Run(Interface* interface,
                                         mach_port_t receive_port,
                                         mach_msg_options_t options,
                                         Persistent persistent,
                                         Nonblocking nonblocking,
                                         ReceiveLarge receive_large,
                                         mach_msg_timeout_t timeout_ms) {
  options &= ~(MACH_RCV_MSG | MACH_SEND_MSG);

  mach_msg_options_t timeout_options = MACH_RCV_TIMEOUT | MACH_SEND_TIMEOUT |
                                       MACH_RCV_INTERRUPT | MACH_SEND_INTERRUPT;

  uint64_t deadline;
  if (nonblocking == kNonblocking) {
    options |= timeout_options;
    deadline = 0;
  } else if (timeout_ms != MACH_MSG_TIMEOUT_NONE) {
    options |= timeout_options;
    deadline = ClockMonotonicNanoseconds() +
               implicit_cast<uint64_t>(timeout_ms) * kNanosecondsPerMillisecond;
  } else {
    options &= ~timeout_options;
    deadline = 0;
  }

  if (receive_large == kReceiveLargeResize) {
    options |= MACH_RCV_LARGE;
  } else {
    options &= ~MACH_RCV_LARGE;
  }

  mach_msg_size_t trailer_alloc = REQUESTED_TRAILER_SIZE(options);
  mach_msg_size_t expected_request_size =
      interface->MachMessageServerRequestSize();
  mach_msg_size_t request_alloc =
      round_page(round_msg(expected_request_size) + trailer_alloc);
  mach_msg_size_t request_size =
      (receive_large == kReceiveLargeResize)
          ? request_alloc
          : round_msg(expected_request_size) + trailer_alloc;

  mach_msg_size_t max_reply_size = interface->MachMessageServerReplySize();

  // mach_msg_server() and mach_msg_server_once() would consider whether
  // |options| contains MACH_SEND_TRAILER and include MAX_TRAILER_SIZE in this
  // computation if it does, but that option is ineffective on OS X.
  mach_msg_size_t reply_alloc = round_page(max_reply_size);

  kern_return_t kr;

  do {
    mach_msg_size_t this_request_alloc = request_alloc;
    mach_msg_size_t this_request_size = request_size;

    base::mac::ScopedMachVM request_scoper;
    mach_msg_header_t* request_header = nullptr;

    while (!request_scoper.address()) {
      vm_address_t request_addr;
      kr = vm_allocate(mach_task_self(),
                       &request_addr,
                       this_request_alloc,
                       VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_MACH_MSG));
      if (kr != KERN_SUCCESS) {
        return kr;
      }
      base::mac::ScopedMachVM trial_request_scoper(request_addr,
                                                   this_request_alloc);
      request_header = reinterpret_cast<mach_msg_header_t*>(request_addr);

      bool run_mach_msg_receive = false;
      do {
        // If |options| contains MACH_RCV_INTERRUPT, retry mach_msg() in a loop
        // when it returns MACH_RCV_INTERRUPTED to recompute |remaining_ms|
        // rather than allowing mach_msg() to retry using the original timeout
        // value. See 10.9.4 xnu-2422.110.17/libsyscall/mach/mach_msg.c
        // mach_msg().
        mach_msg_timeout_t remaining_ms;
        if (!TimerRunning(deadline, &remaining_ms)) {
          return MACH_RCV_TIMED_OUT;
        }

        kr = mach_msg(request_header,
                      options | MACH_RCV_MSG,
                      0,
                      this_request_size,
                      receive_port,
                      remaining_ms,
                      MACH_PORT_NULL);

        if (kr == MACH_RCV_TOO_LARGE && receive_large == kReceiveLargeIgnore) {
          MACH_LOG(WARNING, kr) << "mach_msg: ignoring large message";
          run_mach_msg_receive = true;
        } else if (kr == MACH_RCV_INTERRUPTED) {
          run_mach_msg_receive = true;
        }
      } while (run_mach_msg_receive);

      if (kr == MACH_MSG_SUCCESS) {
        request_scoper.swap(trial_request_scoper);
      } else if (kr == MACH_RCV_TOO_LARGE &&
                 receive_large == kReceiveLargeResize) {
        this_request_size =
            round_page(round_msg(request_header->msgh_size) + trailer_alloc);
        this_request_alloc = this_request_size;
      } else {
        return kr;
      }
    }

    vm_address_t reply_addr;
    kr = vm_allocate(mach_task_self(),
                     &reply_addr,
                     reply_alloc,
                     VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_MACH_MSG));
    if (kr != KERN_SUCCESS) {
      return kr;
    }

    base::mac::ScopedMachVM reply_scoper(reply_addr, reply_alloc);

    mach_msg_header_t* reply_header =
        reinterpret_cast<mach_msg_header_t*>(reply_addr);
    bool destroy_complex_request = false;
    interface->MachMessageServerFunction(
        request_header, reply_header, &destroy_complex_request);

    if (!(reply_header->msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
      // This only works if the reply message is not complex, because otherwise,
      // the location of the RetCode field is not known. It should be possible
      // to locate the RetCode field by looking beyond the descriptors in a
      // complex reply message, but this is not currently done. This behavior
      // has not proven itself necessary in practice, and it’s not done by
      // mach_msg_server() or mach_msg_server_once() either.
      mig_reply_error_t* reply_mig =
          reinterpret_cast<mig_reply_error_t*>(reply_header);
      if (reply_mig->RetCode == MIG_NO_REPLY) {
        reply_header->msgh_remote_port = MACH_PORT_NULL;
      } else if (reply_mig->RetCode != KERN_SUCCESS &&
                 request_header->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
        destroy_complex_request = true;
      }
    }

    if (destroy_complex_request &&
        request_header->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
      request_header->msgh_remote_port = MACH_PORT_NULL;
      mach_msg_destroy(request_header);
    }

    if (reply_header->msgh_remote_port != MACH_PORT_NULL) {
      // If the reply port right is a send-once right, the send won’t block even
      // if the remote side isn’t waiting for a message. No timeout is used,
      // which keeps the communication on the kernel’s fast path. If the reply
      // port right is a send right, MACH_SEND_TIMEOUT is used to avoid blocking
      // indefinitely. This duplicates the logic in 10.9.4
      // xnu-2422.110.17/libsyscall/mach/mach_msg.c mach_msg_server_once().
      mach_msg_option_t send_options =
          options | MACH_SEND_MSG |
          (MACH_MSGH_BITS_REMOTE(reply_header->msgh_bits) ==
                   MACH_MSG_TYPE_MOVE_SEND_ONCE
               ? 0
               : MACH_SEND_TIMEOUT);

      bool running;
      do {
        // If |options| contains MACH_SEND_INTERRUPT, retry mach_msg() in a loop
        // when it returns MACH_SEND_INTERRUPTED to recompute |remaining_ms|
        // rather than allowing mach_msg() to retry using the original timeout
        // value. See 10.9.4 xnu-2422.110.17/libsyscall/mach/mach_msg.c
        // mach_msg().
        mach_msg_timeout_t remaining_ms;
        running = TimerRunning(deadline, &remaining_ms);
        if (!running) {
          // Don’t return just yet. If the timer ran out in between the time the
          // request was received and now, at least try to send the response.
          remaining_ms = 0;
        }

        kr = mach_msg(reply_header,
                      send_options,
                      reply_header->msgh_size,
                      0,
                      MACH_PORT_NULL,
                      remaining_ms,
                      MACH_PORT_NULL);
      } while (kr == MACH_SEND_INTERRUPTED);

      if (kr != KERN_SUCCESS) {
        if (kr == MACH_SEND_INVALID_DEST || kr == MACH_SEND_TIMED_OUT) {
          mach_msg_destroy(reply_header);
        }
        return kr;
      }

      if (!running) {
        // The reply message was sent successfuly, so act as though the deadline
        // was reached before or during the subsequent receive operation when in
        // persistent mode, and just return success when not in persistent mode.
        return (persistent == kPersistent) ? MACH_RCV_TIMED_OUT : kr;
      }
    }
  } while (persistent == kPersistent);

  return kr;
}

}  // namespace crashpad
<|endoftext|>


<commit_before>//-----------------------------------------------
//
//	This file is part of the Siv3D Engine.
//
//	Copyright (c) 2008-2019 Ryo Suzuki
//	Copyright (c) 2016-2019 OpenSiv3D Project
//
//	Licensed under the MIT License.
//
//-----------------------------------------------

# pragma once
# include <type_traits>
# include <limits>
# include <cmath>

namespace s3d
{
	/// <summary>
	/// 表現できる最大の数値
	/// </summary>
	template <class Type>
	constexpr Type Largest = std::numeric_limits<Type>::max();

	/// <summary>
	/// 表現できる最小の数値
	/// </summary>
	template <class Type>
	constexpr Type Smallest = std::numeric_limits<Type>::lowest();

	/// <summary>
	/// 正の無限大
	/// </summary>
	template <class Type>
	constexpr Type Inf = std::numeric_limits<Type>::infinity();

    /// <summary>
    /// 数値が非数 (NaN) であるかを示します。
    /// </summary>
    /// <param name="value">
    /// 数値
    /// </param>
    /// <returns>
    /// 数値が非数 (NaN) である場合 true, それ以外の場合は false
    /// </returns>
    template <class Type>
	[[nodiscard]] inline bool IsNaN([[maybe_unused]] const Type value)
    {
		if constexpr (std::is_floating_point_v<Type>)
		{
			return std::isnan(value);
		}
		else
		{
			return false;
		}
    }

    /// <summary>
    /// 数値が有限値であるかを示します。
    /// </summary>
    /// <param name="value">
    /// 数値
    /// </param>
    /// <returns>
    /// 数値が有限値である場合 true, それ以外の場合は false
    /// </returns>
    template <class Type>
	[[nodiscard]] inline bool IsFinite([[maybe_unused]] const Type value)
    {
		if constexpr (std::is_floating_point_v<Type>)
		{
			return std::isfinite(value);
		}
		else
		{
			return true;
		}
    }

    /// <summary>
    /// 数値が無限であるかを示します。
    /// </summary>
    /// <param name="value">
    /// 数値
    /// </param>
    /// <returns>
    /// 数値が無限である場合 true, それ以外の場合は false
    /// </returns>
    template <class Type>
	[[nodiscard]] inline bool IsInfinity([[maybe_unused]] const Type value)
    {
		if constexpr (std::is_floating_point_v<Type>)
		{
			return std::isinf(value);
		}
		else
		{
			return false;
		}
    }
}
<commit_msg>QNaN, SNaN<commit_after>//-----------------------------------------------
//
//	This file is part of the Siv3D Engine.
//
//	Copyright (c) 2008-2019 Ryo Suzuki
//	Copyright (c) 2016-2019 OpenSiv3D Project
//
//	Licensed under the MIT License.
//
//-----------------------------------------------

# pragma once
# include <type_traits>
# include <limits>
# include <cmath>

namespace s3d
{
	/// <summary>
	/// 表現できる最大の数値
	/// </summary>
	template <class Type>
	constexpr Type Largest = std::numeric_limits<Type>::max();

	/// <summary>
	/// 表現できる最小の数値
	/// </summary>
	template <class Type>
	constexpr Type Smallest = std::numeric_limits<Type>::lowest();

	/// <summary>
	/// 正の無限大
	/// </summary>
	template <class FloatingPoint>
	constexpr FloatingPoint Inf = std::numeric_limits<FloatingPoint>::infinity();

	/// <summary>
	/// qNaN
	/// </summary>
	template <class FloatingPoint>
	constexpr FloatingPoint QNaN = std::numeric_limits<FloatingPoint>::quiet_NaN();

	/// <summary>
	/// sNaN
	/// </summary>
	template <class FloatingPoint>
	constexpr FloatingPoint SNaN = std::numeric_limits<FloatingPoint>::signaling_NaN();

    /// <summary>
    /// 数値が非数 (NaN) であるかを示します。
    /// </summary>
    /// <param name="value">
    /// 数値
    /// </param>
    /// <returns>
    /// 数値が非数 (NaN) である場合 true, それ以外の場合は false
    /// </returns>
    template <class Type>
	[[nodiscard]] inline bool IsNaN([[maybe_unused]] const Type value)
    {
		if constexpr (std::is_floating_point_v<Type>)
		{
			return std::isnan(value);
		}
		else
		{
			return false;
		}
    }

    /// <summary>
    /// 数値が有限値であるかを示します。
    /// </summary>
    /// <param name="value">
    /// 数値
    /// </param>
    /// <returns>
    /// 数値が有限値である場合 true, それ以外の場合は false
    /// </returns>
    template <class Type>
	[[nodiscard]] inline bool IsFinite([[maybe_unused]] const Type value)
    {
		if constexpr (std::is_floating_point_v<Type>)
		{
			return std::isfinite(value);
		}
		else
		{
			return true;
		}
    }

    /// <summary>
    /// 数値が無限であるかを示します。
    /// </summary>
    /// <param name="value">
    /// 数値
    /// </param>
    /// <returns>
    /// 数値が無限である場合 true, それ以外の場合は false
    /// </returns>
    template <class Type>
	[[nodiscard]] inline bool IsInfinity([[maybe_unused]] const Type value)
    {
		if constexpr (std::is_floating_point_v<Type>)
		{
			return std::isinf(value);
		}
		else
		{
			return false;
		}
    }
}
<|endoftext|>


<commit_before>//
// Created by mrjaqbq on 07.03.16.
//

#include <algorithm>
#include <Utils/TypeInfo.h>
#include <Utils/MemorySizes.h>

#include "Core/EngineApis.h"
#include "Core/MemoryModule.h"
#include "Core/WindowManager.h"
#include "Core/Input/InputManager.h"
#include "Core/Resources/ResourceManager.h"
#include "Core/Resources/Mesh/MeshManager.h"
#include "Core/Resources/Shader/ShaderManager.h"
#include "Core/Resources/Texture/TextureManager.h"
#include "Core/Resources/Material/MaterialManager.h"
#include "Core/Gfx/BufferManager.h"
#include "Core/Gfx/Renderer.h"
#include "Core/Logic/Scene.h"
#include "Core/GameTime.h"
#include "Core/Engine.h"
#include "Core/Logger.h"
#include "Core/Config.h"

#ifdef CreateWindow
#undef CreateWindow
#endif

namespace Core
{
	Engine::Engine(std::string name, std::size_t memorySize)
		: Name(name), _isDone(false), _cleanedUp(false)
	{
		MemoryModule	.reset(new Core::MemoryModule(memorySize));
		Config			.reset(new Core::Config(MemoryModule.get().requestMemoryBlock(Memory::KB(1), "Config Block")));

		Renderer		.reset(CreateManager<Gfx::Renderer>(Memory::KB(100)));
		BufferManager	.reset(CreateManager<Gfx::BufferManager>(Memory::KB(100)));
		MeshManager		.reset(CreateManager<Resources::MeshManager>(Memory::KB(100)));
		TextureManager	.reset(CreateManager<Resources::TextureManager>(Memory::MB(4)));
		MaterialManager	.reset(CreateManager<Resources::MaterialManager>(Memory::KB(100)));
		ShaderManager	.reset(CreateManager<Resources::ShaderManager>(Memory::KB(100)));
		WindowManager	.reset(CreateManager<Core::WindowManager>(Memory::KB(10)));
		InputManager	.reset(CreateManager<Core::InputManager>(Memory::KB(10)));
	}

	auto Engine::CreateWindow() const noexcept -> Window::handle_t
	{
		auto handle = WindowManager.get().createNew(((std::string)Config.get().WindowTitle).c_str(),
													  Config.get().WindowWidth,
													  Config.get().WindowHeight);

		auto* window = WindowManager.get().tryGet(handle);
		if(window != nullptr)
		{
			if(!OpenGL::registerWindow(*window))
			{
				Logger::error("Unable to register window in OpenGL!");
			}
		}
		else
		{
			Logger::error("Unable to create window!");
		}

		return handle;
	}

	auto Engine::LoadConfig(std::string path) -> bool
	{
		return Config->Load(path);
	}

	auto Engine::Initialize() -> bool
	{
		bool video = OpenGL::initialize();
		if(video) SDL_Init(SDL_INIT_GAMECONTROLLER);
		return video;
	}

	auto Engine::SwitchScene(borrowed_ptr<Logic::Scene> scene) -> void
	{
		// todo: refactor to handle instead of raw pointer
		if(activeScene) activeScene->End();

		activeScene = scene;

		if(activeScene) activeScene->Start();
	}

	// todo: remove window from here
	auto Engine::Draw(const Core::Window& window, Core::GameTime& time) -> void
	{
		OpenGL::beginDraw(window);

		if(activeScene) activeScene->Draw(time, Renderer.get());

		Renderer->draw();

		OpenGL::endDraw(window);
	}

	auto Engine::ProcessEvents(Core::GameTime& time) -> void
	{
		if(ShouldClose())
			return;

		SDL_Event event;
		while(SDL_PollEvent(&event))
		{
			switch(event.type)
			{
				case SDL_QUIT:
					Quit();
					break;
				case SDL_WINDOWEVENT:
					WindowManager->handleWindowEvent(event);
					break;
				default:
					InputManager->handleInputEvent(event, time);
					break;
			}
		}
	}

	void Engine::Update(GameTime &time)
	{
		if(activeScene) activeScene->Update(time);
	}

	double Engine::GetCurrentTime()
	{
		return SDL_GetTicks() / 1000.0;
	}

	auto Engine::Quit() -> void
	{
		WindowManager->closeAllWindows();
		_isDone = true;
	}

	auto Engine::CleanUp() -> void
	{
		if(_cleanedUp)
			return;

		Logger::info("Cleaning up...");

		Memory::Delete(MemoryModule->masterBlock(), InputManager);
		Memory::Delete(MemoryModule->masterBlock(), WindowManager);
		Memory::Delete(MemoryModule->masterBlock(), BufferManager);
		Memory::Delete(MemoryModule->masterBlock(), MeshManager);
		Memory::Delete(MemoryModule->masterBlock(), TextureManager);
		Memory::Delete(MemoryModule->masterBlock(), MaterialManager);
		Memory::Delete(MemoryModule->masterBlock(), ShaderManager);
		Memory::Delete(MemoryModule->masterBlock(), Renderer);

		SDL_QuitSubSystem( SDL_INIT_VIDEO );
		SDL_Quit();

		Logger::info("Cleaned up!");
		Memory::SafeDelete(Config);
		Memory::SafeDelete(MemoryModule);

		_cleanedUp = true;
	}

	bool Engine::WasCleanedUp()
	{
		return _cleanedUp;
	}

	bool Engine::ShouldClose()
	{
		return _isDone || WasCleanedUp();
	}
}
<commit_msg>Fixed SDL gamecontroller subsystem initialization<commit_after>//
// Created by mrjaqbq on 07.03.16.
//

#include <algorithm>
#include <Utils/TypeInfo.h>
#include <Utils/MemorySizes.h>

#include "Core/EngineApis.h"
#include "Core/MemoryModule.h"
#include "Core/WindowManager.h"
#include "Core/Input/InputManager.h"
#include "Core/Resources/ResourceManager.h"
#include "Core/Resources/Mesh/MeshManager.h"
#include "Core/Resources/Shader/ShaderManager.h"
#include "Core/Resources/Texture/TextureManager.h"
#include "Core/Resources/Material/MaterialManager.h"
#include "Core/Gfx/BufferManager.h"
#include "Core/Gfx/Renderer.h"
#include "Core/Logic/Scene.h"
#include "Core/GameTime.h"
#include "Core/Engine.h"
#include "Core/Logger.h"
#include "Core/Config.h"

#ifdef CreateWindow
#undef CreateWindow
#endif

namespace Core
{
	Engine::Engine(std::string name, std::size_t memorySize)
		: Name(name), _isDone(false), _cleanedUp(false)
	{
		MemoryModule	.reset(new Core::MemoryModule(memorySize));
		Config			.reset(new Core::Config(MemoryModule.get().requestMemoryBlock(Memory::KB(1), "Config Block")));

		Renderer		.reset(CreateManager<Gfx::Renderer>(Memory::KB(100)));
		BufferManager	.reset(CreateManager<Gfx::BufferManager>(Memory::KB(100)));
		MeshManager		.reset(CreateManager<Resources::MeshManager>(Memory::KB(100)));
		TextureManager	.reset(CreateManager<Resources::TextureManager>(Memory::MB(4)));
		MaterialManager	.reset(CreateManager<Resources::MaterialManager>(Memory::KB(100)));
		ShaderManager	.reset(CreateManager<Resources::ShaderManager>(Memory::KB(100)));
		WindowManager	.reset(CreateManager<Core::WindowManager>(Memory::KB(10)));
		InputManager	.reset(CreateManager<Core::InputManager>(Memory::KB(10)));
	}

	auto Engine::CreateWindow() const noexcept -> Window::handle_t
	{
		auto handle = WindowManager.get().createNew(((std::string)Config.get().WindowTitle).c_str(),
													  Config.get().WindowWidth,
													  Config.get().WindowHeight);

		auto* window = WindowManager.get().tryGet(handle);
		if(window != nullptr)
		{
			if(!OpenGL::registerWindow(*window))
			{
				Logger::error("Unable to register window in OpenGL!");
			}
		}
		else
		{
			Logger::error("Unable to create window!");
		}

		return handle;
	}

	auto Engine::LoadConfig(std::string path) -> bool
	{
		return Config->Load(path);
	}

	auto Engine::Initialize() -> bool
	{
		bool video = OpenGL::initialize();
		if(video) SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER);
		return video;
	}

	auto Engine::SwitchScene(borrowed_ptr<Logic::Scene> scene) -> void
	{
		// todo: refactor to handle instead of raw pointer
		if(activeScene) activeScene->End();

		activeScene = scene;

		if(activeScene) activeScene->Start();
	}

	// todo: remove window from here
	auto Engine::Draw(const Core::Window& window, Core::GameTime& time) -> void
	{
		OpenGL::beginDraw(window);

		if(activeScene) activeScene->Draw(time, Renderer.get());

		Renderer->draw();

		OpenGL::endDraw(window);
	}

	auto Engine::ProcessEvents(Core::GameTime& time) -> void
	{
		if(ShouldClose())
			return;

		SDL_Event event;
		while(SDL_PollEvent(&event))
		{
			switch(event.type)
			{
				case SDL_QUIT:
					Quit();
					break;
				case SDL_WINDOWEVENT:
					WindowManager->handleWindowEvent(event);
					break;
				default:
					InputManager->handleInputEvent(event, time);
					break;
			}
		}
	}

	void Engine::Update(GameTime &time)
	{
		if(activeScene) activeScene->Update(time);
	}

	double Engine::GetCurrentTime()
	{
		return SDL_GetTicks() / 1000.0;
	}

	auto Engine::Quit() -> void
	{
		WindowManager->closeAllWindows();
		_isDone = true;
	}

	auto Engine::CleanUp() -> void
	{
		if(_cleanedUp)
			return;

		Logger::info("Cleaning up...");

		Memory::Delete(MemoryModule->masterBlock(), InputManager);
		Memory::Delete(MemoryModule->masterBlock(), WindowManager);
		Memory::Delete(MemoryModule->masterBlock(), BufferManager);
		Memory::Delete(MemoryModule->masterBlock(), MeshManager);
		Memory::Delete(MemoryModule->masterBlock(), TextureManager);
		Memory::Delete(MemoryModule->masterBlock(), MaterialManager);
		Memory::Delete(MemoryModule->masterBlock(), ShaderManager);
		Memory::Delete(MemoryModule->masterBlock(), Renderer);

		SDL_QuitSubSystem( SDL_INIT_VIDEO );
		SDL_Quit();

		Logger::info("Cleaned up!");
		Memory::SafeDelete(Config);
		Memory::SafeDelete(MemoryModule);

		_cleanedUp = true;
	}

	bool Engine::WasCleanedUp()
	{
		return _cleanedUp;
	}

	bool Engine::ShouldClose()
	{
		return _isDone || WasCleanedUp();
	}
}
<|endoftext|>