<commit_before>#include "errors.hpp"

#include <string>

#include "http/http.hpp"
#include "clustering/administration/http/json_adapters.hpp"
#include "clustering/administration/http/semilattice_app.hpp"
#include "clustering/administration/suggester.hpp"
#include "stl_utils.hpp"

semilattice_http_app_t::semilattice_http_app_t(
        metadata_change_handler_t<cluster_semilattice_metadata_t> *_metadata_change_handler,
        const clone_ptr_t<watchable_t<std::map<peer_id_t, cluster_directory_metadata_t> > > &_directory_metadata,
        uuid_t _us)
    : metadata_change_handler(_metadata_change_handler), directory_metadata(_directory_metadata), us(_us) { }

void semilattice_http_app_t::get_root(scoped_cJSON_t *json_out) {
    // keep this in sync with handle's behavior for getting the root
    cluster_semilattice_metadata_t cluster_metadata = metadata_change_handler->get();
    vclock_ctx_t json_ctx(us);
    json_ctx_adapter_t<cluster_semilattice_metadata_t, vclock_ctx_t> json_adapter(&cluster_metadata, json_ctx);
    json_out->reset(json_adapter.render());
}

http_res_t semilattice_http_app_t::handle(const http_req_t &req) {
    try {
        cluster_semilattice_metadata_t cluster_metadata = metadata_change_handler->get();

        //as we traverse the json sub directories this will keep track of where we are
        vclock_ctx_t json_ctx(us);
        boost::shared_ptr<json_adapter_if_t> json_adapter_head(new json_ctx_adapter_t<cluster_semilattice_metadata_t, vclock_ctx_t>(&cluster_metadata, json_ctx));

        http_req_t::resource_t::iterator it = req.resource.begin();

        //Traverse through the subfields until we're done with the url
        while (it != req.resource.end()) {
            json_adapter_if_t::json_adapter_map_t subfields = json_adapter_head->get_subfields();
            if (subfields.find(*it) == subfields.end()) {
                return http_res_t(HTTP_NOT_FOUND); //someone tried to walk off the edge of the world
            }
            json_adapter_head = subfields[*it];
            it++;
        }

        //json_adapter_head now points to the correct part of the metadata time to build a response and be on our way
        switch (req.method) {
            case GET:
            {
                scoped_cJSON_t json_repr(json_adapter_head->render());
                return http_json_res(json_repr.get());
            }
            break;
            case POST:
            {
                // TODO: Get rid of this release mode wrapper, make Michael unhappy.
#ifdef NDEBUG
                {
                    boost::optional<std::string> content_type = req.find_header_line("Content-Type");
                    if (!content_type || content_type.get() != "application/json") {
                        logINF("Bad request, Content-Type should be application/json.");
                        return http_res_t(HTTP_UNSUPPORTED_MEDIA_TYPE);
                    }
                }
#endif
                scoped_cJSON_t change(cJSON_Parse(req.body.c_str()));
                if (!change.get()) { //A null value indicates that parsing failed
                    logINF("Json body failed to parse. Here's the data that failed: %s",
                           req.get_sanitized_body().c_str());
                    return http_res_t(HTTP_BAD_REQUEST);
                }

                json_adapter_head->apply(change.get());

                {
                    scoped_cJSON_t absolute_change(change.release());
                    std::vector<std::string> parts(req.resource.begin(), req.resource.end());
                    for (std::vector<std::string>::reverse_iterator jt = parts.rbegin(); jt != parts.rend(); ++jt) {
                        scoped_cJSON_t inner(absolute_change.release());
                        absolute_change.reset(cJSON_CreateObject());
                        absolute_change.AddItemToObject(jt->c_str(), inner.release());
                    }
                    logINF("Applying data %s", absolute_change.PrintUnformatted().c_str());
                }

                /* Fill in the blueprints */
                try {
                    fill_in_blueprints(&cluster_metadata, directory_metadata->get(), us, false); //RSI this needs to be a parameter that we get from the request
                } catch (const missing_machine_exc_t &e) { }

                metadata_change_handler->update(cluster_metadata);

                scoped_cJSON_t json_repr(json_adapter_head->render());
                return http_json_res(json_repr.get());
            }
            break;
            case DELETE:
            {
                json_adapter_head->erase();

                logINF("Deleting %s", req.resource.as_string().c_str());

                try {
                    fill_in_blueprints(&cluster_metadata, directory_metadata->get(), us, false);
                } catch (const missing_machine_exc_t &e) { }

                metadata_change_handler->update(cluster_metadata);

                scoped_cJSON_t json_repr(json_adapter_head->render());
                return http_json_res(json_repr.get());
            }
            break;
            case PUT:
            {
                // TODO: Get rid of this release mode wrapper, make Michael unhappy.
#ifdef NDEBUG
                {
                    boost::optional<std::string> content_type = req.find_header_line("Content-Type");
                    if (!content_type || content_type.get() != "application/json") {
                        logINF("Bad request, Content-Type should be application/json.");
                        return http_res_t(HTTP_UNSUPPORTED_MEDIA_TYPE);
                    }
                }
#endif
                scoped_cJSON_t change(cJSON_Parse(req.body.c_str()));
                if (!change.get()) { //A null value indicates that parsing failed
                    logINF("Json body failed to parse. Here's the data that failed: %s",
                           req.get_sanitized_body().c_str());
                    return http_res_t(HTTP_BAD_REQUEST);
                }

                {
                    scoped_cJSON_t absolute_change(change.release());
                    std::vector<std::string> parts(req.resource.begin(), req.resource.end());
                    for (std::vector<std::string>::reverse_iterator jt = parts.rbegin(); jt != parts.rend(); ++jt) {
                        scoped_cJSON_t inner(absolute_change.release());
                        absolute_change.reset(cJSON_CreateObject());
                        absolute_change.AddItemToObject(jt->c_str(), inner.release());
                    }
                    logINF("Applying data %s", absolute_change.PrintUnformatted().c_str());
                }

                json_adapter_head->reset();
                json_adapter_head->apply(change.get());

                /* Fill in the blueprints */
                try {
                    fill_in_blueprints(&cluster_metadata, directory_metadata->get(), us, false);
                } catch (const missing_machine_exc_t &e) { }

                metadata_change_handler->update(cluster_metadata);

                scoped_cJSON_t json_repr(json_adapter_head->render());
                return http_json_res(json_repr.get());
            }
            break;
            case HEAD:
            case TRACE:
            case OPTIONS:
            case CONNECT:
            case PATCH:
            default:
                return http_res_t(HTTP_METHOD_NOT_ALLOWED);
                break;
        }
    } catch (const schema_mismatch_exc_t &e) {
        logINF("HTTP request throw a schema_mismatch_exc_t with what = %s", e.what());
        return http_error_res(e.what());
    } catch (const permission_denied_exc_t &e) {
        logINF("HTTP request throw a permission_denied_exc_t with what = %s", e.what());
        return http_error_res(e.what());
    } catch (const cannot_satisfy_goals_exc_t &e) {
        logINF("The server was given a set of goals for which it couldn't find a valid blueprint. %s", e.what());
        return http_error_res(e.what(), HTTP_INTERNAL_SERVER_ERROR);
    }
    unreachable();
}

<commit_msg>Punches prefer_distribution through to the http api.<commit_after>#include "errors.hpp"

#include <string>

#include "http/http.hpp"
#include "clustering/administration/http/json_adapters.hpp"
#include "clustering/administration/http/semilattice_app.hpp"
#include "clustering/administration/suggester.hpp"
#include "stl_utils.hpp"

semilattice_http_app_t::semilattice_http_app_t(
        metadata_change_handler_t<cluster_semilattice_metadata_t> *_metadata_change_handler,
        const clone_ptr_t<watchable_t<std::map<peer_id_t, cluster_directory_metadata_t> > > &_directory_metadata,
        uuid_t _us)
    : metadata_change_handler(_metadata_change_handler), directory_metadata(_directory_metadata), us(_us) { }

void semilattice_http_app_t::get_root(scoped_cJSON_t *json_out) {
    // keep this in sync with handle's behavior for getting the root
    cluster_semilattice_metadata_t cluster_metadata = metadata_change_handler->get();
    vclock_ctx_t json_ctx(us);
    json_ctx_adapter_t<cluster_semilattice_metadata_t, vclock_ctx_t> json_adapter(&cluster_metadata, json_ctx);
    json_out->reset(json_adapter.render());
}

http_res_t semilattice_http_app_t::handle(const http_req_t &req) {
    try {
        cluster_semilattice_metadata_t cluster_metadata = metadata_change_handler->get();

        //as we traverse the json sub directories this will keep track of where we are
        vclock_ctx_t json_ctx(us);
        boost::shared_ptr<json_adapter_if_t> json_adapter_head(new json_ctx_adapter_t<cluster_semilattice_metadata_t, vclock_ctx_t>(&cluster_metadata, json_ctx));

        http_req_t::resource_t::iterator it = req.resource.begin();

        //Traverse through the subfields until we're done with the url
        while (it != req.resource.end()) {
            json_adapter_if_t::json_adapter_map_t subfields = json_adapter_head->get_subfields();
            if (subfields.find(*it) == subfields.end()) {
                return http_res_t(HTTP_NOT_FOUND); //someone tried to walk off the edge of the world
            }
            json_adapter_head = subfields[*it];
            it++;
        }

        //json_adapter_head now points to the correct part of the metadata time to build a response and be on our way
        switch (req.method) {
            case GET:
            {
                scoped_cJSON_t json_repr(json_adapter_head->render());
                return http_json_res(json_repr.get());
            }
            break;
            case POST:
            {
                // TODO: Get rid of this release mode wrapper, make Michael unhappy.
#ifdef NDEBUG
                {
                    boost::optional<std::string> content_type = req.find_header_line("Content-Type");
                    if (!content_type || content_type.get() != "application/json") {
                        logINF("Bad request, Content-Type should be application/json.");
                        return http_res_t(HTTP_UNSUPPORTED_MEDIA_TYPE);
                    }
                }
#endif
                scoped_cJSON_t change(cJSON_Parse(req.body.c_str()));
                if (!change.get()) { //A null value indicates that parsing failed
                    logINF("Json body failed to parse. Here's the data that failed: %s",
                           req.get_sanitized_body().c_str());
                    return http_res_t(HTTP_BAD_REQUEST);
                }

                json_adapter_head->apply(change.get());

                {
                    scoped_cJSON_t absolute_change(change.release());
                    std::vector<std::string> parts(req.resource.begin(), req.resource.end());
                    for (std::vector<std::string>::reverse_iterator jt = parts.rbegin(); jt != parts.rend(); ++jt) {
                        scoped_cJSON_t inner(absolute_change.release());
                        absolute_change.reset(cJSON_CreateObject());
                        absolute_change.AddItemToObject(jt->c_str(), inner.release());
                    }
                    logINF("Applying data %s", absolute_change.PrintUnformatted().c_str());
                }

                /* Fill in the blueprints */
                try {
                    fill_in_blueprints(&cluster_metadata, directory_metadata->get(), us, (req.find_query_param("prefer_distribution") ? true : false)); //RSI this needs to be a parameter that we get from the request
                } catch (const missing_machine_exc_t &e) { }

                metadata_change_handler->update(cluster_metadata);

                scoped_cJSON_t json_repr(json_adapter_head->render());
                return http_json_res(json_repr.get());
            }
            break;
            case DELETE:
            {
                json_adapter_head->erase();

                logINF("Deleting %s", req.resource.as_string().c_str());

                try {
                    fill_in_blueprints(&cluster_metadata, directory_metadata->get(), us, false);
                } catch (const missing_machine_exc_t &e) { }

                metadata_change_handler->update(cluster_metadata);

                scoped_cJSON_t json_repr(json_adapter_head->render());
                return http_json_res(json_repr.get());
            }
            break;
            case PUT:
            {
                // TODO: Get rid of this release mode wrapper, make Michael unhappy.
#ifdef NDEBUG
                {
                    boost::optional<std::string> content_type = req.find_header_line("Content-Type");
                    if (!content_type || content_type.get() != "application/json") {
                        logINF("Bad request, Content-Type should be application/json.");
                        return http_res_t(HTTP_UNSUPPORTED_MEDIA_TYPE);
                    }
                }
#endif
                scoped_cJSON_t change(cJSON_Parse(req.body.c_str()));
                if (!change.get()) { //A null value indicates that parsing failed
                    logINF("Json body failed to parse. Here's the data that failed: %s",
                           req.get_sanitized_body().c_str());
                    return http_res_t(HTTP_BAD_REQUEST);
                }

                {
                    scoped_cJSON_t absolute_change(change.release());
                    std::vector<std::string> parts(req.resource.begin(), req.resource.end());
                    for (std::vector<std::string>::reverse_iterator jt = parts.rbegin(); jt != parts.rend(); ++jt) {
                        scoped_cJSON_t inner(absolute_change.release());
                        absolute_change.reset(cJSON_CreateObject());
                        absolute_change.AddItemToObject(jt->c_str(), inner.release());
                    }
                    logINF("Applying data %s", absolute_change.PrintUnformatted().c_str());
                }

                json_adapter_head->reset();
                json_adapter_head->apply(change.get());

                /* Fill in the blueprints */
                try {
                    fill_in_blueprints(&cluster_metadata, directory_metadata->get(), us, false);
                } catch (const missing_machine_exc_t &e) { }

                metadata_change_handler->update(cluster_metadata);

                scoped_cJSON_t json_repr(json_adapter_head->render());
                return http_json_res(json_repr.get());
            }
            break;
            case HEAD:
            case TRACE:
            case OPTIONS:
            case CONNECT:
            case PATCH:
            default:
                return http_res_t(HTTP_METHOD_NOT_ALLOWED);
                break;
        }
    } catch (const schema_mismatch_exc_t &e) {
        logINF("HTTP request throw a schema_mismatch_exc_t with what = %s", e.what());
        return http_error_res(e.what());
    } catch (const permission_denied_exc_t &e) {
        logINF("HTTP request throw a permission_denied_exc_t with what = %s", e.what());
        return http_error_res(e.what());
    } catch (const cannot_satisfy_goals_exc_t &e) {
        logINF("The server was given a set of goals for which it couldn't find a valid blueprint. %s", e.what());
        return http_error_res(e.what(), HTTP_INTERNAL_SERVER_ERROR);
    }
    unreachable();
}

<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Compositor.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
**     of its contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qwaylandsurfaceitem.h"
#include "qwaylandsurfacenode_p.h"
#include "qwaylandsurface.h"
#include "qwaylandcompositor.h"
#include "qwaylandinput.h"

#include "qwlsurface_p.h"
#include "qwlextendedsurface_p.h"

#include <QtGui/QKeyEvent>
#include <QtGui/QGuiApplication>
#include <QtGui/QScreen>

#include <QtQuick/QSGSimpleRectNode>
#include <QtQuick/QQuickWindow>

#include <QtCore/QMutexLocker>
#include <QtCore/QMutex>

QT_BEGIN_NAMESPACE

class QWaylandSurfaceTextureProvider : public QSGTextureProvider
{
    Q_OBJECT

public:
    QWaylandSurfaceTextureProvider() : t(0) { }
    ~QWaylandSurfaceTextureProvider() { delete t; }

    QSGTexture *texture() const {
        if (t)
            t->setFiltering(smooth ? QSGTexture::Linear : QSGTexture::Nearest);
        return t;
    }

    bool smooth;
    QSGTexture *t;

public slots:
    void invalidate()
    {
        delete t;
        t = 0;
    }
};

QMutex *QWaylandSurfaceItem::mutex = 0;

QWaylandSurfaceItem::QWaylandSurfaceItem(QQuickItem *parent)
    : QQuickItem(parent)
    , m_surface(0)
    , m_provider(0)
    , m_node(0)
    , m_paintEnabled(true)
    , m_useTextureAlpha(false)
    , m_clientRenderingEnabled(false)
    , m_touchEventsEnabled(false)
    , m_resizeSurfaceToItem(false)
{
    if (!mutex)
        mutex = new QMutex;
}

QWaylandSurfaceItem::QWaylandSurfaceItem(QWaylandSurface *surface, QQuickItem *parent)
    : QQuickItem(parent)
    , m_surface(0)
    , m_provider(0)
    , m_node(0)
    , m_paintEnabled(true)
    , m_useTextureAlpha(false)
    , m_clientRenderingEnabled(false)
    , m_touchEventsEnabled(false)
{
    init(surface);
}

void QWaylandSurfaceItem::init(QWaylandSurface *surface)
{
    if (!surface)
        return;

    if (m_surface) {
        m_surface->setSurfaceItem(0);
    }

    m_surface = surface;
    m_surface->setSurfaceItem(this);
    if (m_clientRenderingEnabled) {
        m_surface->sendOnScreenVisibilityChange(m_clientRenderingEnabled);
    }

    if (m_resizeSurfaceToItem) {
        updateSurfaceSize();
    } else {
        setWidth(surface->size().width());
        setHeight(surface->size().height());
    }

    setSmooth(true);
    setFlag(ItemHasContents);
    setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton | Qt::RightButton |
        Qt::ExtraButton1 | Qt::ExtraButton2 | Qt::ExtraButton3 | Qt::ExtraButton4 |
        Qt::ExtraButton5 | Qt::ExtraButton6 | Qt::ExtraButton7 | Qt::ExtraButton8 |
        Qt::ExtraButton9 | Qt::ExtraButton10 | Qt::ExtraButton11 |
        Qt::ExtraButton12 | Qt::ExtraButton13);
    setAcceptHoverEvents(true);
    connect(surface, SIGNAL(mapped()), this, SLOT(surfaceMapped()));
    connect(surface, SIGNAL(unmapped()), this, SLOT(surfaceUnmapped()));
    connect(surface, SIGNAL(destroyed(QObject *)), this, SLOT(surfaceDestroyed(QObject *)));
    connect(surface, SIGNAL(damaged(const QRect &)), this, SLOT(surfaceDamaged(const QRect &)));
    connect(surface, SIGNAL(parentChanged(QWaylandSurface*,QWaylandSurface*)),
            this, SLOT(parentChanged(QWaylandSurface*,QWaylandSurface*)));
    connect(surface, SIGNAL(sizeChanged()), this, SLOT(updateSize()));
    connect(surface, SIGNAL(posChanged()), this, SLOT(updatePosition()));
    connect(this, SIGNAL(widthChanged()), this, SLOT(updateSurfaceSize()));
    connect(this, SIGNAL(heightChanged()), this, SLOT(updateSurfaceSize()));

    m_damaged = false;
    m_yInverted = surface ? surface->isYInverted() : true;
}

QWaylandSurfaceItem::~QWaylandSurfaceItem()
{
    QMutexLocker locker(mutex);
    if (m_node)
        m_node->setItem(0);
    if (m_surface)
        m_surface->setSurfaceItem(0);
    if (m_provider)
        m_provider->deleteLater();
}

void QWaylandSurfaceItem::setSurface(QWaylandSurface *surface)
{
    if (surface == m_surface)
        return;

    init(surface);
    emit surfaceChanged();
}

bool QWaylandSurfaceItem::isYInverted() const
{
    return m_yInverted;
}

QSGTextureProvider *QWaylandSurfaceItem::textureProvider() const
{
    const_cast<QWaylandSurfaceItem *>(this)->ensureProvider();
    return m_provider;
}

void QWaylandSurfaceItem::ensureProvider()
{
    if (!m_provider) {
        m_provider = new QWaylandSurfaceTextureProvider();
        connect(window(), SIGNAL(sceneGraphInvalidated()), m_provider, SLOT(invalidate()), Qt::DirectConnection);
    }
}

void QWaylandSurfaceItem::mousePressEvent(QMouseEvent *event)
{
    if (m_surface) {
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        if (inputDevice->mouseFocus() != m_surface)
            inputDevice->setMouseFocus(m_surface, event->pos(), event->globalPos());
        inputDevice->sendMousePressEvent(event->button(), toSurface(event->pos()), event->globalPos());
    }
}

void QWaylandSurfaceItem::mouseMoveEvent(QMouseEvent *event)
{
    if (m_surface){
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        inputDevice->sendMouseMoveEvent(m_surface, toSurface(event->pos()), event->globalPos());
    }
}

void QWaylandSurfaceItem::mouseReleaseEvent(QMouseEvent *event)
{
    if (m_surface){
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        inputDevice->sendMouseReleaseEvent(event->button(), toSurface(event->pos()), event->globalPos());
    }
}

void QWaylandSurfaceItem::wheelEvent(QWheelEvent *event)
{
    if (m_surface) {
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        inputDevice->sendMouseWheelEvent(event->orientation(), event->delta());
    }
}

void QWaylandSurfaceItem::keyPressEvent(QKeyEvent *event)
{
    if (m_surface && hasFocus()) {
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        inputDevice->sendFullKeyEvent(event);
    }
}

void QWaylandSurfaceItem::keyReleaseEvent(QKeyEvent *event)
{
    if (m_surface && hasFocus()) {
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        inputDevice->sendFullKeyEvent(event);
    }
}

void QWaylandSurfaceItem::touchEvent(QTouchEvent *event)
{
    if (m_touchEventsEnabled && m_surface) {
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        event->accept();
        if (inputDevice->mouseFocus() != m_surface) {
            QPoint pointPos;
            QList<QTouchEvent::TouchPoint> points = event->touchPoints();
            if (!points.isEmpty())
                pointPos = points.at(0).pos().toPoint();
            inputDevice->setMouseFocus(m_surface, pointPos, pointPos);
        }
        inputDevice->sendFullTouchEvent(event);
    } else {
        event->ignore();
    }
}

void QWaylandSurfaceItem::takeFocus()
{
    setFocus(true);

    if (m_surface) {
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        inputDevice->setKeyboardFocus(m_surface);
    }
}

QPoint QWaylandSurfaceItem::toSurface(const QPointF &pos) const
{
    return pos.toPoint();
}

void QWaylandSurfaceItem::surfaceMapped()
{
    setPaintEnabled(true);
}

void QWaylandSurfaceItem::surfaceUnmapped()
{
    setPaintEnabled(false);
}

void QWaylandSurfaceItem::surfaceDestroyed(QObject *)
{
    m_surface = 0;
}

void QWaylandSurfaceItem::setDamagedFlag(bool on)
{
    m_damaged = on;
}

void QWaylandSurfaceItem::surfaceDamaged(const QRect &)
{
    m_damaged = true;
    if (m_surface) {
        bool inverted = m_surface->isYInverted();
        if (inverted  != m_yInverted) {
            m_yInverted = inverted;
            emit yInvertedChanged();
        }
    }
    emit textureChanged();
    update();
}

void QWaylandSurfaceItem::parentChanged(QWaylandSurface *newParent, QWaylandSurface *oldParent)
{
    Q_UNUSED(oldParent);

    QWaylandSurfaceItem *item = newParent? newParent->surfaceItem():0;
    setParentItem(item);

    if (newParent) {
        setPaintEnabled(true);
        setVisible(true);
        setOpacity(1);
        setEnabled(true);
    }
}

void QWaylandSurfaceItem::updateSize()
{
    setSize(m_surface->size());
}

void QWaylandSurfaceItem::updateSurfaceSize()
{
    if (m_resizeSurfaceToItem) {
        m_surface->sendConfigure(QSize(width(), height()));
    }
}

void QWaylandSurfaceItem::updatePosition()
{
    setPosition(m_surface->pos());
}

bool QWaylandSurfaceItem::paintEnabled() const
{
    return m_paintEnabled;
}

void QWaylandSurfaceItem::setPaintEnabled(bool enabled)
{
    m_paintEnabled = enabled;
    update();
}

void QWaylandSurfaceItem::updateTexture()
{
    ensureProvider();
    QSGTexture *texture = m_provider->t;
    if (m_damaged) {
        m_damaged = false;
        QSGTexture *oldTexture = texture;
        if (m_surface->type() == QWaylandSurface::Texture) {
            QOpenGLContext *context = QOpenGLContext::currentContext();
            QQuickWindow::CreateTextureOptions opt = 0;
            if (useTextureAlpha()) {
                opt |= QQuickWindow::TextureHasAlphaChannel;
            }
            texture = window()->createTextureFromId(m_surface->texture(context), m_surface->size(), opt);
        } else {
            texture = window()->createTextureFromImage(m_surface->image());
        }
        texture->bind();
        delete oldTexture;
    }

    m_provider->t = texture;
    m_provider->smooth = smooth();
}

QSGNode *QWaylandSurfaceItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
    if (!m_surface) {
        delete oldNode;
        return 0;
    }

    updateTexture();
    if (!m_provider->t || !m_paintEnabled) {
        delete oldNode;
        return 0;
    }

    QWaylandSurfaceNode *node = static_cast<QWaylandSurfaceNode *>(oldNode);

    if (!node) {
        node = new QWaylandSurfaceNode(this);
    }

    node->updateTexture();

    if (surface()->isYInverted()) {
        node->setRect(0, height(), width(), -height());
    } else {
        node->setRect(0, 0, width(), height());
    }

    node->setTextureUpdated(true);

    return node;
}

void QWaylandSurfaceItem::setUseTextureAlpha(bool useTextureAlpha)
{
    m_useTextureAlpha = useTextureAlpha;

    if ((flags() & ItemHasContents) != 0) {
        update();
    }
}

void QWaylandSurfaceItem::setClientRenderingEnabled(bool enabled)
{
    if (m_clientRenderingEnabled != enabled) {
        m_clientRenderingEnabled = enabled;

        if (m_surface) {
            m_surface->sendOnScreenVisibilityChange(enabled);
        }

        emit clientRenderingEnabledChanged();
    }
}

void QWaylandSurfaceItem::setTouchEventsEnabled(bool enabled)
{
    if (m_touchEventsEnabled != enabled) {
        m_touchEventsEnabled = enabled;
        emit touchEventsEnabledChanged();
    }
}

void QWaylandSurfaceItem::setResizeSurfaceToItem(bool enabled)
{
    if (m_resizeSurfaceToItem != enabled) {
        m_resizeSurfaceToItem = enabled;
        emit resizeSurfaceToItemChanged();
    }
}

#include "qwaylandsurfaceitem.moc"

QT_END_NAMESPACE
<commit_msg>Fixed rendering stalling in qml-compositor.<commit_after>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Compositor.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
**     of its contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qwaylandsurfaceitem.h"
#include "qwaylandsurfacenode_p.h"
#include "qwaylandsurface.h"
#include "qwaylandcompositor.h"
#include "qwaylandinput.h"

#include "qwlsurface_p.h"
#include "qwlextendedsurface_p.h"

#include <QtGui/QKeyEvent>
#include <QtGui/QGuiApplication>
#include <QtGui/QScreen>

#include <QtQuick/QSGSimpleRectNode>
#include <QtQuick/QQuickWindow>

#include <QtCore/QMutexLocker>
#include <QtCore/QMutex>

QT_BEGIN_NAMESPACE

class QWaylandSurfaceTextureProvider : public QSGTextureProvider
{
    Q_OBJECT

public:
    QWaylandSurfaceTextureProvider() : t(0) { }
    ~QWaylandSurfaceTextureProvider() { delete t; }

    QSGTexture *texture() const {
        if (t)
            t->setFiltering(smooth ? QSGTexture::Linear : QSGTexture::Nearest);
        return t;
    }

    bool smooth;
    QSGTexture *t;

public slots:
    void invalidate()
    {
        delete t;
        t = 0;
    }
};

QMutex *QWaylandSurfaceItem::mutex = 0;

QWaylandSurfaceItem::QWaylandSurfaceItem(QQuickItem *parent)
    : QQuickItem(parent)
    , m_surface(0)
    , m_provider(0)
    , m_node(0)
    , m_paintEnabled(true)
    , m_useTextureAlpha(false)
    , m_clientRenderingEnabled(false)
    , m_touchEventsEnabled(false)
    , m_resizeSurfaceToItem(false)
{
    if (!mutex)
        mutex = new QMutex;
}

QWaylandSurfaceItem::QWaylandSurfaceItem(QWaylandSurface *surface, QQuickItem *parent)
    : QQuickItem(parent)
    , m_surface(0)
    , m_provider(0)
    , m_node(0)
    , m_paintEnabled(true)
    , m_useTextureAlpha(false)
    , m_clientRenderingEnabled(false)
    , m_touchEventsEnabled(false)
{
    init(surface);
}

void QWaylandSurfaceItem::init(QWaylandSurface *surface)
{
    if (!surface)
        return;

    if (m_surface) {
        m_surface->setSurfaceItem(0);
    }

    m_surface = surface;
    m_surface->setSurfaceItem(this);
    if (m_clientRenderingEnabled) {
        m_surface->sendOnScreenVisibilityChange(m_clientRenderingEnabled);
    }

    if (m_resizeSurfaceToItem) {
        updateSurfaceSize();
    } else {
        setWidth(surface->size().width());
        setHeight(surface->size().height());
    }

    setSmooth(true);
    setFlag(ItemHasContents);
    setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton | Qt::RightButton |
        Qt::ExtraButton1 | Qt::ExtraButton2 | Qt::ExtraButton3 | Qt::ExtraButton4 |
        Qt::ExtraButton5 | Qt::ExtraButton6 | Qt::ExtraButton7 | Qt::ExtraButton8 |
        Qt::ExtraButton9 | Qt::ExtraButton10 | Qt::ExtraButton11 |
        Qt::ExtraButton12 | Qt::ExtraButton13);
    setAcceptHoverEvents(true);
    connect(surface, SIGNAL(mapped()), this, SLOT(surfaceMapped()));
    connect(surface, SIGNAL(unmapped()), this, SLOT(surfaceUnmapped()));
    connect(surface, SIGNAL(destroyed(QObject *)), this, SLOT(surfaceDestroyed(QObject *)));
    connect(surface, SIGNAL(damaged(const QRect &)), this, SLOT(surfaceDamaged(const QRect &)));
    connect(surface, SIGNAL(parentChanged(QWaylandSurface*,QWaylandSurface*)),
            this, SLOT(parentChanged(QWaylandSurface*,QWaylandSurface*)));
    connect(surface, SIGNAL(sizeChanged()), this, SLOT(updateSize()));
    connect(surface, SIGNAL(posChanged()), this, SLOT(updatePosition()));
    connect(this, SIGNAL(widthChanged()), this, SLOT(updateSurfaceSize()));
    connect(this, SIGNAL(heightChanged()), this, SLOT(updateSurfaceSize()));

    m_damaged = false;
    m_yInverted = surface ? surface->isYInverted() : true;
}

QWaylandSurfaceItem::~QWaylandSurfaceItem()
{
    QMutexLocker locker(mutex);
    if (m_node)
        m_node->setItem(0);
    if (m_surface)
        m_surface->setSurfaceItem(0);
    if (m_provider)
        m_provider->deleteLater();
}

void QWaylandSurfaceItem::setSurface(QWaylandSurface *surface)
{
    if (surface == m_surface)
        return;

    init(surface);
    emit surfaceChanged();
}

bool QWaylandSurfaceItem::isYInverted() const
{
    return m_yInverted;
}

QSGTextureProvider *QWaylandSurfaceItem::textureProvider() const
{
    const_cast<QWaylandSurfaceItem *>(this)->ensureProvider();
    return m_provider;
}

void QWaylandSurfaceItem::ensureProvider()
{
    if (!m_provider) {
        m_provider = new QWaylandSurfaceTextureProvider();
        connect(window(), SIGNAL(sceneGraphInvalidated()), m_provider, SLOT(invalidate()), Qt::DirectConnection);
    }
}

void QWaylandSurfaceItem::mousePressEvent(QMouseEvent *event)
{
    if (m_surface) {
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        if (inputDevice->mouseFocus() != m_surface)
            inputDevice->setMouseFocus(m_surface, event->pos(), event->globalPos());
        inputDevice->sendMousePressEvent(event->button(), toSurface(event->pos()), event->globalPos());
    }
}

void QWaylandSurfaceItem::mouseMoveEvent(QMouseEvent *event)
{
    if (m_surface){
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        inputDevice->sendMouseMoveEvent(m_surface, toSurface(event->pos()), event->globalPos());
    }
}

void QWaylandSurfaceItem::mouseReleaseEvent(QMouseEvent *event)
{
    if (m_surface){
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        inputDevice->sendMouseReleaseEvent(event->button(), toSurface(event->pos()), event->globalPos());
    }
}

void QWaylandSurfaceItem::wheelEvent(QWheelEvent *event)
{
    if (m_surface) {
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        inputDevice->sendMouseWheelEvent(event->orientation(), event->delta());
    }
}

void QWaylandSurfaceItem::keyPressEvent(QKeyEvent *event)
{
    if (m_surface && hasFocus()) {
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        inputDevice->sendFullKeyEvent(event);
    }
}

void QWaylandSurfaceItem::keyReleaseEvent(QKeyEvent *event)
{
    if (m_surface && hasFocus()) {
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        inputDevice->sendFullKeyEvent(event);
    }
}

void QWaylandSurfaceItem::touchEvent(QTouchEvent *event)
{
    if (m_touchEventsEnabled && m_surface) {
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        event->accept();
        if (inputDevice->mouseFocus() != m_surface) {
            QPoint pointPos;
            QList<QTouchEvent::TouchPoint> points = event->touchPoints();
            if (!points.isEmpty())
                pointPos = points.at(0).pos().toPoint();
            inputDevice->setMouseFocus(m_surface, pointPos, pointPos);
        }
        inputDevice->sendFullTouchEvent(event);
    } else {
        event->ignore();
    }
}

void QWaylandSurfaceItem::takeFocus()
{
    setFocus(true);

    if (m_surface) {
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        inputDevice->setKeyboardFocus(m_surface);
    }
}

QPoint QWaylandSurfaceItem::toSurface(const QPointF &pos) const
{
    return pos.toPoint();
}

void QWaylandSurfaceItem::surfaceMapped()
{
    setPaintEnabled(true);
}

void QWaylandSurfaceItem::surfaceUnmapped()
{
    setPaintEnabled(false);
}

void QWaylandSurfaceItem::surfaceDestroyed(QObject *)
{
    m_surface = 0;
}

void QWaylandSurfaceItem::setDamagedFlag(bool on)
{
    m_damaged = on;
}

void QWaylandSurfaceItem::surfaceDamaged(const QRect &)
{
    m_damaged = true;
    if (m_surface) {
        bool inverted = m_surface->isYInverted();
        if (inverted  != m_yInverted) {
            m_yInverted = inverted;
            emit yInvertedChanged();
        }
    }
    emit textureChanged();
    update();
}

void QWaylandSurfaceItem::parentChanged(QWaylandSurface *newParent, QWaylandSurface *oldParent)
{
    Q_UNUSED(oldParent);

    QWaylandSurfaceItem *item = newParent? newParent->surfaceItem():0;
    setParentItem(item);

    if (newParent) {
        setPaintEnabled(true);
        setVisible(true);
        setOpacity(1);
        setEnabled(true);
    }
}

void QWaylandSurfaceItem::updateSize()
{
    setSize(m_surface->size());
}

void QWaylandSurfaceItem::updateSurfaceSize()
{
    if (m_resizeSurfaceToItem) {
        m_surface->sendConfigure(QSize(width(), height()));
    }
}

void QWaylandSurfaceItem::updatePosition()
{
    setPosition(m_surface->pos());
}

bool QWaylandSurfaceItem::paintEnabled() const
{
    return m_paintEnabled;
}

void QWaylandSurfaceItem::setPaintEnabled(bool enabled)
{
    m_paintEnabled = enabled;
    update();
}

void QWaylandSurfaceItem::updateTexture()
{
    ensureProvider();
    QSGTexture *texture = m_provider->t;
    if (m_damaged) {
        m_damaged = false;
        QSGTexture *oldTexture = texture;
        if (m_surface->type() == QWaylandSurface::Texture) {
            QOpenGLContext *context = QOpenGLContext::currentContext();
            QQuickWindow::CreateTextureOptions opt = 0;
            if (useTextureAlpha()) {
                opt |= QQuickWindow::TextureHasAlphaChannel;
            }
            texture = window()->createTextureFromId(m_surface->texture(context), m_surface->size(), opt);
        } else {
            texture = window()->createTextureFromImage(m_surface->image());
        }
        texture->bind();
        delete oldTexture;
    }

    m_provider->t = texture;
    emit m_provider->textureChanged();
    m_provider->smooth = smooth();
}

QSGNode *QWaylandSurfaceItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
    if (!m_surface) {
        delete oldNode;
        return 0;
    }

    updateTexture();
    if (!m_provider->t || !m_paintEnabled) {
        delete oldNode;
        return 0;
    }

    QWaylandSurfaceNode *node = static_cast<QWaylandSurfaceNode *>(oldNode);

    if (!node) {
        node = new QWaylandSurfaceNode(this);
    }

    node->updateTexture();

    if (surface()->isYInverted()) {
        node->setRect(0, height(), width(), -height());
    } else {
        node->setRect(0, 0, width(), height());
    }

    node->setTextureUpdated(true);

    return node;
}

void QWaylandSurfaceItem::setUseTextureAlpha(bool useTextureAlpha)
{
    m_useTextureAlpha = useTextureAlpha;

    if ((flags() & ItemHasContents) != 0) {
        update();
    }
}

void QWaylandSurfaceItem::setClientRenderingEnabled(bool enabled)
{
    if (m_clientRenderingEnabled != enabled) {
        m_clientRenderingEnabled = enabled;

        if (m_surface) {
            m_surface->sendOnScreenVisibilityChange(enabled);
        }

        emit clientRenderingEnabledChanged();
    }
}

void QWaylandSurfaceItem::setTouchEventsEnabled(bool enabled)
{
    if (m_touchEventsEnabled != enabled) {
        m_touchEventsEnabled = enabled;
        emit touchEventsEnabledChanged();
    }
}

void QWaylandSurfaceItem::setResizeSurfaceToItem(bool enabled)
{
    if (m_resizeSurfaceToItem != enabled) {
        m_resizeSurfaceToItem = enabled;
        emit resizeSurfaceToItemChanged();
    }
}

#include "qwaylandsurfaceitem.moc"

QT_END_NAMESPACE
<|endoftext|>


<commit_before>#pragma once

#include <array>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>

#include <boost/algorithm/string.hpp>
#include <boost/optional.hpp>
#include <boost/variant.hpp>

#include <blackhole/detail/config/noexcept.hpp>

namespace blackhole {

namespace formatter {

namespace string {

namespace parser {

class error_t : public std::runtime_error {
    const uint pos;
    const std::string inspect;

public:
    error_t(uint pos, const std::string& pattern, const std::string& reason) :
        std::runtime_error("parser error: " + reason),
        pos(pos),
        inspect(
            "parser error: " +  reason + "\n" +
            pattern + "\n" +
            std::string(pos, '~') + "^"
        )
    {}

    ~error_t() BLACKHOLE_NOEXCEPT {}

    std::string detail() const {
        return inspect;
    }
};

class broken_t : public error_t {
public:
    broken_t(uint pos, const std::string& pattern) :
        error_t(pos, pattern, "broken parser")
    {}
};

class exhausted_t : public error_t {
public:
    exhausted_t(uint pos, const std::string& pattern) :
        error_t(pos, pattern, "exhausted state")
    {}
};

class illformed_t : public error_t {
public:
    illformed_t(uint pos, const std::string& pattern) :
        error_t(pos, pattern, "illformed pattern")
    {}
};

class invalid_placeholder_t : public error_t {
public:
    invalid_placeholder_t(uint pos, const std::string& pattern) :
        error_t(pos, pattern, "invalid placeholder name (only [a-zA-Z0-9] allowed)")
    {}
};

}

struct literal_t {
    std::string value;
};

namespace placeholder {

struct required_t {
    std::string name;
};

struct optional_t {
    std::string name;
    std::string prefix;
    std::string suffix;
};

struct variadic_t {
    struct key_t {};
    struct value_t {};

    typedef boost::variant<
        literal_t,
        key_t,
        value_t
    > pattern_t;

    std::string prefix;
    std::string suffix;
    std::vector<pattern_t> pattern;
    std::string separator;

    variadic_t() :
        pattern(default_pattern()),
        separator(", ")
    {}

private:
    static
    std::vector<pattern_t>
    default_pattern() {
        return std::vector<pattern_t>({ key_t(), literal_t{ ": " }, value_t() });
    }
};

} // namespace placeholder

typedef boost::variant<
    literal_t,
    placeholder::required_t,
    placeholder::optional_t,
    placeholder::variadic_t
> token_t;

static const std::array<char, 2> PH_BEGIN = {{ '%', '(' }};
static const std::array<char, 2> PH_END   = {{ ')', 's' }};
static const std::array<char, 3> PH_VARIADIC = {{ '.', '.', '.' }};

class parser_t {
    enum state_t {
        whatever,
        literal,
        placeholder,
        broken
    };

    std::string pattern;
    std::string::const_iterator pos;
    const std::string::const_iterator begin;
    const std::string::const_iterator end;
    state_t state;

public:
    parser_t(std::string pattern) :
        pattern(std::move(pattern)),
        pos(this->pattern.begin()),
        begin(this->pattern.begin()),
        end(this->pattern.end()),
        state(whatever)
    {}

    boost::optional<token_t>
    next() {
        if (state == broken) {
            throw_<parser::broken_t>();
        }

        if (pos == end) {
            return boost::optional<token_t>();
        }

        switch (state) {
        case whatever:
            return parse_whatever();
        case literal:
            return parse_literal();
        case placeholder:
            return parse_placeholder();
        case broken:
            throw_<parser::broken_t>();
        default:
            BOOST_ASSERT(false);
        }
    }

private:
    boost::optional<token_t>
    parse_whatever() {
        if (starts_with(pos, end, PH_BEGIN)) {
            pos += PH_BEGIN.size();
            state = placeholder;
        } else {
            state = literal;
        }

        return next();
    }

    token_t
    parse_literal() {
        literal_t literal;

        while (pos != end) {
            if (starts_with(pos, end, PH_BEGIN)) {
                pos += PH_BEGIN.size();
                state = placeholder;
                return literal;
            }

            literal.value.push_back(*pos);
            pos++;
        }

        return literal;
    }

    token_t
    parse_placeholder() {
        if (starts_with(pos, end, PH_VARIADIC)) {
            pos += PH_VARIADIC.size();
            return parse_variadic();
        }

        std::string name;
        while (pos != end) {
            const char ch = *pos;

            if (std::isalpha(ch) || std::isdigit(ch)) {
                name.push_back(ch);
            } else {
                if (ch == ':') {
                    pos++;
                    return parse_optional(name);
                } else if (starts_with(pos, end, PH_END)) {
                    pos += PH_END.size();
                    state = whatever;
                    return placeholder::required_t { name };
                } else if (ch == ')' && std::next(pos) == end) {
                    throw_<parser::illformed_t>();
                } else {
                    throw_<parser::invalid_placeholder_t>();
                }
            }

            pos++;
        }

        throw_<parser::illformed_t>();
    }

    placeholder::optional_t
    parse_optional(std::string name) {
        placeholder::optional_t ph { std::move(name), "", "" };
        std::tie(ph.prefix, std::ignore) = parse({ ":" });
        std::tie(ph.suffix, std::ignore) = parse({ ")s" });
        state = whatever;
        return ph;
    }

    placeholder::variadic_t
    parse_variadic() {
        if (pos == end) {
            throw_<parser::illformed_t>();
        } else {
            placeholder::variadic_t ph;
            if (*pos == '[') {
                pos++;

                std::string pattern;
                std::tie(pattern, std::ignore) = parse({ "]" });
                parse_variadic_pattern(ph, pattern);
                if (starts_with(pos, end, PH_END)) {
                    pos += PH_END.size();
                    state = whatever;
                    return ph;
                } else if (*pos == ':') {
                    pos++;
                    parse_variadic_options(ph);
                    state = whatever;
                    return ph;
                } else {
                    throw_<parser::illformed_t>();
                }
            } else if (*pos == ':') {
                pos++;
                placeholder::variadic_t ph;
                parse_variadic_options(ph);
                state = whatever;
                return ph;
            } else if (starts_with(pos, end, PH_END)) {
                pos += PH_END.size();
                state = whatever;
                return placeholder::variadic_t();
            } else if (is_variadic_legacy(*pos)) {
                std::cout << "Warning: using legacy '"
                          << *pos
                          << "' character in variadic placeholder is deprecated"
                          << std::endl;

                while (is_variadic_legacy(*pos)) {
                    pos++;
                }

                if (starts_with(pos, end, PH_END)) {
                    pos += PH_END.size();
                    parse_variadic_pattern(ph, "'%k': %v");
                    state = whatever;
                    return ph;
                } else {
                    throw_<parser::illformed_t>();
                }
            }
        }

        throw_<parser::illformed_t>();
    }

    static
    bool
    is_variadic_legacy(char ch) {
        return ch == 'L' || ch == 'E' || ch == 'G' || ch == 'T' || ch == 'U';
    }

    static
    void
    parse_variadic_pattern(placeholder::variadic_t& ph, const std::string& pattern) {
        ph.pattern.clear();

        std::string literal;
        auto it = pattern.begin();
        auto end = pattern.end();
        for (; it != end; ++it) {
            if (starts_with(it, end, "%k")) {
                it++;

                if (!literal.empty()) {
                    ph.pattern.push_back(literal_t{ literal });
                    literal.clear();
                }
                ph.pattern.push_back(placeholder::variadic_t::key_t());
                continue;
            } else if (starts_with(it, end, "%v")) {
                it++;

                if (!literal.empty()) {
                    ph.pattern.push_back(literal_t{ literal });
                    literal.clear();
                }
                ph.pattern.push_back(placeholder::variadic_t::value_t());
                continue;
            }
            literal.push_back(*it);
        }

        if (!literal.empty()) {
            ph.pattern.push_back(literal_t{ literal });
        }
    }

    void
    parse_variadic_options(placeholder::variadic_t& ph) {
        std::tie(ph.prefix, std::ignore) = parse({ ":" });
        std::string breaker;
        std::tie(ph.suffix, breaker) = parse({ ":", ")s" });
        if (breaker == ":") {
            std::tie(ph.separator, std::ignore) = parse({ ")s" });
        }
    }

    std::tuple<std::string, std::string>
    parse(std::initializer_list<std::string> breakers,
          std::function<int(int)> match = ::isprint) {
        std::string result;
        bool escaped = false;
        while (pos != end) {
            const char ch = *pos;
            if (!match(ch)) {
                throw_<parser::illformed_t>();
            }

            if (ch == '\\') {
                pos++;
                escaped = true;
                continue;
            }

            bool matched = false;
            std::string breaker;
            for (auto it = breakers.begin(); it != breakers.end(); ++it) {
                if (starts_with(pos, end, *it)) {
                    matched = true;
                    breaker = *it;
                    break;
                }
            }

            if (matched && !escaped) {
                pos += breaker.size();
                return std::make_tuple(result, breaker);
            }

            result.push_back(ch);
            escaped = false;
            pos++;
        }

        throw_<parser::illformed_t>();
    }

private:
    template<class Exception, class... Args>
    __attribute__((noreturn))
    void throw_(Args&&... args) {
        state = broken;
        throw Exception(
            std::distance(begin, pos),
            std::string(begin, end),
            std::forward<Args>(args)...
        );
    }

    template<typename Iterator, class Range>
    static
    inline
    bool
    starts_with(Iterator first, Iterator last, const Range& range) {
        return boost::starts_with(
            boost::make_iterator_range(first, last),
            range
        );
    }
};

} // namespace string

} // namespace formatter

} // namespace blackhole
<commit_msg>[GCC 4.4] Added unreachable code to satisfy GCC 4.4.<commit_after>#pragma once

#include <array>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>

#include <boost/algorithm/string.hpp>
#include <boost/optional.hpp>
#include <boost/variant.hpp>

#include <blackhole/detail/config/noexcept.hpp>

namespace blackhole {

namespace formatter {

namespace string {

namespace parser {

class error_t : public std::runtime_error {
    const uint pos;
    const std::string inspect;

public:
    error_t(uint pos, const std::string& pattern, const std::string& reason) :
        std::runtime_error("parser error: " + reason),
        pos(pos),
        inspect(
            "parser error: " +  reason + "\n" +
            pattern + "\n" +
            std::string(pos, '~') + "^"
        )
    {}

    ~error_t() BLACKHOLE_NOEXCEPT {}

    std::string detail() const {
        return inspect;
    }
};

class broken_t : public error_t {
public:
    broken_t(uint pos, const std::string& pattern) :
        error_t(pos, pattern, "broken parser")
    {}
};

class exhausted_t : public error_t {
public:
    exhausted_t(uint pos, const std::string& pattern) :
        error_t(pos, pattern, "exhausted state")
    {}
};

class illformed_t : public error_t {
public:
    illformed_t(uint pos, const std::string& pattern) :
        error_t(pos, pattern, "illformed pattern")
    {}
};

class invalid_placeholder_t : public error_t {
public:
    invalid_placeholder_t(uint pos, const std::string& pattern) :
        error_t(pos, pattern, "invalid placeholder name (only [a-zA-Z0-9] allowed)")
    {}
};

}

struct literal_t {
    std::string value;
};

namespace placeholder {

struct required_t {
    std::string name;
};

struct optional_t {
    std::string name;
    std::string prefix;
    std::string suffix;
};

struct variadic_t {
    struct key_t {};
    struct value_t {};

    typedef boost::variant<
        literal_t,
        key_t,
        value_t
    > pattern_t;

    std::string prefix;
    std::string suffix;
    std::vector<pattern_t> pattern;
    std::string separator;

    variadic_t() :
        pattern(default_pattern()),
        separator(", ")
    {}

private:
    static
    std::vector<pattern_t>
    default_pattern() {
        return std::vector<pattern_t>({ key_t(), literal_t{ ": " }, value_t() });
    }
};

} // namespace placeholder

typedef boost::variant<
    literal_t,
    placeholder::required_t,
    placeholder::optional_t,
    placeholder::variadic_t
> token_t;

static const std::array<char, 2> PH_BEGIN = {{ '%', '(' }};
static const std::array<char, 2> PH_END   = {{ ')', 's' }};
static const std::array<char, 3> PH_VARIADIC = {{ '.', '.', '.' }};

class parser_t {
    enum state_t {
        whatever,
        literal,
        placeholder,
        broken
    };

    std::string pattern;
    std::string::const_iterator pos;
    const std::string::const_iterator begin;
    const std::string::const_iterator end;
    state_t state;

public:
    parser_t(std::string pattern) :
        pattern(std::move(pattern)),
        pos(this->pattern.begin()),
        begin(this->pattern.begin()),
        end(this->pattern.end()),
        state(whatever)
    {}

    boost::optional<token_t>
    next() {
        if (state == broken) {
            throw_<parser::broken_t>();
        }

        if (pos == end) {
            return boost::optional<token_t>();
        }

        switch (state) {
        case whatever:
            return parse_whatever();
        case literal:
            return parse_literal();
        case placeholder:
            return parse_placeholder();
        case broken:
            throw_<parser::broken_t>();
        default:
            BOOST_ASSERT(false);
        }

        throw_<parser::broken_t>();
    }

private:
    boost::optional<token_t>
    parse_whatever() {
        if (starts_with(pos, end, PH_BEGIN)) {
            pos += PH_BEGIN.size();
            state = placeholder;
        } else {
            state = literal;
        }

        return next();
    }

    token_t
    parse_literal() {
        literal_t literal;

        while (pos != end) {
            if (starts_with(pos, end, PH_BEGIN)) {
                pos += PH_BEGIN.size();
                state = placeholder;
                return literal;
            }

            literal.value.push_back(*pos);
            pos++;
        }

        return literal;
    }

    token_t
    parse_placeholder() {
        if (starts_with(pos, end, PH_VARIADIC)) {
            pos += PH_VARIADIC.size();
            return parse_variadic();
        }

        std::string name;
        while (pos != end) {
            const char ch = *pos;

            if (std::isalpha(ch) || std::isdigit(ch)) {
                name.push_back(ch);
            } else {
                if (ch == ':') {
                    pos++;
                    return parse_optional(name);
                } else if (starts_with(pos, end, PH_END)) {
                    pos += PH_END.size();
                    state = whatever;
                    return placeholder::required_t { name };
                } else if (ch == ')' && std::next(pos) == end) {
                    throw_<parser::illformed_t>();
                } else {
                    throw_<parser::invalid_placeholder_t>();
                }
            }

            pos++;
        }

        throw_<parser::illformed_t>();
    }

    placeholder::optional_t
    parse_optional(std::string name) {
        placeholder::optional_t ph { std::move(name), "", "" };
        std::tie(ph.prefix, std::ignore) = parse({ ":" });
        std::tie(ph.suffix, std::ignore) = parse({ ")s" });
        state = whatever;
        return ph;
    }

    placeholder::variadic_t
    parse_variadic() {
        if (pos == end) {
            throw_<parser::illformed_t>();
        } else {
            placeholder::variadic_t ph;
            if (*pos == '[') {
                pos++;

                std::string pattern;
                std::tie(pattern, std::ignore) = parse({ "]" });
                parse_variadic_pattern(ph, pattern);
                if (starts_with(pos, end, PH_END)) {
                    pos += PH_END.size();
                    state = whatever;
                    return ph;
                } else if (*pos == ':') {
                    pos++;
                    parse_variadic_options(ph);
                    state = whatever;
                    return ph;
                } else {
                    throw_<parser::illformed_t>();
                }
            } else if (*pos == ':') {
                pos++;
                placeholder::variadic_t ph;
                parse_variadic_options(ph);
                state = whatever;
                return ph;
            } else if (starts_with(pos, end, PH_END)) {
                pos += PH_END.size();
                state = whatever;
                return placeholder::variadic_t();
            } else if (is_variadic_legacy(*pos)) {
                std::cout << "Warning: using legacy '"
                          << *pos
                          << "' character in variadic placeholder is deprecated"
                          << std::endl;

                while (is_variadic_legacy(*pos)) {
                    pos++;
                }

                if (starts_with(pos, end, PH_END)) {
                    pos += PH_END.size();
                    parse_variadic_pattern(ph, "'%k': %v");
                    state = whatever;
                    return ph;
                } else {
                    throw_<parser::illformed_t>();
                }
            }
        }

        throw_<parser::illformed_t>();
    }

    static
    bool
    is_variadic_legacy(char ch) {
        return ch == 'L' || ch == 'E' || ch == 'G' || ch == 'T' || ch == 'U';
    }

    static
    void
    parse_variadic_pattern(placeholder::variadic_t& ph, const std::string& pattern) {
        ph.pattern.clear();

        std::string literal;
        auto it = pattern.begin();
        auto end = pattern.end();
        for (; it != end; ++it) {
            if (starts_with(it, end, "%k")) {
                it++;

                if (!literal.empty()) {
                    ph.pattern.push_back(literal_t{ literal });
                    literal.clear();
                }
                ph.pattern.push_back(placeholder::variadic_t::key_t());
                continue;
            } else if (starts_with(it, end, "%v")) {
                it++;

                if (!literal.empty()) {
                    ph.pattern.push_back(literal_t{ literal });
                    literal.clear();
                }
                ph.pattern.push_back(placeholder::variadic_t::value_t());
                continue;
            }
            literal.push_back(*it);
        }

        if (!literal.empty()) {
            ph.pattern.push_back(literal_t{ literal });
        }
    }

    void
    parse_variadic_options(placeholder::variadic_t& ph) {
        std::tie(ph.prefix, std::ignore) = parse({ ":" });
        std::string breaker;
        std::tie(ph.suffix, breaker) = parse({ ":", ")s" });
        if (breaker == ":") {
            std::tie(ph.separator, std::ignore) = parse({ ")s" });
        }
    }

    std::tuple<std::string, std::string>
    parse(std::initializer_list<std::string> breakers,
          std::function<int(int)> match = ::isprint) {
        std::string result;
        bool escaped = false;
        while (pos != end) {
            const char ch = *pos;
            if (!match(ch)) {
                throw_<parser::illformed_t>();
            }

            if (ch == '\\') {
                pos++;
                escaped = true;
                continue;
            }

            bool matched = false;
            std::string breaker;
            for (auto it = breakers.begin(); it != breakers.end(); ++it) {
                if (starts_with(pos, end, *it)) {
                    matched = true;
                    breaker = *it;
                    break;
                }
            }

            if (matched && !escaped) {
                pos += breaker.size();
                return std::make_tuple(result, breaker);
            }

            result.push_back(ch);
            escaped = false;
            pos++;
        }

        throw_<parser::illformed_t>();
    }

private:
    template<class Exception, class... Args>
    __attribute__((noreturn))
    void throw_(Args&&... args) {
        state = broken;
        throw Exception(
            std::distance(begin, pos),
            std::string(begin, end),
            std::forward<Args>(args)...
        );
    }

    template<typename Iterator, class Range>
    static
    inline
    bool
    starts_with(Iterator first, Iterator last, const Range& range) {
        return boost::starts_with(
            boost::make_iterator_range(first, last),
            range
        );
    }
};

} // namespace string

} // namespace formatter

} // namespace blackhole
<|endoftext|>


<commit_before>/*
    Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>

    This file is part of the KDE project

    This library is free software you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    aint with this library see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include "KmlElementDictionary.h"

namespace Marble
{

// One static list of all tag names, to avoid string comparisons all-over-the-place
namespace kml
{

const char* kmlTag_nameSpace20 = "http://earth.google.com/kml/2.0";
const char* kmlTag_nameSpace21 = "http://earth.google.com/kml/2.1";
const char* kmlTag_nameSpace22 = "http://earth.google.com/kml/2.2";

const char* kmlTag_address = "address";
const char* kmlTag_AddressDetails = "AddressDetails";
const char* kmlTag_altitude = "altitude";
const char* kmlTag_altitudeMode = "altitudeMode";
const char* kmlTag_BalloonStyle = "BalloonStyle";
const char* kmlTag_begin = "begin";
const char* kmlTag_bgColor = "bgColor";
const char* kmlTag_Change = "Change";
const char* kmlTag_code = "code";
const char* kmlTag_color = "color";
const char* kmlTag_colorMode = "colorMode";
const char* kmlTag_ColorStyle = "ColorStyle";
const char* kmlTag_Container = "Container";
const char* kmlTag_cookie = "cookie";
const char* kmlTag_coordinates = "coordinates";
const char* kmlTag_Create = "Create";
const char* kmlTag_Delete = "Delete";
const char* kmlTag_description = "description";
const char* kmlTag_Document = "Document";
const char* kmlTag_drawOrder = "drawOrder";
const char* kmlTag_east = "east";
const char* kmlTag_end = "end";
const char* kmlTag_expires = "expires";
const char* kmlTag_extrude = "extrude";
const char* kmlTag_Feature = "Feature";
const char* kmlTag_fill = "fill";
const char* kmlTag_flyToView = "flyToView";
const char* kmlTag_Folder = "Folder";
const char* kmlTag_geomColor = "geomColor";
const char* kmlTag_Geometry = "Geometry";
const char* kmlTag_GeometryCollection = "GeometryCollection";
const char* kmlTag_geomScale = "geomScale";
const char* kmlTag_GroundOverlay = "GroundOverlay";
const char* kmlTag_h = 'h';
const char* kmlTag_heading = "heading";
const char* kmlTag_href = "href";
const char* kmlTag_hotSpot = "hotSpot";
const char* kmlTag_httpQuery = "httpQuery";
const char* kmlTag_Icon = "Icon";
const char* kmlTag_IconStyle = "IconStyle";
const char* kmlTag_innerBoundaryIs = "innerBoundaryIs";
const char* kmlTag_ItemIcon = "ItemIcon";
const char* kmlTag_key = "key";
const char* kmlTag_kml = "kml";
const char* kmlTag_labelColor = "labelColor";
const char* kmlTag_LabelStyle = "LabelStyle";
const char* kmlTag_latitude = "latitude";
const char* kmlTag_LatLonAltBox = "LatLonAltBox";
const char* kmlTag_LatLonBox = "LatLonBox";
const char* kmlTag_LinearRing = "LinearRing";
const char* kmlTag_LineString = "LineString";
const char* kmlTag_LineStyle = "LineStyle";
const char* kmlTag_Link = "Link";
const char* kmlTag_linkDescription = "linkDescription";
const char* kmlTag_linkName = "linkName";
const char* kmlTag_linkSnippet = "linkSnippet";
const char* kmlTag_listItemType = "listItemType";
const char* kmlTag_ListStyle = "ListStyle";
const char* kmlTag_Location = "Location";
const char* kmlTag_Lod = "Lod";
const char* kmlTag_longitude = "longitude";
const char* kmlTag_LookAt = "LookAt";
const char* kmlTag_maxAltitude = "maxAltitude";
const char* kmlTag_maxFadeExtent = "maxFadeExtent";
const char* kmlTag_maxLodPixels = "maxLodPixels";
const char* kmlTag_message = "message";
const char* kmlTag_Metadata = "Metadata";
const char* kmlTag_minAltitude = "minAltitude";
const char* kmlTag_minFadeExtent = "minFadeExtent";
const char* kmlTag_minLodPixels = "minLodPixels";
const char* kmlTag_minRefreshPeriod = "minRefreshPeriod";
const char* kmlTag_Model = "Model";
const char* kmlTag_MultiGeometry = "MultiGeometry";
const char* kmlTag_name = "name";
const char* kmlTag_NetworkLink = "NetworkLink";
const char* kmlTag_NetworkLinkControl = "NetworkLinkControl";
const char* kmlTag_north = "north";
const char* kmlTag_Object = "Object";
const char* kmlTag_ObjArrayField = "ObjArrayField";
const char* kmlTag_ObjField = "ObjField";
const char* kmlTag_open = "open";
const char* kmlTag_Orientation = "Orientation";
const char* kmlTag_outerBoundaryIs = "outerBoundaryIs";
const char* kmlTag_outline = "outline";
const char* kmlTag_Overlay = "Overlay";
const char* kmlTag_overlayXY = "overlayXY";
const char* kmlTag_Pair = "Pair";
const char* kmlTag_phoneNumber = "phoneNumber";
const char* kmlTag_Placemark = "Placemark";
const char* kmlTag_Point = "Point";
const char* kmlTag_Polygon = "Polygon";
const char* kmlTag_PolyStyle = "PolyStyle";
const char* kmlTag_range = "range";
const char* kmlTag_refreshInterval = "refreshInterval";
const char* kmlTag_refreshMode = "refreshMode";
const char* kmlTag_refreshVisibility = "refreshVisibility";
const char* kmlTag_Region = "Region";
const char* kmlTag_request = "request";
const char* kmlTag_Response = "Response";
const char* kmlTag_roll = "roll";
const char* kmlTag_rotation = "rotation";
const char* kmlTag_rotationXY = "rotationXY";
const char* kmlTag_Scale = "Scale";
const char* kmlTag_scale = "scale";
const char* kmlTag_Schema = "Schema";
const char* kmlTag_SchemaField = "SchemaField";
const char* kmlTag_ScreenOverlay = "ScreenOverlay";
const char* kmlTag_screenXY = "screenXY";
const char* kmlTag_SimpleArrayField = "SimpleArrayField";
const char* kmlTag_SimpleField = "SimpleField";
const char* kmlTag_size = "size";
const char* kmlTag_Snippet = "Snippet";
const char* kmlTag_south = "south";
const char* kmlTag_state = "state";
const char* kmlTag_Status = "Status";
const char* kmlTag_Style = "Style";
const char* kmlTag_StyleMap = "StyleMap";
const char* kmlTag_StyleSelector = "StyleSelector";
const char* kmlTag_styleUrl = "styleUrl";
const char* kmlTag_targetHref = "targetHref";
const char* kmlTag_tessellate = "tessellate";
const char* kmlTag_text = "text";
const char* kmlTag_textcolor = "textcolor";
const char* kmlTag_tilt = "tilt";
const char* kmlTag_TimePrimitive = "TimePrimitive";
const char* kmlTag_TimeSpan = "TimeSpan";
const char* kmlTag_TimeStamp = "TimeStamp";
const char* kmlTag_Update = "Update";
const char* kmlTag_Url = "Url";
const char* kmlTag_viewBoundScale = "viewBoundScale";
const char* kmlTag_viewFormat = "viewFormat";
const char* kmlTag_viewRefreshMode = "viewRefreshMode";
const char* kmlTag_viewRefreshTime = "viewRefreshTime";
const char* kmlTag_visibility = "visibility";
const char* kmlTag_w = 'w';
const char* kmlTag_west = "west";
const char* kmlTag_when = "when";
const char* kmlTag_width = "width";
const char* kmlTag_x = 'x';
const char* kmlTag_y = 'y';
#ifdef KML_LAZY_IMP
 const char* kmlTag_MarblePlacemark = "MarblePlacemark";
 const char* kmlTag_area = "area";
 const char* kmlTag_pop = "pop";
 const char* kmlTag_role = "role";
 const char* kmlTag_CountryNameCode = "CountryNameCode";
 const char* kmlTag_countrycode = "countrycode";
#endif // KML_LAZY_IMP
}

}
<commit_msg>Revert fix by hdevalence CCMAIL: hdevalence@gmail.com<commit_after>/*
    Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>

    This file is part of the KDE project

    This library is free software you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    aint with this library see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include "KmlElementDictionary.h"

namespace Marble
{

// One static list of all tag names, to avoid string comparisons all-over-the-place
namespace kml
{

const char* kmlTag_nameSpace20 = "http://earth.google.com/kml/2.0";
const char* kmlTag_nameSpace21 = "http://earth.google.com/kml/2.1";
const char* kmlTag_nameSpace22 = "http://earth.google.com/kml/2.2";

const char* kmlTag_address = "address";
const char* kmlTag_AddressDetails = "AddressDetails";
const char* kmlTag_altitude = "altitude";
const char* kmlTag_altitudeMode = "altitudeMode";
const char* kmlTag_BalloonStyle = "BalloonStyle";
const char* kmlTag_begin = "begin";
const char* kmlTag_bgColor = "bgColor";
const char* kmlTag_Change = "Change";
const char* kmlTag_code = "code";
const char* kmlTag_color = "color";
const char* kmlTag_colorMode = "colorMode";
const char* kmlTag_ColorStyle = "ColorStyle";
const char* kmlTag_Container = "Container";
const char* kmlTag_cookie = "cookie";
const char* kmlTag_coordinates = "coordinates";
const char* kmlTag_Create = "Create";
const char* kmlTag_Delete = "Delete";
const char* kmlTag_description = "description";
const char* kmlTag_Document = "Document";
const char* kmlTag_drawOrder = "drawOrder";
const char* kmlTag_east = "east";
const char* kmlTag_end = "end";
const char* kmlTag_expires = "expires";
const char* kmlTag_extrude = "extrude";
const char* kmlTag_Feature = "Feature";
const char* kmlTag_fill = "fill";
const char* kmlTag_flyToView = "flyToView";
const char* kmlTag_Folder = "Folder";
const char* kmlTag_geomColor = "geomColor";
const char* kmlTag_Geometry = "Geometry";
const char* kmlTag_GeometryCollection = "GeometryCollection";
const char* kmlTag_geomScale = "geomScale";
const char* kmlTag_GroundOverlay = "GroundOverlay";
const char* kmlTag_h = "h";
const char* kmlTag_heading = "heading";
const char* kmlTag_href = "href";
const char* kmlTag_hotSpot = "hotSpot";
const char* kmlTag_httpQuery = "httpQuery";
const char* kmlTag_Icon = "Icon";
const char* kmlTag_IconStyle = "IconStyle";
const char* kmlTag_innerBoundaryIs = "innerBoundaryIs";
const char* kmlTag_ItemIcon = "ItemIcon";
const char* kmlTag_key = "key";
const char* kmlTag_kml = "kml";
const char* kmlTag_labelColor = "labelColor";
const char* kmlTag_LabelStyle = "LabelStyle";
const char* kmlTag_latitude = "latitude";
const char* kmlTag_LatLonAltBox = "LatLonAltBox";
const char* kmlTag_LatLonBox = "LatLonBox";
const char* kmlTag_LinearRing = "LinearRing";
const char* kmlTag_LineString = "LineString";
const char* kmlTag_LineStyle = "LineStyle";
const char* kmlTag_Link = "Link";
const char* kmlTag_linkDescription = "linkDescription";
const char* kmlTag_linkName = "linkName";
const char* kmlTag_linkSnippet = "linkSnippet";
const char* kmlTag_listItemType = "listItemType";
const char* kmlTag_ListStyle = "ListStyle";
const char* kmlTag_Location = "Location";
const char* kmlTag_Lod = "Lod";
const char* kmlTag_longitude = "longitude";
const char* kmlTag_LookAt = "LookAt";
const char* kmlTag_maxAltitude = "maxAltitude";
const char* kmlTag_maxFadeExtent = "maxFadeExtent";
const char* kmlTag_maxLodPixels = "maxLodPixels";
const char* kmlTag_message = "message";
const char* kmlTag_Metadata = "Metadata";
const char* kmlTag_minAltitude = "minAltitude";
const char* kmlTag_minFadeExtent = "minFadeExtent";
const char* kmlTag_minLodPixels = "minLodPixels";
const char* kmlTag_minRefreshPeriod = "minRefreshPeriod";
const char* kmlTag_Model = "Model";
const char* kmlTag_MultiGeometry = "MultiGeometry";
const char* kmlTag_name = "name";
const char* kmlTag_NetworkLink = "NetworkLink";
const char* kmlTag_NetworkLinkControl = "NetworkLinkControl";
const char* kmlTag_north = "north";
const char* kmlTag_Object = "Object";
const char* kmlTag_ObjArrayField = "ObjArrayField";
const char* kmlTag_ObjField = "ObjField";
const char* kmlTag_open = "open";
const char* kmlTag_Orientation = "Orientation";
const char* kmlTag_outerBoundaryIs = "outerBoundaryIs";
const char* kmlTag_outline = "outline";
const char* kmlTag_Overlay = "Overlay";
const char* kmlTag_overlayXY = "overlayXY";
const char* kmlTag_Pair = "Pair";
const char* kmlTag_phoneNumber = "phoneNumber";
const char* kmlTag_Placemark = "Placemark";
const char* kmlTag_Point = "Point";
const char* kmlTag_Polygon = "Polygon";
const char* kmlTag_PolyStyle = "PolyStyle";
const char* kmlTag_range = "range";
const char* kmlTag_refreshInterval = "refreshInterval";
const char* kmlTag_refreshMode = "refreshMode";
const char* kmlTag_refreshVisibility = "refreshVisibility";
const char* kmlTag_Region = "Region";
const char* kmlTag_request = "request";
const char* kmlTag_Response = "Response";
const char* kmlTag_roll = "roll";
const char* kmlTag_rotation = "rotation";
const char* kmlTag_rotationXY = "rotationXY";
const char* kmlTag_Scale = "Scale";
const char* kmlTag_scale = "scale";
const char* kmlTag_Schema = "Schema";
const char* kmlTag_SchemaField = "SchemaField";
const char* kmlTag_ScreenOverlay = "ScreenOverlay";
const char* kmlTag_screenXY = "screenXY";
const char* kmlTag_SimpleArrayField = "SimpleArrayField";
const char* kmlTag_SimpleField = "SimpleField";
const char* kmlTag_size = "size";
const char* kmlTag_Snippet = "Snippet";
const char* kmlTag_south = "south";
const char* kmlTag_state = "state";
const char* kmlTag_Status = "Status";
const char* kmlTag_Style = "Style";
const char* kmlTag_StyleMap = "StyleMap";
const char* kmlTag_StyleSelector = "StyleSelector";
const char* kmlTag_styleUrl = "styleUrl";
const char* kmlTag_targetHref = "targetHref";
const char* kmlTag_tessellate = "tessellate";
const char* kmlTag_text = "text";
const char* kmlTag_textcolor = "textcolor";
const char* kmlTag_tilt = "tilt";
const char* kmlTag_TimePrimitive = "TimePrimitive";
const char* kmlTag_TimeSpan = "TimeSpan";
const char* kmlTag_TimeStamp = "TimeStamp";
const char* kmlTag_Update = "Update";
const char* kmlTag_Url = "Url";
const char* kmlTag_viewBoundScale = "viewBoundScale";
const char* kmlTag_viewFormat = "viewFormat";
const char* kmlTag_viewRefreshMode = "viewRefreshMode";
const char* kmlTag_viewRefreshTime = "viewRefreshTime";
const char* kmlTag_visibility = "visibility";
const char* kmlTag_w = "w";
const char* kmlTag_west = "west";
const char* kmlTag_when = "when";
const char* kmlTag_width = "width";
const char* kmlTag_x = "x";
const char* kmlTag_y = "y";
#ifdef KML_LAZY_IMP
 const char* kmlTag_MarblePlacemark = "MarblePlacemark";
 const char* kmlTag_area = "area";
 const char* kmlTag_pop = "pop";
 const char* kmlTag_role = "role";
 const char* kmlTag_CountryNameCode = "CountryNameCode";
 const char* kmlTag_countrycode = "countrycode";
#endif // KML_LAZY_IMP
}

}
<|endoftext|>


<commit_before>#include <ncurses.h>
#include <stdint.h>

#include "display/Screen.h"
#include "display/Window.h"
#include "map/Level.h"
#include "map/filters/DrunkardsWalkFilter.h"

int main()
{
	Screen screen;

	uint32_t screen_y = screen.getHeight();
	uint32_t screen_x = screen.getWidth();

	//Create a window for our map; window (and map) are double screen size)
	uint32_t map_y = screen_y * 2;
	uint32_t map_x = screen_x * 2;
	WINDOW* map = newwin(map_y, map_x, 0, 0);
	//Generate a map
	Level cave(map_y, map_x);
	DrunkardsWalkFilter walk;
	walk.setSeed(time(NULL));
	walk.apply(cave);
	//Now put the map into our map window
	for(uint32_t x = 0; x < cave.getWidth(); x++)
	{
		for(uint32_t y = 0; y < cave.getHeight(); y++)
		{
			mvwaddch(map, x+1, y, cave[x][y].getDisplay());
		}
	}

	//WINDOW* top = newwin(3, screen_x, 0, 0);
	Window top(screen_x, 3, 0, 0);
	WINDOW* left = newwin(screen_y-2, 20, 2, 0);
	//WINDOW* main = newwin(screen_y-2, screen_x-19, 2, 19);
	WINDOW* main = subwin(map, screen_y-3, screen_x-20, 3, 20);

	//wborder(top, '|', '|', '-', '-', '+', '+', '+', '+');
	wborder(left, '|', '|', '-', '-', '+', '+', '+', '+');
	//wborder(main, '|', '|', '-', '-', '+', '+', '+', '+');

	//mvwprintw(top, 0, 1, "Message Panel");
	mvwprintw(left, 0, 1, "Stat Panel");
	//mvwprintw(main, 0, 1, "Main Panel");

	//Center the map viewport
	uint32_t map_view_y = map_y/2 - (screen_y-3)/2;
	uint32_t map_view_x = map_x/2 - (screen_x-20)/2;
	uint32_t map_view_max_y = screen_y - 3;
	uint32_t map_view_max_x = screen_x - 20;
	mvderwin(main, map_view_y, map_view_x);

	//wrefresh(top);
	top.refresh();
	wrefresh(left);
	wrefresh(main);

	int ch;
	bool run = true;
	while(run)
	{
		ch = getch();

		switch(ch)
		{
			case KEY_UP:
				if(0 < map_view_y)
				{
					//mvwprintw(top, 1, 1, "Up");
					top.add(1, 1, "Up");
					map_view_y--;
				}
				break;
			case KEY_DOWN:
				if(map_view_max_y > map_view_y)
				{
					//mvwprintw(top, 1, 1, "Down");
					top.add(1, 1, "Down");
					map_view_y++;
				}
				break;
			case KEY_LEFT:
				if(0 < map_view_x)
				{
					//mvwprintw(top, 1, 1, "Left");
					top.add(1, 1, "Left");
					map_view_x--;
				}
				break;
			case KEY_RIGHT:
				if(map_view_max_x > map_view_x)
				{
					//mvwprintw(top, 1, 1, "Right");
					top.add(1, 1, "Right");
					map_view_x++;
				}
				break;
			case 'q':
			case 'Q':
				run = false;
				break;
		}

		mvderwin(main, map_view_y, map_view_x);
		wrefresh(main);
		//wrefresh(top);
		top.refresh();
	}
}
<commit_msg>Re-added "Message Panel" label to top window.<commit_after>#include <ncurses.h>
#include <stdint.h>

#include "display/Screen.h"
#include "display/Window.h"
#include "map/Level.h"
#include "map/filters/DrunkardsWalkFilter.h"

int main()
{
	Screen screen;

	uint32_t screen_y = screen.getHeight();
	uint32_t screen_x = screen.getWidth();

	//Create a window for our map; window (and map) are double screen size)
	uint32_t map_y = screen_y * 2;
	uint32_t map_x = screen_x * 2;
	WINDOW* map = newwin(map_y, map_x, 0, 0);
	//Generate a map
	Level cave(map_y, map_x);
	DrunkardsWalkFilter walk;
	walk.setSeed(time(NULL));
	walk.apply(cave);
	//Now put the map into our map window
	for(uint32_t x = 0; x < cave.getWidth(); x++)
	{
		for(uint32_t y = 0; y < cave.getHeight(); y++)
		{
			mvwaddch(map, x+1, y, cave[x][y].getDisplay());
		}
	}

	//WINDOW* top = newwin(3, screen_x, 0, 0);
	Window top(screen_x, 3, 0, 0);
	WINDOW* left = newwin(screen_y-2, 20, 2, 0);
	//WINDOW* main = newwin(screen_y-2, screen_x-19, 2, 19);
	WINDOW* main = subwin(map, screen_y-3, screen_x-20, 3, 20);

	//wborder(top, '|', '|', '-', '-', '+', '+', '+', '+');
	wborder(left, '|', '|', '-', '-', '+', '+', '+', '+');
	//wborder(main, '|', '|', '-', '-', '+', '+', '+', '+');

	//mvwprintw(top, 0, 1, "Message Panel");
	top.add(1, 0, "Message Panel");
	mvwprintw(left, 0, 1, "Stat Panel");
	//mvwprintw(main, 0, 1, "Main Panel");

	//Center the map viewport
	uint32_t map_view_y = map_y/2 - (screen_y-3)/2;
	uint32_t map_view_x = map_x/2 - (screen_x-20)/2;
	uint32_t map_view_max_y = screen_y - 3;
	uint32_t map_view_max_x = screen_x - 20;
	mvderwin(main, map_view_y, map_view_x);

	//wrefresh(top);
	top.refresh();
	wrefresh(left);
	wrefresh(main);

	int ch;
	bool run = true;
	while(run)
	{
		ch = getch();

		switch(ch)
		{
			case KEY_UP:
				if(0 < map_view_y)
				{
					//mvwprintw(top, 1, 1, "Up");
					top.add(1, 1, "Up");
					map_view_y--;
				}
				break;
			case KEY_DOWN:
				if(map_view_max_y > map_view_y)
				{
					//mvwprintw(top, 1, 1, "Down");
					top.add(1, 1, "Down");
					map_view_y++;
				}
				break;
			case KEY_LEFT:
				if(0 < map_view_x)
				{
					//mvwprintw(top, 1, 1, "Left");
					top.add(1, 1, "Left");
					map_view_x--;
				}
				break;
			case KEY_RIGHT:
				if(map_view_max_x > map_view_x)
				{
					//mvwprintw(top, 1, 1, "Right");
					top.add(1, 1, "Right");
					map_view_x++;
				}
				break;
			case 'q':
			case 'Q':
				run = false;
				break;
		}

		mvderwin(main, map_view_y, map_view_x);
		wrefresh(main);
		//wrefresh(top);
		top.refresh();
	}
}
<|endoftext|>


<commit_before>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2014 Klaus Post
    Copyright (C) 2014-2015 Pedro Côrte-Real
    Copyright (C) 2017 Roman Lebedev

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "decompressors/OlympusDecompressor.h"
#include "common/Common.h"                // for uint32, ushort16, uchar8
#include "common/Point.h"                 // for iPoint2D
#include "common/RawImage.h"              // for RawImage, RawImageData
#include "decoders/RawDecoderException.h" // for ThrowRDE
#include "io/BitPumpMSB.h"                // for BitPumpMSB
#include "io/ByteStream.h"                // for ByteStream
#include <algorithm>                      // for min
#include <array>                          // for array, array<>::value_type
#include <cassert>                        // for assert
#include <cmath>                          // for abs
#include <cstdlib>                        // for abs
#include <memory>                         // for unique_ptr
#include <type_traits>                    // for enable_if_t, is_integral

namespace {

// Normally, we'd just use std::signbit(int) here. But, some (non-conforming?)
// compilers do not provide that overload, so the code simply fails to compile.
// One could cast the int to the double, but at least right now that results
// in a horrible code. So let's just provide our own signbit(). It compiles to
// the exact same code as the std::signbit(int).
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
constexpr __attribute__((const)) bool SignBit(T x) {
  return x < 0;
}

} // namespace

namespace rawspeed {

OlympusDecompressor::OlympusDecompressor(const RawImage& img) : mRaw(img) {
  if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
      mRaw->getBpp() != 2)
    ThrowRDE("Unexpected component count / data type");

  const uint32 w = mRaw->dim.x;
  const uint32 h = mRaw->dim.y;

  if (w == 0 || h == 0 || w % 2 != 0 || w > 10400 || h > 7792)
    ThrowRDE("Unexpected image dimensions found: (%u; %u)", w, h);
}

/* This is probably the slowest decoder of them all.
 * I cannot see any way to effectively speed up the prediction
 * phase, which is by far the slowest part of this algorithm.
 * Also there is no way to multithread this code, since prediction
 * is based on the output of all previous pixel (bar the first four)
 */

void OlympusDecompressor::decompress(ByteStream input) const {
  assert(mRaw->dim.y > 0);
  assert(mRaw->dim.x > 0);
  assert(mRaw->dim.x % 2 == 0);

  uchar8* data = mRaw->getData();
  int pitch = mRaw->pitch;

  /* Build a table to quickly look up "high" value */
  std::unique_ptr<char[]> bittable(new char[4096]); // NOLINT

  for (int i = 0; i < 4096; i++) {
    int b = i;
    int high;
    for (high = 0; high < 12; high++)
      if ((b >> (11 - high)) & 1)
        break;
    bittable[i] = std::min(12, high);
  }

  input.skipBytes(7);
  BitPumpMSB bits(input);

  for (uint32 y = 0; y < static_cast<uint32>(mRaw->dim.y); y++) {
    std::array<std::array<int, 3>, 2> acarry{{}};

    auto* dest = reinterpret_cast<ushort16*>(&data[y * pitch]);
    bool y_border = y < 2;
    bool border = true;
    for (uint32 x = 0; x < static_cast<uint32>(mRaw->dim.x); x++) {
      int c = x & 1;

      std::array<int, 3>& carry = acarry[c];

      bits.fill();
      int i = 2 * (carry[2] < 3);
      int nbits;
      for (nbits = 2 + i; static_cast<ushort16>(carry[0]) >> (nbits + i);
           nbits++)
        ;

      int b = bits.peekBitsNoFill(15);
      int sign = (b >> 14) * -1;
      int low = (b >> 12) & 3;
      int high = bittable[b & 4095];

      // Skip bytes used above or read bits
      if (high == 12) {
        bits.skipBitsNoFill(15);
        high = bits.getBits(16 - nbits) >> 1;
      } else
        bits.skipBitsNoFill(high + 1 + 3);

      carry[0] = (high << nbits) | bits.getBits(nbits);
      int diff = (carry[0] ^ sign) + carry[1];
      carry[1] = (diff * 3 + carry[1]) >> 5;
      carry[2] = carry[0] > 16 ? 0 : carry[2] + 1;

      auto getLeft = [dest]() { return dest[-2]; };
      auto getUp = [dest, pitch]() { return dest[-pitch]; };
      auto getLeftUp = [dest, pitch]() { return dest[-pitch - 2]; };

      int pred;
      if (border) {
        if (y_border && x < 2)
          pred = 0;
        else {
          if (y_border)
            pred = getLeft();
          else {
            pred = getUp();
          }
        }
      } else {
        int left = getLeft();
        int up = getUp();
        int leftUp = getLeftUp();

        int leftMinusNw = left - leftUp;
        int upMinusNw = up - leftUp;

        // Check if sign is different, and they are both not zero
        if ((SignBit(leftMinusNw) ^ SignBit(upMinusNw)) &&
            (leftMinusNw != 0 && upMinusNw != 0)) {
          if (std::abs(leftMinusNw) > 32 || std::abs(upMinusNw) > 32)
            pred = left + upMinusNw;
          else
            pred = (left + up) >> 1;
        } else
          pred = std::abs(leftMinusNw) > std::abs(upMinusNw) ? left : up;
      }

      *dest = pred + ((diff * 4) | low);

      if (c)
        border = y_border;

      dest++;
    }
  }
}

} // namespace rawspeed
<commit_msg>OlympusDecompressor: simplify x/y border 'detection' logic<commit_after>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2014 Klaus Post
    Copyright (C) 2014-2015 Pedro Côrte-Real
    Copyright (C) 2017 Roman Lebedev

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "decompressors/OlympusDecompressor.h"
#include "common/Common.h"                // for uint32, ushort16, uchar8
#include "common/Point.h"                 // for iPoint2D
#include "common/RawImage.h"              // for RawImage, RawImageData
#include "decoders/RawDecoderException.h" // for ThrowRDE
#include "io/BitPumpMSB.h"                // for BitPumpMSB
#include "io/ByteStream.h"                // for ByteStream
#include <algorithm>                      // for min
#include <array>                          // for array, array<>::value_type
#include <cassert>                        // for assert
#include <cmath>                          // for abs
#include <cstdlib>                        // for abs
#include <memory>                         // for unique_ptr
#include <type_traits>                    // for enable_if_t, is_integral

namespace {

// Normally, we'd just use std::signbit(int) here. But, some (non-conforming?)
// compilers do not provide that overload, so the code simply fails to compile.
// One could cast the int to the double, but at least right now that results
// in a horrible code. So let's just provide our own signbit(). It compiles to
// the exact same code as the std::signbit(int).
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
constexpr __attribute__((const)) bool SignBit(T x) {
  return x < 0;
}

} // namespace

namespace rawspeed {

OlympusDecompressor::OlympusDecompressor(const RawImage& img) : mRaw(img) {
  if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
      mRaw->getBpp() != 2)
    ThrowRDE("Unexpected component count / data type");

  const uint32 w = mRaw->dim.x;
  const uint32 h = mRaw->dim.y;

  if (w == 0 || h == 0 || w % 2 != 0 || w > 10400 || h > 7792)
    ThrowRDE("Unexpected image dimensions found: (%u; %u)", w, h);
}

/* This is probably the slowest decoder of them all.
 * I cannot see any way to effectively speed up the prediction
 * phase, which is by far the slowest part of this algorithm.
 * Also there is no way to multithread this code, since prediction
 * is based on the output of all previous pixel (bar the first four)
 */

void OlympusDecompressor::decompress(ByteStream input) const {
  assert(mRaw->dim.y > 0);
  assert(mRaw->dim.x > 0);
  assert(mRaw->dim.x % 2 == 0);

  uchar8* data = mRaw->getData();
  int pitch = mRaw->pitch;

  /* Build a table to quickly look up "high" value */
  std::unique_ptr<char[]> bittable(new char[4096]); // NOLINT

  for (int i = 0; i < 4096; i++) {
    int b = i;
    int high;
    for (high = 0; high < 12; high++)
      if ((b >> (11 - high)) & 1)
        break;
    bittable[i] = std::min(12, high);
  }

  input.skipBytes(7);
  BitPumpMSB bits(input);

  for (uint32 y = 0; y < static_cast<uint32>(mRaw->dim.y); y++) {
    std::array<std::array<int, 3>, 2> acarry{{}};

    auto* dest = reinterpret_cast<ushort16*>(&data[y * pitch]);
    for (uint32 x = 0; x < static_cast<uint32>(mRaw->dim.x); x++) {
      int c = x & 1;

      std::array<int, 3>& carry = acarry[c];

      bits.fill();
      int i = 2 * (carry[2] < 3);
      int nbits;
      for (nbits = 2 + i; static_cast<ushort16>(carry[0]) >> (nbits + i);
           nbits++)
        ;

      int b = bits.peekBitsNoFill(15);
      int sign = (b >> 14) * -1;
      int low = (b >> 12) & 3;
      int high = bittable[b & 4095];

      // Skip bytes used above or read bits
      if (high == 12) {
        bits.skipBitsNoFill(15);
        high = bits.getBits(16 - nbits) >> 1;
      } else
        bits.skipBitsNoFill(high + 1 + 3);

      carry[0] = (high << nbits) | bits.getBits(nbits);
      int diff = (carry[0] ^ sign) + carry[1];
      carry[1] = (diff * 3 + carry[1]) >> 5;
      carry[2] = carry[0] > 16 ? 0 : carry[2] + 1;

      auto getLeft = [dest]() { return dest[-2]; };
      auto getUp = [dest, pitch]() { return dest[-pitch]; };
      auto getLeftUp = [dest, pitch]() { return dest[-pitch - 2]; };

      int pred;
      if (y < 2 && x < 2)
        pred = 0;
      else if (y < 2)
        pred = getLeft();
      else if (x < 2)
        pred = getUp();
      else {
        int left = getLeft();
        int up = getUp();
        int leftUp = getLeftUp();

        int leftMinusNw = left - leftUp;
        int upMinusNw = up - leftUp;

        // Check if sign is different, and they are both not zero
        if ((SignBit(leftMinusNw) ^ SignBit(upMinusNw)) &&
            (leftMinusNw != 0 && upMinusNw != 0)) {
          if (std::abs(leftMinusNw) > 32 || std::abs(upMinusNw) > 32)
            pred = left + upMinusNw;
          else
            pred = (left + up) >> 1;
        } else
          pred = std::abs(leftMinusNw) > std::abs(upMinusNw) ? left : up;
      }

      *dest = pred + ((diff * 4) | low);
      dest++;
    }
  }
}

} // namespace rawspeed
<|endoftext|>