<commit_before>#include <arithmetic.h>
#include <eigenbroetler_window.h>
#include <limits>
#include <QFileInfo>
#include <QSettings>
#include <array_window.h>
#include <complex_array.h>
#include <complex_operations.h>

static QString const op_name("ArithmeticDialog/operator");
static QString const lnum_name("ArithmeticDialog/leftNumerator");
static QString const lden_name("ArithmeticDialog/leftDenominator");
static QString const loff_name("ArithmeticDialog/leftOffset");
static QString const rnum_name("ArithmeticDialog/rightNumerator");
static QString const rden_name("ArithmeticDialog/rightDenominator");
static QString const roff_name("ArithmeticDialog/rightOffset");

ArithmeticDialog::ArithmeticDialog(QWidget *w):
    QDialog(w),
    currentCombo(NULL)
{
    ui.setupUi(this);
    ui.leftComboBox->installEventFilter(this);
    ui.rightComboBox->installEventFilter(this);
    ui.okButton->setEnabled(false);

    ui.leftNum->setRange(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
    ui.leftDen->setRange(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
    ui.leftOffs->setRange(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
    ui.rightNum->setRange(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
    ui.rightDen->setRange(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
    ui.rightOffs->setRange(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());

    EigenbroetlerWindow *eb = EigenbroetlerWindow::instance();
    QSettings settings(eb->app_owner, eb->app_name);
    ui.leftNum->setValue(settings.value(lnum_name, 1).toInt());
    ui.leftDen->setValue(settings.value(lden_name, 1).toInt());
    ui.leftOffs->setValue(settings.value(loff_name, 0).toInt());
    ui.rightNum->setValue(settings.value(rnum_name, 1).toInt());
    ui.rightDen->setValue(settings.value(rden_name, 1).toInt());
    ui.rightOffs->setValue(settings.value(roff_name, 0).toInt());
    op = abs(settings.value(op_name, 0).toInt()) % 4;
    buttons << ui.plusRadioButton;
    buttons << ui.minusRadioButton;
    buttons << ui.timesRadioButton;
    buttons << ui.divideRadioButton;
    buttons[op]->setChecked(true);
    comboSelection(); // This won't do anything except test whether
                       // okButton can be re-enabled
}

void ArithmeticDialog::comboSelection()
{
    if (currentCombo && currentCombo->currentText() == DataSelector::chooseFileText()) {
        QString filename = EigenbroetlerWindow::getFileName(this);
        if (!filename.isEmpty()) {
            QFileInfo file(filename);
            QString name = file.fileName();
            int count = 0;
            for (int k = 0; k < currentCombo->count(); ++k) {
                QVariant v = currentCombo->itemData(k);
                if (v.canConvert(QVariant::String)) {
                    if (filename == v.toString()) {
                        currentCombo->setCurrentIndex(k);
                        return;
                    }
                    else {
                        QFileInfo cmp(v.toString());
                        if (name == cmp.fileName())
                            ++count;
                    }
               }
            }
            if (count > 0)
                name += QString(" (%1)").arg(count + 1);
            int n = currentCombo->count();
            ui.leftComboBox->insertItem(n - 1, name, filename);
            ui.rightComboBox->insertItem(n - 1, name, filename);
            currentCombo->setCurrentIndex(n - 1);
        }
    }
    if (ui.leftComboBox->currentText() == DataSelector::chooseFileText() ||
        ui.rightComboBox->currentText() == DataSelector::chooseFileText())
        return;
    ui.okButton->setEnabled(true);
}

void ArithmeticDialog::accept()
{
    EigenbroetlerWindow *eb = EigenbroetlerWindow::instance();
    QSettings settings(eb->app_owner, eb->app_name);
    settings.setValue(lnum_name, ui.leftNum->value());
    settings.setValue(lden_name, ui.leftDen->value());
    settings.setValue(loff_name, ui.leftOffs->value());
    settings.setValue(rnum_name, ui.rightNum->value());
    settings.setValue(rden_name, ui.rightDen->value());
    settings.setValue(roff_name, ui.rightOffs->value());
    for (int i = 0; i < buttons.length(); ++i)
        if (buttons[i]->isChecked()) {
            op = i;
            break;
        }
    settings.setValue(op_name, op);
    QDialog::accept();
}

QList<ComplexArray const *> ArithmeticDialog::getData(DataSelector *s, bool& is_owned) const
{
    QVariant v = s->itemData(s->currentIndex());
    if (v.canConvert(QVariant::String)) {
        // file name
        is_owned = true;
        QString errStr;
        QList<ComplexArray *> arr = ComplexArray::readFileData(v.toString(), errStr, true);
        QList<ComplexArray const *> c_arr;
        for(QList<ComplexArray *>::iterator a = arr.begin(); a != arr.end(); ++a)
            c_arr << *a;
        return c_arr;
    }
    else {
        // window data
        ArrayWindow const *w = dynamic_cast<ArrayWindow const *>(v.value<QWidget*>());
        is_owned = false;
        return w->getData();
    }
}

QList<ComplexArray *> ArithmeticDialog::doArithmetic() const
{
    bool l_owned;
    QList<ComplexArray const *> left_operand = getData(ui.leftComboBox, l_owned);
    bool r_owned;
    QList<ComplexArray const *> right_operand = getData(ui.rightComboBox, r_owned);
    QList<ComplexArray *> arith_result;

    QSize sz(left_operand[0]->width(), left_operand[0]->height());
    bool same_size = true;
    for (int i = 0; i < left_operand.length(); ++i) {
        same_size &= (sz.width() == left_operand[i]->width());
        same_size &= (sz.height() == left_operand[i]->height());
        sz.setWidth(std::max(sz.width(), left_operand[i]->width()));
        sz.setHeight(std::max(sz.height(), left_operand[i]->height()));
    }
    for (int i = 0; i < right_operand.length(); ++i) {
        same_size &= (sz.width() == right_operand[i]->width());
        same_size &= (sz.height() == right_operand[i]->height());
        sz.setWidth(std::max(sz.width(), right_operand[i]->width()));
        sz.setHeight(std::max(sz.height(), right_operand[i]->height()));
    }
    if (!same_size) {
        for (int i = 0; i < left_operand.length(); ++i) {
            ComplexArray const *a = Operations::resize(left_operand[i], sz.width(), sz.height());
            if (l_owned)
                delete left_operand[i];
            left_operand[i] = a;
        }
        for (int i = 0; i < right_operand.length(); ++i) {
            ComplexArray const *a = Operations::resize(right_operand[i], sz.width(), sz.height());
            if (r_owned)
                delete right_operand[i];
            right_operand[i] = a;
        }
        l_owned = r_owned = true;
    }
    Operations::ArithOp arith_op;
    switch (op) {
    case 0:
        arith_op = Operations::ADD;
        break;
    case 1:
        arith_op = Operations::SUBTRACT;
        break;
    case 2:
        arith_op = Operations::MULTIPLY;
        break;
    case 3:
        arith_op = Operations::DIVIDE;
        break;
    };
    if (left_operand.length() == right_operand.length()) {
        for (int i = 0; i < left_operand.length(); ++i)
            arith_result << Operations::arithmetic(left_operand[i],
                                                   ui.leftNum->value(), ui.leftDen->value(), ui.leftOffs->value(),
                                                   arith_op,
                                                   right_operand[i],
                                                   ui.rightNum->value(), ui.rightDen->value(), ui.rightOffs->value());

    }
    else if (left_operand.length() == 1) {
        for (int i = 0; i < right_operand.length(); ++i)
            arith_result << Operations::arithmetic(left_operand[0],
                                                   ui.leftNum->value(), ui.leftDen->value(), ui.leftOffs->value(),
                                                   arith_op,
                                                   right_operand[i],
                                                   ui.rightNum->value(), ui.rightDen->value(), ui.rightOffs->value());

    }
    else if (right_operand.length() == 1) {
        for (int i = 0; i < left_operand.length(); ++i)
            arith_result << Operations::arithmetic(left_operand[i],
                                                   ui.leftNum->value(), ui.leftDen->value(), ui.leftOffs->value(),
                                                   arith_op,
                                                   right_operand[0],
                                                   ui.rightNum->value(), ui.rightDen->value(), ui.rightOffs->value());

    }
    else {
        int const n = std::min(left_operand.length(), right_operand.length());
        for (int i = 0; i < n; ++i)
            arith_result << Operations::arithmetic(left_operand[i],
                                                   ui.leftNum->value(), ui.leftDen->value(), ui.leftOffs->value(),
                                                   arith_op,
                                                   right_operand[i],
                                                   ui.rightNum->value(), ui.rightDen->value(), ui.rightOffs->value());

    }

    if (l_owned)
        for (int i = 0; i < left_operand.length(); ++i)
            delete left_operand[i];
    if (r_owned)
        for (int i = 0; i < right_operand.length(); ++i)
            delete right_operand[i];
    return arith_result;
}

bool ArithmeticDialog::eventFilter(QObject *obj, QEvent *evt)
{
    if (evt->type() == QEvent::FocusIn)
        currentCombo = dynamic_cast<DataSelector *>(obj);
    return QDialog::eventFilter(obj, evt);
}

void EigenbroetlerWindow::arithmetic()
{
    ArithmeticDialog dlg(this);
    if (dlg.exec() == QDialog::Accepted) {
        QList<ComplexArray *> da = dlg.doArithmetic();
        newWindow(da, true);
    }
}
<commit_msg>Fixed uninitialized value.<commit_after>#include <arithmetic.h>
#include <eigenbroetler_window.h>
#include <limits>
#include <QFileInfo>
#include <QSettings>
#include <array_window.h>
#include <complex_array.h>
#include <complex_operations.h>

static QString const op_name("ArithmeticDialog/operator");
static QString const lnum_name("ArithmeticDialog/leftNumerator");
static QString const lden_name("ArithmeticDialog/leftDenominator");
static QString const loff_name("ArithmeticDialog/leftOffset");
static QString const rnum_name("ArithmeticDialog/rightNumerator");
static QString const rden_name("ArithmeticDialog/rightDenominator");
static QString const roff_name("ArithmeticDialog/rightOffset");

ArithmeticDialog::ArithmeticDialog(QWidget *w):
    QDialog(w),
    currentCombo(NULL)
{
    ui.setupUi(this);
    ui.leftComboBox->installEventFilter(this);
    ui.rightComboBox->installEventFilter(this);
    ui.okButton->setEnabled(false);

    ui.leftNum->setRange(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
    ui.leftDen->setRange(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
    ui.leftOffs->setRange(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
    ui.rightNum->setRange(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
    ui.rightDen->setRange(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
    ui.rightOffs->setRange(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());

    EigenbroetlerWindow *eb = EigenbroetlerWindow::instance();
    QSettings settings(eb->app_owner, eb->app_name);
    ui.leftNum->setValue(settings.value(lnum_name, 1).toInt());
    ui.leftDen->setValue(settings.value(lden_name, 1).toInt());
    ui.leftOffs->setValue(settings.value(loff_name, 0).toInt());
    ui.rightNum->setValue(settings.value(rnum_name, 1).toInt());
    ui.rightDen->setValue(settings.value(rden_name, 1).toInt());
    ui.rightOffs->setValue(settings.value(roff_name, 0).toInt());
    op = abs(settings.value(op_name, 0).toInt()) % 4;
    buttons << ui.plusRadioButton;
    buttons << ui.minusRadioButton;
    buttons << ui.timesRadioButton;
    buttons << ui.divideRadioButton;
    buttons[op]->setChecked(true);
    comboSelection(); // This won't do anything except test whether
                       // okButton can be re-enabled
}

void ArithmeticDialog::comboSelection()
{
    if (currentCombo && currentCombo->currentText() == DataSelector::chooseFileText()) {
        QString filename = EigenbroetlerWindow::getFileName(this);
        if (!filename.isEmpty()) {
            QFileInfo file(filename);
            QString name = file.fileName();
            int count = 0;
            for (int k = 0; k < currentCombo->count(); ++k) {
                QVariant v = currentCombo->itemData(k);
                if (v.canConvert(QVariant::String)) {
                    if (filename == v.toString()) {
                        currentCombo->setCurrentIndex(k);
                        return;
                    }
                    else {
                        QFileInfo cmp(v.toString());
                        if (name == cmp.fileName())
                            ++count;
                    }
               }
            }
            if (count > 0)
                name += QString(" (%1)").arg(count + 1);
            int n = currentCombo->count();
            ui.leftComboBox->insertItem(n - 1, name, filename);
            ui.rightComboBox->insertItem(n - 1, name, filename);
            currentCombo->setCurrentIndex(n - 1);
        }
    }
    if (ui.leftComboBox->currentText() == DataSelector::chooseFileText() ||
        ui.rightComboBox->currentText() == DataSelector::chooseFileText())
        return;
    ui.okButton->setEnabled(true);
}

void ArithmeticDialog::accept()
{
    EigenbroetlerWindow *eb = EigenbroetlerWindow::instance();
    QSettings settings(eb->app_owner, eb->app_name);
    settings.setValue(lnum_name, ui.leftNum->value());
    settings.setValue(lden_name, ui.leftDen->value());
    settings.setValue(loff_name, ui.leftOffs->value());
    settings.setValue(rnum_name, ui.rightNum->value());
    settings.setValue(rden_name, ui.rightDen->value());
    settings.setValue(roff_name, ui.rightOffs->value());
    for (int i = 0; i < buttons.length(); ++i)
        if (buttons[i]->isChecked()) {
            op = i;
            break;
        }
    settings.setValue(op_name, op);
    QDialog::accept();
}

QList<ComplexArray const *> ArithmeticDialog::getData(DataSelector *s, bool& is_owned) const
{
    QVariant v = s->itemData(s->currentIndex());
    if (v.canConvert(QVariant::String)) {
        // file name
        is_owned = true;
        QString errStr;
        QList<ComplexArray *> arr = ComplexArray::readFileData(v.toString(), errStr, true);
        QList<ComplexArray const *> c_arr;
        for(QList<ComplexArray *>::iterator a = arr.begin(); a != arr.end(); ++a)
            c_arr << *a;
        return c_arr;
    }
    else {
        // window data
        ArrayWindow const *w = dynamic_cast<ArrayWindow const *>(v.value<QWidget*>());
        is_owned = false;
        return w->getData();
    }
}

QList<ComplexArray *> ArithmeticDialog::doArithmetic() const
{
    bool l_owned;
    QList<ComplexArray const *> left_operand = getData(ui.leftComboBox, l_owned);
    bool r_owned;
    QList<ComplexArray const *> right_operand = getData(ui.rightComboBox, r_owned);
    QList<ComplexArray *> arith_result;

    QSize sz(left_operand[0]->width(), left_operand[0]->height());
    bool same_size = true;
    for (int i = 0; i < left_operand.length(); ++i) {
        same_size &= (sz.width() == left_operand[i]->width());
        same_size &= (sz.height() == left_operand[i]->height());
        sz.setWidth(std::max(sz.width(), left_operand[i]->width()));
        sz.setHeight(std::max(sz.height(), left_operand[i]->height()));
    }
    for (int i = 0; i < right_operand.length(); ++i) {
        same_size &= (sz.width() == right_operand[i]->width());
        same_size &= (sz.height() == right_operand[i]->height());
        sz.setWidth(std::max(sz.width(), right_operand[i]->width()));
        sz.setHeight(std::max(sz.height(), right_operand[i]->height()));
    }
    if (!same_size) {
        for (int i = 0; i < left_operand.length(); ++i) {
            ComplexArray const *a = Operations::resize(left_operand[i], sz.width(), sz.height());
            if (l_owned)
                delete left_operand[i];
            left_operand[i] = a;
        }
        for (int i = 0; i < right_operand.length(); ++i) {
            ComplexArray const *a = Operations::resize(right_operand[i], sz.width(), sz.height());
            if (r_owned)
                delete right_operand[i];
            right_operand[i] = a;
        }
        l_owned = r_owned = true;
    }
    Operations::ArithOp arith_op = Operations::ArithOp(-1);
    switch (op) {
    case 0:
        arith_op = Operations::ADD;
        break;
    case 1:
        arith_op = Operations::SUBTRACT;
        break;
    case 2:
        arith_op = Operations::MULTIPLY;
        break;
    case 3:
        arith_op = Operations::DIVIDE;
        break;
    };
    if (left_operand.length() == right_operand.length()) {
        for (int i = 0; i < left_operand.length(); ++i)
            arith_result << Operations::arithmetic(left_operand[i],
                                                   ui.leftNum->value(), ui.leftDen->value(), ui.leftOffs->value(),
                                                   arith_op,
                                                   right_operand[i],
                                                   ui.rightNum->value(), ui.rightDen->value(), ui.rightOffs->value());

    }
    else if (left_operand.length() == 1) {
        for (int i = 0; i < right_operand.length(); ++i)
            arith_result << Operations::arithmetic(left_operand[0],
                                                   ui.leftNum->value(), ui.leftDen->value(), ui.leftOffs->value(),
                                                   arith_op,
                                                   right_operand[i],
                                                   ui.rightNum->value(), ui.rightDen->value(), ui.rightOffs->value());

    }
    else if (right_operand.length() == 1) {
        for (int i = 0; i < left_operand.length(); ++i)
            arith_result << Operations::arithmetic(left_operand[i],
                                                   ui.leftNum->value(), ui.leftDen->value(), ui.leftOffs->value(),
                                                   arith_op,
                                                   right_operand[0],
                                                   ui.rightNum->value(), ui.rightDen->value(), ui.rightOffs->value());

    }
    else {
        int const n = std::min(left_operand.length(), right_operand.length());
        for (int i = 0; i < n; ++i)
            arith_result << Operations::arithmetic(left_operand[i],
                                                   ui.leftNum->value(), ui.leftDen->value(), ui.leftOffs->value(),
                                                   arith_op,
                                                   right_operand[i],
                                                   ui.rightNum->value(), ui.rightDen->value(), ui.rightOffs->value());

    }

    if (l_owned)
        for (int i = 0; i < left_operand.length(); ++i)
            delete left_operand[i];
    if (r_owned)
        for (int i = 0; i < right_operand.length(); ++i)
            delete right_operand[i];
    return arith_result;
}

bool ArithmeticDialog::eventFilter(QObject *obj, QEvent *evt)
{
    if (evt->type() == QEvent::FocusIn)
        currentCombo = dynamic_cast<DataSelector *>(obj);
    return QDialog::eventFilter(obj, evt);
}

void EigenbroetlerWindow::arithmetic()
{
    ArithmeticDialog dlg(this);
    if (dlg.exec() == QDialog::Accepted) {
        QList<ComplexArray *> da = dlg.doArithmetic();
        newWindow(da, true);
    }
}
<|endoftext|>


<commit_before>//
// remote-stream.cpp
//
//  Created by Peter Gusev on 17 June 2016.
//  Copyright 2013-2016 Regents of the University of California
//

#include "remote-stream.hpp"
#include <boost/make_shared.hpp>
#include <ndn-cpp/name.hpp>

#include "remote-stream-impl.hpp"
#include "remote-video-stream.hpp"
#include "remote-audio-stream.hpp"

using namespace ndnrtc;

//******************************************************************************
RemoteStream::RemoteStream(boost::asio::io_service& faceIo,
			const boost::shared_ptr<ndn::Face>& face,
			const boost::shared_ptr<ndn::KeyChain>& keyChain,
			const std::string& basePrefix,
			const std::string& streamName):
basePrefix_(basePrefix), streamName_(streamName)
{
}

RemoteStream::~RemoteStream(){
	pimpl_->setNeedsMeta(false);
}

bool
RemoteStream::isMetaFetched() const
{
	return pimpl_->isMetaFetched();
}

std::vector<std::string>
RemoteStream::getThreads() const
{
	return pimpl_->getThreads();
}

void
RemoteStream::setThread(const std::string& threadName)
{
	pimpl_->setThread(threadName);
}

std::string
RemoteStream::getThread() const
{
    return pimpl_->getThread();
}

void
RemoteStream::stop()
{
	pimpl_->stop();
}

void
RemoteStream::setInterestLifetime(unsigned int lifetime)
{
	pimpl_->setInterestLifetime(lifetime);
}

void
RemoteStream::setTargetBufferSize(unsigned int bufferSize)
{
	pimpl_->setTargetBufferSize(bufferSize);
}

statistics::StatisticsStorage
RemoteStream::getStatistics() const
{
	return pimpl_->getStatistics();
}

void
RemoteStream::setLogger(boost::shared_ptr<ndnlog::new_api::Logger> logger)
{
	pimpl_->setLogger(logger);
}

bool
RemoteStream::isVerified() const
{
	return pimpl_->isVerified();
}

bool
RemoteStream::isRunning() const
{
    return pimpl_->isRunning();
}

void
RemoteStream::registerObserver(IRemoteStreamObserver* o)
{
    pimpl_->attach(o);
}

void
RemoteStream::unregisterObserver(IRemoteStreamObserver* o)
{
    pimpl_->detach(o);
}

boost::shared_ptr<StorageEngine>
RemoteStream::getStorage() const
{
    throw std::runtime_error("Not implemented");
}

//******************************************************************************
RemoteAudioStream::RemoteAudioStream(boost::asio::io_service& faceIo,
			const boost::shared_ptr<ndn::Face>& face,
			const boost::shared_ptr<ndn::KeyChain>& keyChain,
			const std::string& basePrefix,
			const std::string& streamName,
			const int interestLifetime,
			const int jitterSizeMs):
RemoteStream(faceIo, face, keyChain, basePrefix, streamName)
{
	pimpl_ = boost::make_shared<RemoteAudioStreamImpl>(faceIo, face, keyChain,
                                                       NameComponents::audioStreamPrefix(basePrefix).append(streamName).toUri());
	pimpl_->setInterestLifetime(interestLifetime);
	pimpl_->setTargetBufferSize(jitterSizeMs);
	pimpl_->fetchMeta();
}

void
RemoteAudioStream::start(const std::string& threadName)
{
	pimpl_->start(threadName);
}

//******************************************************************************
RemoteVideoStream::RemoteVideoStream(boost::asio::io_service& faceIo,
			const boost::shared_ptr<ndn::Face>& face,
			const boost::shared_ptr<ndn::KeyChain>& keyChain,
			const std::string& basePrefix,
			const std::string& streamName,
			const int interestLifetime,
			const int jitterSizeMs):
RemoteStream(faceIo, face, keyChain, basePrefix, streamName)
{
	pimpl_ = boost::make_shared<RemoteVideoStreamImpl>(faceIo, face, keyChain,
                                                      NameComponents::videoStreamPrefix(basePrefix).append(streamName).toUri());
	pimpl_->setInterestLifetime(interestLifetime);
	pimpl_->setTargetBufferSize(jitterSizeMs);
	pimpl_->fetchMeta();
}

void
RemoteVideoStream::start(const std::string& threadName, IExternalRenderer* renderer)
{
	boost::dynamic_pointer_cast<RemoteVideoStreamImpl>(pimpl_)->start(threadName, renderer);
}

RemoteVideoStream::RemoteVideoStream(boost::asio::io_service& faceIo,
			const boost::shared_ptr<ndn::Face>& face,
			const boost::shared_ptr<ndn::KeyChain>& keyChain,
			const std::string& threadPrefix,
            const int jitterSizeMs):
RemoteStream(faceIo, face, keyChain, "", "")
{
    NamespaceInfo prefixInfo;
    if (!NameComponents::extractInfo(threadPrefix, prefixInfo) ||
        prefixInfo.threadName_ == "" ||
        prefixInfo.streamType_ != MediaStreamParams::MediaStreamType::MediaStreamTypeVideo)
        throw std::runtime_error("Invalid thread prefix provided");

    basePrefix_ = prefixInfo.getPrefix(prefix_filter::Base).toUri();
    streamName_ = prefixInfo.streamName_;

    pimpl_ = boost::make_shared<RemoteVideoStreamImpl>(faceIo, face, keyChain,
                                                       prefixInfo.getPrefix(prefix_filter::Stream).toUri(),
                                                       prefixInfo.threadName_);
    pimpl_->setTargetBufferSize(jitterSizeMs);
    pimpl_->fetchMeta();
}

void
RemoteVideoStream::start(const FetchingRuleSet& ruleset, IExternalRenderer* renderer)
{
    boost::dynamic_pointer_cast<RemoteVideoStreamImpl>(pimpl_)->start(ruleset, renderer);
}<commit_msg>RemoteStream::getPrefix() fixed<commit_after>//
// remote-stream.cpp
//
//  Created by Peter Gusev on 17 June 2016.
//  Copyright 2013-2016 Regents of the University of California
//

#include "remote-stream.hpp"
#include <boost/make_shared.hpp>
#include <ndn-cpp/name.hpp>

#include "remote-stream-impl.hpp"
#include "remote-video-stream.hpp"
#include "remote-audio-stream.hpp"

using namespace ndnrtc;

//******************************************************************************
RemoteStream::RemoteStream(boost::asio::io_service& faceIo,
			const boost::shared_ptr<ndn::Face>& face,
			const boost::shared_ptr<ndn::KeyChain>& keyChain,
			const std::string& basePrefix,
			const std::string& streamName):
basePrefix_(basePrefix), streamName_(streamName)
{
}

RemoteStream::~RemoteStream(){
	pimpl_->setNeedsMeta(false);
}

bool
RemoteStream::isMetaFetched() const
{
	return pimpl_->isMetaFetched();
}

std::vector<std::string>
RemoteStream::getThreads() const
{
	return pimpl_->getThreads();
}

void
RemoteStream::setThread(const std::string& threadName)
{
	pimpl_->setThread(threadName);
}

std::string
RemoteStream::getThread() const
{
    return pimpl_->getThread();
}

void
RemoteStream::stop()
{
	pimpl_->stop();
}

void
RemoteStream::setInterestLifetime(unsigned int lifetime)
{
	pimpl_->setInterestLifetime(lifetime);
}

void
RemoteStream::setTargetBufferSize(unsigned int bufferSize)
{
	pimpl_->setTargetBufferSize(bufferSize);
}

statistics::StatisticsStorage
RemoteStream::getStatistics() const
{
	return pimpl_->getStatistics();
}

void
RemoteStream::setLogger(boost::shared_ptr<ndnlog::new_api::Logger> logger)
{
	pimpl_->setLogger(logger);
}

bool
RemoteStream::isVerified() const
{
	return pimpl_->isVerified();
}

bool
RemoteStream::isRunning() const
{
    return pimpl_->isRunning();
}

void
RemoteStream::registerObserver(IRemoteStreamObserver* o)
{
    pimpl_->attach(o);
}

void
RemoteStream::unregisterObserver(IRemoteStreamObserver* o)
{
    pimpl_->detach(o);
}

boost::shared_ptr<StorageEngine>
RemoteStream::getStorage() const
{
    throw std::runtime_error("Not implemented");
}

//******************************************************************************
RemoteAudioStream::RemoteAudioStream(boost::asio::io_service& faceIo,
			const boost::shared_ptr<ndn::Face>& face,
			const boost::shared_ptr<ndn::KeyChain>& keyChain,
			const std::string& basePrefix,
			const std::string& streamName,
			const int interestLifetime,
			const int jitterSizeMs):
RemoteStream(faceIo, face, keyChain, basePrefix, streamName)
{
	streamPrefix_ = NameComponents::audioStreamPrefix(basePrefix).append(streamName).toUri();
	pimpl_ = boost::make_shared<RemoteAudioStreamImpl>(faceIo, face, keyChain, streamPrefix_);
	pimpl_->setInterestLifetime(interestLifetime);
	pimpl_->setTargetBufferSize(jitterSizeMs);
	pimpl_->fetchMeta();
}

void
RemoteAudioStream::start(const std::string& threadName)
{
	pimpl_->start(threadName);
}

//******************************************************************************
RemoteVideoStream::RemoteVideoStream(boost::asio::io_service& faceIo,
			const boost::shared_ptr<ndn::Face>& face,
			const boost::shared_ptr<ndn::KeyChain>& keyChain,
			const std::string& basePrefix,
			const std::string& streamName,
			const int interestLifetime,
			const int jitterSizeMs):
RemoteStream(faceIo, face, keyChain, basePrefix, streamName)
{
	streamPrefix_ = NameComponents::videoStreamPrefix(basePrefix).append(streamName).toUri();
	pimpl_ = boost::make_shared<RemoteVideoStreamImpl>(faceIo, face, keyChain, streamPrefix_);

	pimpl_->setInterestLifetime(interestLifetime);
	pimpl_->setTargetBufferSize(jitterSizeMs);
	pimpl_->fetchMeta();
}

void
RemoteVideoStream::start(const std::string& threadName, IExternalRenderer* renderer)
{
	boost::dynamic_pointer_cast<RemoteVideoStreamImpl>(pimpl_)->start(threadName, renderer);
}

RemoteVideoStream::RemoteVideoStream(boost::asio::io_service& faceIo,
			const boost::shared_ptr<ndn::Face>& face,
			const boost::shared_ptr<ndn::KeyChain>& keyChain,
			const std::string& threadPrefix,
            const int jitterSizeMs):
RemoteStream(faceIo, face, keyChain, "", "")
{
    NamespaceInfo prefixInfo;
    if (!NameComponents::extractInfo(threadPrefix, prefixInfo) ||
        prefixInfo.threadName_ == "" ||
        prefixInfo.streamType_ != MediaStreamParams::MediaStreamType::MediaStreamTypeVideo)
        throw std::runtime_error("Invalid thread prefix provided");

    basePrefix_ = prefixInfo.getPrefix(prefix_filter::Base).toUri();
    streamName_ = prefixInfo.streamName_;

    pimpl_ = boost::make_shared<RemoteVideoStreamImpl>(faceIo, face, keyChain,
                                                       prefixInfo.getPrefix(prefix_filter::Stream).toUri(),
                                                       prefixInfo.threadName_);
    pimpl_->setTargetBufferSize(jitterSizeMs);
    pimpl_->fetchMeta();
}

void
RemoteVideoStream::start(const FetchingRuleSet& ruleset, IExternalRenderer* renderer)
{
    boost::dynamic_pointer_cast<RemoteVideoStreamImpl>(pimpl_)->start(ruleset, renderer);
}<|endoftext|>


<commit_before>/*
  Copyright 2015-2016 P4FPGA Project

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#include "fdeparser.h"
#include "ir/ir.h"
#include "vector_utils.h"
#include "string_utils.h"

namespace FPGA {

class DeparserBuilder : public Inspector {
  public:
    DeparserBuilder(FPGADeparser* deparser, const FPGAProgram* program) :
      deparser(deparser), program(program) {}
    bool preorder(const IR::MethodCallStatement* stat) override
    { visit(stat->methodCall); return false; }
    bool preorder(const IR::MethodCallExpression* expression) override;
    bool preorder(const IR::Member* member) override;
  private:
    const FPGAProgram* program;
    FPGADeparser* deparser;
};

bool DeparserBuilder::preorder(const IR::MethodCallExpression* expression) {
  // packet.emit
  auto emit = expression->method;
  for (auto h : MakeZipRange(*expression->typeArguments, *expression->arguments)) {
    auto typeName = h.get<0>();
    auto instName = h.get<1>();
    auto type = program->typeMap->getType(typeName, true);

    // get header width
    auto hdr_width = type->width_bits();
    // create deparse state for each header
    if (type->is<IR::Type_StructLike>()) {
      auto t = type->to<IR::Type_StructLike>();
      if (instName->is<IR::Member>()) {
        const IR::Member* member = instName->to<IR::Member>();
        cstring name = member->member;
        cstring indexed_name = name;
        deparser->states.push_back(new IR::BSV::DeparseState(name, t->fields, hdr_width, indexed_name));
      }
    }
    // unroll header stack to individual headers and create deparse state for each one
    else if (type->is<IR::Type_Stack>()){
      auto stk = type->to<IR::Type_Stack>();
      for (int i = 0; i < stk->getSize(); i++) {
        if (stk->elementType->is<IR::Type_StructLike>()) {
          auto t = stk->elementType->to<IR::Type_StructLike>();
          int hdr_width = stk->elementType->width_bits();
          if (instName->is<IR::Member>()) {
            const IR::Member* member = instName->to<IR::Member>();
            cstring name = member->member + std::to_string(i);
            cstring indexed_name = member->member + "[" + std::to_string(i) + "]";
            deparser->states.push_back(new IR::BSV::DeparseState(name.c_str(), t->fields, hdr_width, indexed_name));
          }
        }
      }
    }
  }
  return false;
}

bool DeparserBuilder::preorder(const IR::Member* member) {
  if (member->expr->is<IR::PathExpression>()) {
    auto et = member->expr->to<IR::PathExpression>();
    // LOG1(et->path->name);
  }
  return false;
}

class DeparserRuleVisitor : public Inspector {
  public:
    DeparserRuleVisitor(const FPGADeparser* deparser, CodeBuilder* builder, int& num_rules) :
      builder(builder), num_rules(num_rules) {}
    bool preorder(const IR::BSV::DeparseState* state) override;
  private:
    const FPGAProgram* program;
    CodeBuilder* builder;
    int& num_rules;
};

bool DeparserRuleVisitor::preorder(const IR::BSV::DeparseState* state) {
  auto width = state->width_bits;
  auto hdr = state->to<IR::Type_Header>();
  auto name = hdr->name.name;

  builder->append_line("`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseNextRule(w_%s, StateDeparse%s, %d))));", name, CamelCase(name), width);
  builder->append_line("`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseLoadRule(StateDeparse%s, %d))));", CamelCase(name), width);
  builder->append_line("`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseSendRule(StateDeparse%s, %d))));", CamelCase(name), width);
  num_rules += 3;
  return false;
}

class DeparserStateVisitor : public Inspector {
  public:
    DeparserStateVisitor(const FPGADeparser* deparser, CodeBuilder* builder) :
      builder(builder) {}
    bool preorder(const IR::BSV::DeparseState* state) override;
  private:
    const FPGAProgram* program;
    CodeBuilder* builder;
};

bool DeparserStateVisitor::preorder(const IR::BSV::DeparseState* state) {
  auto hdr = state->to<IR::Type_Header>();
  auto name = hdr->name.name;
  builder->append_format("PulseWire w_%s <- mkPulseWire();", name);
  return false;
}

// Convert emit() to IR::BSV::DeparseState
bool FPGADeparser::build() {
  auto stat = controlBlock->container->body;
  DeparserBuilder visitor(this, program);
  stat->apply(visitor);
  return true;
}

void FPGADeparser::emitEnums() {
  builder->append_line("`ifdef DEPARSER_STRUCT");
  builder->append_line("typedef enum {");
  builder->incr_indent();
  builder->append_line("StateDeparseStart,");
  for (auto r : states) {
    auto name = r->name.name;
    if (r != states.back()) {
      builder->append_format("StateDeparse%s,", CamelCase(name));
    } else {
      builder->append_format("StateDeparse%s", CamelCase(name));
    }
  }
  builder->decr_indent();
  builder->append_line("} DeparserState deriving (Bits, Eq, FShow);");
  builder->append_line("`endif  // DEPARSER_STRUCT");
}

void FPGADeparser::emitRules() {
  builder->append_line("`ifdef DEPARSER_RULES");
  // deparse rules are mutually exclusive
//  std::vector<cstring> exclusive_rules;
//  for (auto r : states) {
//    cstring rl = cstring("rl_deparse_") + r->name.toString() + cstring("_next");
//    exclusive_rules.push_back(rl);
//  }
//  auto exclusive_annotation = cstring("(* mutually_exclusive=\"");
//  for (auto r : exclusive_rules) {
//    exclusive_annotation += r;
//    if (r != exclusive_rules.back()) {
//      exclusive_annotation += cstring(",");
//    }
//  }
//  exclusive_annotation += cstring("\" *)");
//  builder->append_line(exclusive_annotation);

  int num_rules = 0;
  DeparserRuleVisitor visitor(this, builder, num_rules);
  for (auto r : states) {
    r->apply(visitor);
  }
  builder->append_line("Vector#(%d, Rules) fsmRules = toVector(deparse_fsm);", num_rules);
  builder->append_line("`endif  // DEPARSER_RULES");
}

void FPGADeparser::emitStates() {
  builder->append_line("`ifdef DEPARSER_STATE");

  // pulsewire to initiate next state
  DeparserStateVisitor visitor(this, builder);
  for (auto r : states) {
    r->apply(visitor);
  }
  builder->append_line("");

  // Function: next_parse_state
  auto len = states.size();
  // bit0 is by default 0.
  auto lenp1 = len + 1;
  builder->append_format("function Bit#(%d) nextDeparseState(MetadataT metadata);", lenp1);
  builder->incr_indent();
  builder->append_format("Vector#(%d, Bool) headerValid;", lenp1);
  builder->append_line("headerValid[0] = False;");
  for (int i = 0; i < states.size(); i++) {
    cstring name = states.at(i)->indexed_name;
    builder->append_format("headerValid[%d] = checkForward(metadata.hdr.%s);", i+1, name);
  }
  builder->append_line("let vec = pack(headerValid);");
  builder->append_line("return vec;");
  builder->decr_indent();
  builder->append_line("endfunction");
  builder->append_line("");

  // Function: transit_next_state
  builder->append_line("function Action transit_next_state(MetadataT metadata);");
  builder->incr_indent();
  builder->append_line("action");
  builder->append_line("let vec = nextDeparseState(metadata);");
  builder->append_line("if (vec == 0) begin");
  builder->incr_indent();
  builder->append_line("w_deparse_header_done.send();");
  builder->decr_indent();
  builder->append_line("end");
  builder->append_line("else begin");
  builder->incr_indent();
  auto nextVecLen = ceil(log2(lenp1));
  builder->append_format("Bit#(%d) nextHeader = truncate(pack(countZerosLSB(vec)%% %d));", nextVecLen, lenp1 );
  builder->append_line("DeparserState nextState = unpack(nextHeader);");
  builder->append_line("case (nextState) matches");
  builder->incr_indent();
  for (int i = 0; i < states.size(); i++) {
    auto name = states.at(i)->name.name;
    builder->append_format("StateDeparse%s: w_%s.send();", CamelCase(name), name);
  }
  builder->append_line("default: $display(\"ERROR: unknown states.\");");
  builder->decr_indent();
  builder->append_line("endcase");
  builder->decr_indent();
  builder->append_line("end");
  builder->append_line("endaction");
  builder->decr_indent();
  builder->append_line("endfunction");

  // Function: update_metadata
  builder->append_line("function MetadataT update_metadata(DeparserState state);");
  builder->incr_indent();
  builder->append_line("let metadata = meta[0];");
  builder->append_line("case (state) matches");
  builder->incr_indent();
  for (auto s : states) {
    cstring name = s->name.toString();
    cstring indexed_name = s->indexed_name;
    builder->append_line("StateDeparse%s :", CamelCase(name));
    builder->incr_indent();
    builder->append_format("metadata.hdr.%s = updateState(metadata.hdr.%s, tagged StructDefines::NotPresent);", indexed_name, indexed_name);
    builder->decr_indent();
  }
  builder->decr_indent();
  builder->append_line("endcase");
  builder->append_line("return metadata;");
  builder->decr_indent();
  builder->append_line("endfunction");
  builder->append_line("let initState = StateDeparse%s;", CamelCase(states[0]->name.toString()));
  builder->append_line("`endif  // DEPARSER_STATE");

}

void FPGADeparser::emit(BSVProgram & bsv) {
  builder = &bsv.getDeparserBuilder();
  emitEnums();
  emitRules();
  emitStates();
}

}  // namespace FPGA
<commit_msg>meta[0] -> rg_metadata<commit_after>/*
  Copyright 2015-2016 P4FPGA Project

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#include "fdeparser.h"
#include "ir/ir.h"
#include "vector_utils.h"
#include "string_utils.h"

namespace FPGA {

class DeparserBuilder : public Inspector {
  public:
    DeparserBuilder(FPGADeparser* deparser, const FPGAProgram* program) :
      deparser(deparser), program(program) {}
    bool preorder(const IR::MethodCallStatement* stat) override
    { visit(stat->methodCall); return false; }
    bool preorder(const IR::MethodCallExpression* expression) override;
    bool preorder(const IR::Member* member) override;
  private:
    const FPGAProgram* program;
    FPGADeparser* deparser;
};

bool DeparserBuilder::preorder(const IR::MethodCallExpression* expression) {
  // packet.emit
  auto emit = expression->method;
  for (auto h : MakeZipRange(*expression->typeArguments, *expression->arguments)) {
    auto typeName = h.get<0>();
    auto instName = h.get<1>();
    auto type = program->typeMap->getType(typeName, true);

    // get header width
    auto hdr_width = type->width_bits();
    // create deparse state for each header
    if (type->is<IR::Type_StructLike>()) {
      auto t = type->to<IR::Type_StructLike>();
      if (instName->is<IR::Member>()) {
        const IR::Member* member = instName->to<IR::Member>();
        cstring name = member->member;
        cstring indexed_name = name;
        deparser->states.push_back(new IR::BSV::DeparseState(name, t->fields, hdr_width, indexed_name));
      }
    }
    // unroll header stack to individual headers and create deparse state for each one
    else if (type->is<IR::Type_Stack>()){
      auto stk = type->to<IR::Type_Stack>();
      for (int i = 0; i < stk->getSize(); i++) {
        if (stk->elementType->is<IR::Type_StructLike>()) {
          auto t = stk->elementType->to<IR::Type_StructLike>();
          int hdr_width = stk->elementType->width_bits();
          if (instName->is<IR::Member>()) {
            const IR::Member* member = instName->to<IR::Member>();
            cstring name = member->member + std::to_string(i);
            cstring indexed_name = member->member + "[" + std::to_string(i) + "]";
            deparser->states.push_back(new IR::BSV::DeparseState(name.c_str(), t->fields, hdr_width, indexed_name));
          }
        }
      }
    }
  }
  return false;
}

bool DeparserBuilder::preorder(const IR::Member* member) {
  if (member->expr->is<IR::PathExpression>()) {
    auto et = member->expr->to<IR::PathExpression>();
    // LOG1(et->path->name);
  }
  return false;
}

class DeparserRuleVisitor : public Inspector {
  public:
    DeparserRuleVisitor(const FPGADeparser* deparser, CodeBuilder* builder, int& num_rules) :
      builder(builder), num_rules(num_rules) {}
    bool preorder(const IR::BSV::DeparseState* state) override;
  private:
    const FPGAProgram* program;
    CodeBuilder* builder;
    int& num_rules;
};

bool DeparserRuleVisitor::preorder(const IR::BSV::DeparseState* state) {
  auto width = state->width_bits;
  auto hdr = state->to<IR::Type_Header>();
  auto name = hdr->name.name;

  builder->append_line("`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseNextRule(w_%s, StateDeparse%s, %d))));", name, CamelCase(name), width);
  builder->append_line("`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseLoadRule(StateDeparse%s, %d))));", CamelCase(name), width);
  builder->append_line("`COLLECT_RULE(deparse_fsm, joinRules(vec(genDeparseSendRule(StateDeparse%s, %d))));", CamelCase(name), width);
  num_rules += 3;
  return false;
}

class DeparserStateVisitor : public Inspector {
  public:
    DeparserStateVisitor(const FPGADeparser* deparser, CodeBuilder* builder) :
      builder(builder) {}
    bool preorder(const IR::BSV::DeparseState* state) override;
  private:
    const FPGAProgram* program;
    CodeBuilder* builder;
};

bool DeparserStateVisitor::preorder(const IR::BSV::DeparseState* state) {
  auto hdr = state->to<IR::Type_Header>();
  auto name = hdr->name.name;
  builder->append_format("PulseWire w_%s <- mkPulseWire();", name);
  return false;
}

// Convert emit() to IR::BSV::DeparseState
bool FPGADeparser::build() {
  auto stat = controlBlock->container->body;
  DeparserBuilder visitor(this, program);
  stat->apply(visitor);
  return true;
}

void FPGADeparser::emitEnums() {
  builder->append_line("`ifdef DEPARSER_STRUCT");
  builder->append_line("typedef enum {");
  builder->incr_indent();
  builder->append_line("StateDeparseStart,");
  for (auto r : states) {
    auto name = r->name.name;
    if (r != states.back()) {
      builder->append_format("StateDeparse%s,", CamelCase(name));
    } else {
      builder->append_format("StateDeparse%s", CamelCase(name));
    }
  }
  builder->decr_indent();
  builder->append_line("} DeparserState deriving (Bits, Eq, FShow);");
  builder->append_line("`endif  // DEPARSER_STRUCT");
}

void FPGADeparser::emitRules() {
  builder->append_line("`ifdef DEPARSER_RULES");
  // deparse rules are mutually exclusive
//  std::vector<cstring> exclusive_rules;
//  for (auto r : states) {
//    cstring rl = cstring("rl_deparse_") + r->name.toString() + cstring("_next");
//    exclusive_rules.push_back(rl);
//  }
//  auto exclusive_annotation = cstring("(* mutually_exclusive=\"");
//  for (auto r : exclusive_rules) {
//    exclusive_annotation += r;
//    if (r != exclusive_rules.back()) {
//      exclusive_annotation += cstring(",");
//    }
//  }
//  exclusive_annotation += cstring("\" *)");
//  builder->append_line(exclusive_annotation);

  int num_rules = 0;
  DeparserRuleVisitor visitor(this, builder, num_rules);
  for (auto r : states) {
    r->apply(visitor);
  }
  builder->append_line("Vector#(%d, Rules) fsmRules = toVector(deparse_fsm);", num_rules);
  builder->append_line("`endif  // DEPARSER_RULES");
}

void FPGADeparser::emitStates() {
  builder->append_line("`ifdef DEPARSER_STATE");

  // pulsewire to initiate next state
  DeparserStateVisitor visitor(this, builder);
  for (auto r : states) {
    r->apply(visitor);
  }
  builder->append_line("");

  // Function: next_parse_state
  auto len = states.size();
  // bit0 is by default 0.
  auto lenp1 = len + 1;
  builder->append_format("function Bit#(%d) nextDeparseState(MetadataT metadata);", lenp1);
  builder->incr_indent();
  builder->append_format("Vector#(%d, Bool) headerValid;", lenp1);
  builder->append_line("headerValid[0] = False;");
  for (int i = 0; i < states.size(); i++) {
    cstring name = states.at(i)->indexed_name;
    builder->append_format("headerValid[%d] = checkForward(metadata.hdr.%s);", i+1, name);
  }
  builder->append_line("let vec = pack(headerValid);");
  builder->append_line("return vec;");
  builder->decr_indent();
  builder->append_line("endfunction");
  builder->append_line("");

  // Function: transit_next_state
  builder->append_line("function Action transit_next_state(MetadataT metadata);");
  builder->incr_indent();
  builder->append_line("action");
  builder->append_line("let vec = nextDeparseState(metadata);");
  builder->append_line("if (vec == 0) begin");
  builder->incr_indent();
  builder->append_line("header_done <= True;");
  builder->decr_indent();
  builder->append_line("end");
  builder->append_line("else begin");
  builder->incr_indent();
  auto nextVecLen = ceil(log2(lenp1));
  builder->append_format("Bit#(%d) nextHeader = truncate(pack(countZerosLSB(vec)%% %d));", nextVecLen, lenp1 );
  builder->append_line("DeparserState nextState = unpack(nextHeader);");
  builder->append_line("case (nextState) matches");
  builder->incr_indent();
  for (int i = 0; i < states.size(); i++) {
    auto name = states.at(i)->name.name;
    builder->append_format("StateDeparse%s: w_%s.send();", CamelCase(name), name);
  }
  builder->append_line("default: $display(\"ERROR: unknown states.\");");
  builder->decr_indent();
  builder->append_line("endcase");
  builder->decr_indent();
  builder->append_line("end");
  builder->append_line("endaction");
  builder->decr_indent();
  builder->append_line("endfunction");

  // Function: update_metadata
  builder->append_line("function MetadataT update_metadata(DeparserState state);");
  builder->incr_indent();
  builder->append_line("let metadata = rg_metadata;");
  builder->append_line("case (state) matches");
  builder->incr_indent();
  for (auto s : states) {
    cstring name = s->name.toString();
    cstring indexed_name = s->indexed_name;
    builder->append_line("StateDeparse%s :", CamelCase(name));
    builder->incr_indent();
    builder->append_format("metadata.hdr.%s = updateState(metadata.hdr.%s, tagged StructDefines::NotPresent);", indexed_name, indexed_name);
    builder->decr_indent();
  }
  builder->decr_indent();
  builder->append_line("endcase");
  builder->append_line("return metadata;");
  builder->decr_indent();
  builder->append_line("endfunction");
  builder->append_line("let initState = StateDeparse%s;", CamelCase(states[0]->name.toString()));
  builder->append_line("`endif  // DEPARSER_STATE");

}

void FPGADeparser::emit(BSVProgram & bsv) {
  builder = &bsv.getDeparserBuilder();
  emitEnums();
  emitRules();
  emitStates();
}

}  // namespace FPGA
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2010-2011 Digital Bazaar, Inc. All rights reserved.
 */
#include "monarch/ws/RestfulHandler.h"

#include "monarch/rt/DynamicObjectIterator.h"

using namespace std;
using namespace monarch::http;
using namespace monarch::rt;
using namespace monarch::util;
using namespace monarch::ws;

RestfulHandler::RestfulHandler()
{
}

RestfulHandler::~RestfulHandler()
{
   // free regexes
   for(RegexList::iterator i = mRegexList.begin(); i != mRegexList.end(); ++i)
   {
      free(*i);
   }
}

void RestfulHandler::operator()(ServiceChannel* ch)
{
   // enforce secure connection if appropriate
   if(mSecureOnly && !ch->getRequest()->getConnection()->isSecure())
   {
      // send 404
      ch->getResponse()->getHeader()->setStatus(404, "Not Found");
      ch->sendNoContent();
   }
   else
   {
      handleChannel(ch, findHandler(ch));
   }
}

/**
 * Creates a query-variable key for the HandlerInfoMap.
 *
 * @param queryVars the query vars to base the key on.
 *
 * @return the query-variable key.
 */
static DynamicObject _createQueryVarKey(DynamicObject* queryVars)
{
   DynamicObject rval(NULL);

   if(queryVars != NULL && !(*queryVars).isNull())
   {
      // arrayify and sort all values
      rval = DynamicObject(Map);
      DynamicObjectIterator i = queryVars->getIterator();
      while(i->hasNext())
      {
         DynamicObject& next = i->next();
         rval[i->getName()] = next.arrayify().sort();
      }
   }

   return rval;
}

void RestfulHandler::addHandler(
   PathHandlerRef handler,
   Message::MethodType mt,
   int paramCount,
   DynamicObject* queryVars,
   monarch::validation::ValidatorRef* queryValidator,
   monarch::validation::ValidatorRef* contentValidator,
   uint32_t flags)
{
   initializeHandlerInfo(
      mPathHandlers[paramCount][mt][_createQueryVarKey(queryVars)],
      handler, NULL, queryValidator, contentValidator, flags);
}

void RestfulHandler::addHandler(
   PathHandlerRef handler,
   Message::MethodType mt,
   DynamicObject* queryVars,
   monarch::validation::ValidatorRef* resourceValidator,
   monarch::validation::ValidatorRef* queryValidator,
   monarch::validation::ValidatorRef* contentValidator,
   uint32_t flags)
{
   int paramCount = (resourceValidator != NULL)
      ? (*resourceValidator)->length()
      : 0;
   initializeHandlerInfo(
      mPathHandlers[paramCount][mt][_createQueryVarKey(queryVars)],
      handler, resourceValidator, queryValidator, contentValidator, flags);
}

bool RestfulHandler::addRegexHandler(
   const char* regex,
   PathHandlerRef handler,
   Message::MethodType mt,
   DynamicObject* queryVars,
   monarch::validation::ValidatorRef* queryValidator,
   monarch::validation::ValidatorRef* contentValidator,
   uint32_t flags)
{
   bool rval = true;

   // look up the regex
   RegexInfo* rinfo = NULL;
   RegexMap::iterator i = mRegexMap.find(regex);
   if(i != mRegexMap.end())
   {
      rinfo = &(mRegexMap[regex]);
   }
   else
   {
      // new regex, try to compile the pattern
      PatternRef p = Pattern::compile(regex);
      if(p == NULL)
      {
         ExceptionRef e = new Exception(
            "Could not add WebService handler. Invalid regular expression.",
            "monarch.ws.InvalidRegularExpression");
         e->getDetails()["pattern"] = regex;
         Exception::set(e);
         rval = false;
      }
      else
      {
         // insert regex entry
         char* copy = strdup(regex);
         mRegexList.push_back(copy);
         rinfo = &(mRegexMap[copy]);
         rinfo->pattern = p;
      }
   }

   // add handler info
   if(rinfo != NULL)
   {
      initializeHandlerInfo(
         rinfo->methods[mt][_createQueryVarKey(queryVars)],
         handler, NULL, queryValidator, contentValidator, flags);
   }

   return rval;
}

void RestfulHandler::initializeHandlerInfo(
   HandlerInfo& info,
   PathHandlerRef& handler,
   monarch::validation::ValidatorRef* resourceValidator,
   monarch::validation::ValidatorRef* queryValidator,
   monarch::validation::ValidatorRef* contentValidator,
   uint32_t flags)
{
   // inherit exception handler if available
   if(!mExceptionHandlerRef.isNull())
   {
      handler->setExceptionHandlerRef(mExceptionHandlerRef);
   }
   else if(mExceptionHandler != NULL)
   {
      handler->setExceptionHandler(mExceptionHandler, false);
   }

   if(resourceValidator != NULL)
   {
      info.resourceValidator = *resourceValidator;
   }
   if(queryValidator != NULL)
   {
      info.queryValidator = *queryValidator;
   }
   if(contentValidator != NULL)
   {
      info.contentValidator = *contentValidator;
   }
   info.handler = handler;
   info.flags = flags;
}

static Message::MethodType _getMethodType(ServiceChannel* ch, string& method)
{
   Message::MethodType mt = Message::Undefined;

   // allow X-Method-Override on request
   HttpRequestHeader* header = ch->getRequest()->getHeader();
   if(header->hasField("X-Method-Override"))
   {
      method = header->getFieldValue("X-Method-Override");
      mt = Message::stringToMethod(method.c_str());
   }
   if(mt == Message::Undefined)
   {
      method = header->getMethod();
      mt = Message::stringToMethod(method.c_str());
   }

   return mt;
}

RestfulHandler::HandlerInfo* RestfulHandler::findHandler(ServiceChannel* ch)
{
   HandlerInfo* rval = NULL;

   // keep track of error response to send: send a 404 if no path is found at
   // all, but if one is found, but there is no method for it, send a 405
   bool send404 = true;

   // get path params, query vars, and method type from channel
   DynamicObject paramDyno;
   ch->getPathParams(paramDyno);
   int paramCount = paramDyno->length();
   DynamicObject queryVars;
   ch->getQuery(queryVars, true);
   string method;
   Message::MethodType mt = _getMethodType(ch, method);
   DynamicObject validMethods(NULL);

   // try to find path handler using param count
   HandlerMap::iterator hmi = mPathHandlers.find(paramCount);
   if(hmi == mPathHandlers.end())
   {
      // no handler found for specific param count, so check arbitrary count
      hmi = mPathHandlers.find(-1);
   }

   // potential handler found, check method types
   MethodMap::iterator mmi;
   if(hmi != mPathHandlers.end())
   {
      // path match found, so if methods don't match, return a 405 not a 404
      send404 = false;

      // find the map of valid methods for the given handler
      MethodMap& mm = hmi->second;
      mmi = mm.find(mt);

      // if there's no match for a valid method using the given param count,
      // try looking for one using the arbitrary param count
      if(mmi == mm.end() && hmi->first != -1)
      {
         hmi = mPathHandlers.find(-1);
         if(hmi != mPathHandlers.end())
         {
            mm = hmi->second;
            mmi = mm.find(mt);
         }
      }

      // see if there is a match for the given request method
      if(mmi != mm.end())
      {
         rval = findHandler(mmi->second, queryVars);
      }
      else
      {
         // add valid method types
         validMethods = DynamicObject();
         validMethods->setType(Array);
         for(mmi = mm.begin(); mmi != mm.end(); ++mmi)
         {
            validMethods->append(Message::methodToString(mmi->first));
         }
      }
   }

   // no handler found yet, check regexes
   if(rval == NULL && mRegexList.size() > 0)
   {
      // get relative local path (the part of the path after the base path)
      const char* path = ch->getPath() + (strlen(ch->getBasePath()) - 1);

      // get path up to query (do not regex query-part)
      int len = strlen(path);
      char p[len + 1];
      strcpy(p, path);
      char* pos = strchr(p, '?');
      if(pos != NULL)
      {
         *pos = 0;
      }

      // check each regex
      DynamicObject matches;
      for(RegexList::iterator i = mRegexList.begin();
          rval == NULL && i != mRegexList.end(); ++i)
      {
         RegexMap::iterator rmi = mRegexMap.find(*i);
         if(rmi->second.pattern->getSubMatches(p, matches, -1, false, 1))
         {
            send404 = false;

            // look for a handler with a matching method
            MethodMap& mm = rmi->second.methods;
            mmi = mm.find(mt);
            if(mmi != mm.end())
            {
               // handler found, set channel handler info
               rval = findHandler(mmi->second, queryVars);
               DynamicObject info(Map);
               info["type"] = "monarch.ws.RestfulHandler";
               info["matches"] = matches;
               ch->setHandlerInfo(info);
            }
            else if(validMethods.isNull())
            {
               // add valid method types
               validMethods = DynamicObject();
               validMethods->setType(Array);
               for(mmi = mm.begin(); mmi != mm.end(); ++mmi)
               {
                  validMethods->append(Message::methodToString(mmi->first));
               }
            }
         }
      }
   }

   // if no handler found
   if(rval == NULL)
   {
      // no such path found
      if(send404)
      {
         // no handler found, send 404
         ch->getResponse()->getHeader()->setStatus(404, "Not Found");
         ExceptionRef e = new Exception(
            "Resource not found.",
            "monarch.ws.ResourceNotFound");
         e->getDetails()["httpStatusCode"] = 404;
         e->getDetails()["resource"] = ch->getPath();
         Exception::set(e);
      }
      // path match was found, but method wasn't supported
      else
      {
         // 405
         ch->getResponse()->getHeader()->setStatus(405, "Method Not Allowed");
         ExceptionRef e = new Exception(
            "Method not allowed.",
            "monarch.ws.MethodNotAllowed");
         e->getDetails()["httpStatusCode"] = 405;
         e->getDetails()["invalidMethod"] = method.c_str();
         e->getDetails()["validMethods"] = validMethods;

         // set allow header
         string allow = StringTools::join(
            e->getDetails()["validMethods"], ", ");
         ch->getResponse()->getHeader()->setField("Allow", allow.c_str());
         Exception::set(e);
      }
   }

   return rval;
}

RestfulHandler::HandlerInfo* RestfulHandler::findHandler(
   HandlerInfoMap& him, DynamicObject& queryVars)
{
   HandlerInfo* rval = NULL;

   // find the queryVar with the most specific matches
   int maxKeyMatches = 0;
   int maxValMatches = 0;
   bool allKeysMatch = false;
   for(HandlerInfoMap::iterator himi = him.begin(); himi != him.end(); ++himi)
   {
      DynamicObject& qVar = const_cast<DynamicObject&>(himi->first);

      // catch-all queryVar
      if(qVar.isNull())
      {
         if(rval == NULL)
         {
            rval = &himi->second;
         }
      }
      // more specific queryVar
      else
      {
         // count matches
         int keyMatches = 0;
         int valMatches = 0;
         DynamicObjectIterator ki = queryVars.getIterator();
         while(ki->hasNext())
         {
            DynamicObject& values = ki->next();
            if(qVar->hasMember(ki->getName()))
            {
               ++keyMatches;
               DynamicObject& qVarVals = qVar[ki->getName()];
               DynamicObjectIterator vi = values.getIterator();
               while(vi->hasNext())
               {
                  DynamicObject& value = vi->next();
                  if(!qVarVals.isNull() && qVarVals->indexOf(value) != -1)
                  {
                     ++valMatches;
                  }
               }
            }
         }

         // determine if all the keys match exactly
         bool hasSameKeys = (keyMatches == queryVars->length() &&
            keyMatches == qVar->length());

         // pick current handler if:
         // 1. no handler picked yet, OR
         // 2. # of key matches is greater than previous pick or # of key
         //    matches are equal and either:
         // 1. previous pick's keys do not all match but current's do, OR
         // 2. key matches are the same, but current has more value matches
         if(rval == NULL || keyMatches > maxKeyMatches ||
            (keyMatches == maxKeyMatches && (
               (!allKeysMatch && hasSameKeys) ||
               (allKeysMatch == hasSameKeys && valMatches > maxValMatches))))
         {
            maxKeyMatches = keyMatches;
            maxValMatches = valMatches;
            allKeysMatch = hasSameKeys;
            rval = &himi->second;
         }
      }
   }

   return rval;
}

void RestfulHandler::handleChannel(ServiceChannel* ch, HandlerInfo* info)
{
   bool pass = false;

   if(info != NULL && info->handler->canHandleRequest(ch))
   {
      // clear last exception
      Exception::clear();

      // always receive content
      DynamicObject content;
      pass = ch->receiveContent(content);
      bool received = pass;

      // do validation
      if(pass && !info->resourceValidator.isNull())
      {
         DynamicObject params;
         ch->getPathParams(params);
         pass = info->resourceValidator->isValid(params);
      }
      if(pass && !info->queryValidator.isNull())
      {
         DynamicObject query;
         ch->getQuery(query, info->flags & ArrayQuery);
         pass = info->queryValidator->isValid(query);
      }
      if(pass && !info->contentValidator.isNull())
      {
         pass = info->contentValidator->isValid(content);
      }

      if(pass)
      {
         info->handler->handleRequest(ch);
      }
   }

   // if handling failed and nothing has been sent to the client yet, then
   // handle the exception
   if(!pass && !ch->hasSent())
   {
      ExceptionRef e = Exception::get();
      handleChannelException(ch, e);
   }
}
<commit_msg>Remove unused variable.<commit_after>/*
 * Copyright (c) 2010-2011 Digital Bazaar, Inc. All rights reserved.
 */
#include "monarch/ws/RestfulHandler.h"

#include "monarch/rt/DynamicObjectIterator.h"

using namespace std;
using namespace monarch::http;
using namespace monarch::rt;
using namespace monarch::util;
using namespace monarch::ws;

RestfulHandler::RestfulHandler()
{
}

RestfulHandler::~RestfulHandler()
{
   // free regexes
   for(RegexList::iterator i = mRegexList.begin(); i != mRegexList.end(); ++i)
   {
      free(*i);
   }
}

void RestfulHandler::operator()(ServiceChannel* ch)
{
   // enforce secure connection if appropriate
   if(mSecureOnly && !ch->getRequest()->getConnection()->isSecure())
   {
      // send 404
      ch->getResponse()->getHeader()->setStatus(404, "Not Found");
      ch->sendNoContent();
   }
   else
   {
      handleChannel(ch, findHandler(ch));
   }
}

/**
 * Creates a query-variable key for the HandlerInfoMap.
 *
 * @param queryVars the query vars to base the key on.
 *
 * @return the query-variable key.
 */
static DynamicObject _createQueryVarKey(DynamicObject* queryVars)
{
   DynamicObject rval(NULL);

   if(queryVars != NULL && !(*queryVars).isNull())
   {
      // arrayify and sort all values
      rval = DynamicObject(Map);
      DynamicObjectIterator i = queryVars->getIterator();
      while(i->hasNext())
      {
         DynamicObject& next = i->next();
         rval[i->getName()] = next.arrayify().sort();
      }
   }

   return rval;
}

void RestfulHandler::addHandler(
   PathHandlerRef handler,
   Message::MethodType mt,
   int paramCount,
   DynamicObject* queryVars,
   monarch::validation::ValidatorRef* queryValidator,
   monarch::validation::ValidatorRef* contentValidator,
   uint32_t flags)
{
   initializeHandlerInfo(
      mPathHandlers[paramCount][mt][_createQueryVarKey(queryVars)],
      handler, NULL, queryValidator, contentValidator, flags);
}

void RestfulHandler::addHandler(
   PathHandlerRef handler,
   Message::MethodType mt,
   DynamicObject* queryVars,
   monarch::validation::ValidatorRef* resourceValidator,
   monarch::validation::ValidatorRef* queryValidator,
   monarch::validation::ValidatorRef* contentValidator,
   uint32_t flags)
{
   int paramCount = (resourceValidator != NULL)
      ? (*resourceValidator)->length()
      : 0;
   initializeHandlerInfo(
      mPathHandlers[paramCount][mt][_createQueryVarKey(queryVars)],
      handler, resourceValidator, queryValidator, contentValidator, flags);
}

bool RestfulHandler::addRegexHandler(
   const char* regex,
   PathHandlerRef handler,
   Message::MethodType mt,
   DynamicObject* queryVars,
   monarch::validation::ValidatorRef* queryValidator,
   monarch::validation::ValidatorRef* contentValidator,
   uint32_t flags)
{
   bool rval = true;

   // look up the regex
   RegexInfo* rinfo = NULL;
   RegexMap::iterator i = mRegexMap.find(regex);
   if(i != mRegexMap.end())
   {
      rinfo = &(mRegexMap[regex]);
   }
   else
   {
      // new regex, try to compile the pattern
      PatternRef p = Pattern::compile(regex);
      if(p == NULL)
      {
         ExceptionRef e = new Exception(
            "Could not add WebService handler. Invalid regular expression.",
            "monarch.ws.InvalidRegularExpression");
         e->getDetails()["pattern"] = regex;
         Exception::set(e);
         rval = false;
      }
      else
      {
         // insert regex entry
         char* copy = strdup(regex);
         mRegexList.push_back(copy);
         rinfo = &(mRegexMap[copy]);
         rinfo->pattern = p;
      }
   }

   // add handler info
   if(rinfo != NULL)
   {
      initializeHandlerInfo(
         rinfo->methods[mt][_createQueryVarKey(queryVars)],
         handler, NULL, queryValidator, contentValidator, flags);
   }

   return rval;
}

void RestfulHandler::initializeHandlerInfo(
   HandlerInfo& info,
   PathHandlerRef& handler,
   monarch::validation::ValidatorRef* resourceValidator,
   monarch::validation::ValidatorRef* queryValidator,
   monarch::validation::ValidatorRef* contentValidator,
   uint32_t flags)
{
   // inherit exception handler if available
   if(!mExceptionHandlerRef.isNull())
   {
      handler->setExceptionHandlerRef(mExceptionHandlerRef);
   }
   else if(mExceptionHandler != NULL)
   {
      handler->setExceptionHandler(mExceptionHandler, false);
   }

   if(resourceValidator != NULL)
   {
      info.resourceValidator = *resourceValidator;
   }
   if(queryValidator != NULL)
   {
      info.queryValidator = *queryValidator;
   }
   if(contentValidator != NULL)
   {
      info.contentValidator = *contentValidator;
   }
   info.handler = handler;
   info.flags = flags;
}

static Message::MethodType _getMethodType(ServiceChannel* ch, string& method)
{
   Message::MethodType mt = Message::Undefined;

   // allow X-Method-Override on request
   HttpRequestHeader* header = ch->getRequest()->getHeader();
   if(header->hasField("X-Method-Override"))
   {
      method = header->getFieldValue("X-Method-Override");
      mt = Message::stringToMethod(method.c_str());
   }
   if(mt == Message::Undefined)
   {
      method = header->getMethod();
      mt = Message::stringToMethod(method.c_str());
   }

   return mt;
}

RestfulHandler::HandlerInfo* RestfulHandler::findHandler(ServiceChannel* ch)
{
   HandlerInfo* rval = NULL;

   // keep track of error response to send: send a 404 if no path is found at
   // all, but if one is found, but there is no method for it, send a 405
   bool send404 = true;

   // get path params, query vars, and method type from channel
   DynamicObject paramDyno;
   ch->getPathParams(paramDyno);
   int paramCount = paramDyno->length();
   DynamicObject queryVars;
   ch->getQuery(queryVars, true);
   string method;
   Message::MethodType mt = _getMethodType(ch, method);
   DynamicObject validMethods(NULL);

   // try to find path handler using param count
   HandlerMap::iterator hmi = mPathHandlers.find(paramCount);
   if(hmi == mPathHandlers.end())
   {
      // no handler found for specific param count, so check arbitrary count
      hmi = mPathHandlers.find(-1);
   }

   // potential handler found, check method types
   MethodMap::iterator mmi;
   if(hmi != mPathHandlers.end())
   {
      // path match found, so if methods don't match, return a 405 not a 404
      send404 = false;

      // find the map of valid methods for the given handler
      MethodMap& mm = hmi->second;
      mmi = mm.find(mt);

      // if there's no match for a valid method using the given param count,
      // try looking for one using the arbitrary param count
      if(mmi == mm.end() && hmi->first != -1)
      {
         hmi = mPathHandlers.find(-1);
         if(hmi != mPathHandlers.end())
         {
            mm = hmi->second;
            mmi = mm.find(mt);
         }
      }

      // see if there is a match for the given request method
      if(mmi != mm.end())
      {
         rval = findHandler(mmi->second, queryVars);
      }
      else
      {
         // add valid method types
         validMethods = DynamicObject();
         validMethods->setType(Array);
         for(mmi = mm.begin(); mmi != mm.end(); ++mmi)
         {
            validMethods->append(Message::methodToString(mmi->first));
         }
      }
   }

   // no handler found yet, check regexes
   if(rval == NULL && mRegexList.size() > 0)
   {
      // get relative local path (the part of the path after the base path)
      const char* path = ch->getPath() + (strlen(ch->getBasePath()) - 1);

      // get path up to query (do not regex query-part)
      int len = strlen(path);
      char p[len + 1];
      strcpy(p, path);
      char* pos = strchr(p, '?');
      if(pos != NULL)
      {
         *pos = 0;
      }

      // check each regex
      DynamicObject matches;
      for(RegexList::iterator i = mRegexList.begin();
          rval == NULL && i != mRegexList.end(); ++i)
      {
         RegexMap::iterator rmi = mRegexMap.find(*i);
         if(rmi->second.pattern->getSubMatches(p, matches, -1, false, 1))
         {
            send404 = false;

            // look for a handler with a matching method
            MethodMap& mm = rmi->second.methods;
            mmi = mm.find(mt);
            if(mmi != mm.end())
            {
               // handler found, set channel handler info
               rval = findHandler(mmi->second, queryVars);
               DynamicObject info(Map);
               info["type"] = "monarch.ws.RestfulHandler";
               info["matches"] = matches;
               ch->setHandlerInfo(info);
            }
            else if(validMethods.isNull())
            {
               // add valid method types
               validMethods = DynamicObject();
               validMethods->setType(Array);
               for(mmi = mm.begin(); mmi != mm.end(); ++mmi)
               {
                  validMethods->append(Message::methodToString(mmi->first));
               }
            }
         }
      }
   }

   // if no handler found
   if(rval == NULL)
   {
      // no such path found
      if(send404)
      {
         // no handler found, send 404
         ch->getResponse()->getHeader()->setStatus(404, "Not Found");
         ExceptionRef e = new Exception(
            "Resource not found.",
            "monarch.ws.ResourceNotFound");
         e->getDetails()["httpStatusCode"] = 404;
         e->getDetails()["resource"] = ch->getPath();
         Exception::set(e);
      }
      // path match was found, but method wasn't supported
      else
      {
         // 405
         ch->getResponse()->getHeader()->setStatus(405, "Method Not Allowed");
         ExceptionRef e = new Exception(
            "Method not allowed.",
            "monarch.ws.MethodNotAllowed");
         e->getDetails()["httpStatusCode"] = 405;
         e->getDetails()["invalidMethod"] = method.c_str();
         e->getDetails()["validMethods"] = validMethods;

         // set allow header
         string allow = StringTools::join(
            e->getDetails()["validMethods"], ", ");
         ch->getResponse()->getHeader()->setField("Allow", allow.c_str());
         Exception::set(e);
      }
   }

   return rval;
}

RestfulHandler::HandlerInfo* RestfulHandler::findHandler(
   HandlerInfoMap& him, DynamicObject& queryVars)
{
   HandlerInfo* rval = NULL;

   // find the queryVar with the most specific matches
   int maxKeyMatches = 0;
   int maxValMatches = 0;
   bool allKeysMatch = false;
   for(HandlerInfoMap::iterator himi = him.begin(); himi != him.end(); ++himi)
   {
      DynamicObject& qVar = const_cast<DynamicObject&>(himi->first);

      // catch-all queryVar
      if(qVar.isNull())
      {
         if(rval == NULL)
         {
            rval = &himi->second;
         }
      }
      // more specific queryVar
      else
      {
         // count matches
         int keyMatches = 0;
         int valMatches = 0;
         DynamicObjectIterator ki = queryVars.getIterator();
         while(ki->hasNext())
         {
            DynamicObject& values = ki->next();
            if(qVar->hasMember(ki->getName()))
            {
               ++keyMatches;
               DynamicObject& qVarVals = qVar[ki->getName()];
               DynamicObjectIterator vi = values.getIterator();
               while(vi->hasNext())
               {
                  DynamicObject& value = vi->next();
                  if(!qVarVals.isNull() && qVarVals->indexOf(value) != -1)
                  {
                     ++valMatches;
                  }
               }
            }
         }

         // determine if all the keys match exactly
         bool hasSameKeys = (keyMatches == queryVars->length() &&
            keyMatches == qVar->length());

         // pick current handler if:
         // 1. no handler picked yet, OR
         // 2. # of key matches is greater than previous pick or # of key
         //    matches are equal and either:
         // 1. previous pick's keys do not all match but current's do, OR
         // 2. key matches are the same, but current has more value matches
         if(rval == NULL || keyMatches > maxKeyMatches ||
            (keyMatches == maxKeyMatches && (
               (!allKeysMatch && hasSameKeys) ||
               (allKeysMatch == hasSameKeys && valMatches > maxValMatches))))
         {
            maxKeyMatches = keyMatches;
            maxValMatches = valMatches;
            allKeysMatch = hasSameKeys;
            rval = &himi->second;
         }
      }
   }

   return rval;
}

void RestfulHandler::handleChannel(ServiceChannel* ch, HandlerInfo* info)
{
   bool pass = false;

   if(info != NULL && info->handler->canHandleRequest(ch))
   {
      // clear last exception
      Exception::clear();

      // always receive content
      DynamicObject content;
      pass = ch->receiveContent(content);

      // do validation
      if(pass && !info->resourceValidator.isNull())
      {
         DynamicObject params;
         ch->getPathParams(params);
         pass = info->resourceValidator->isValid(params);
      }
      if(pass && !info->queryValidator.isNull())
      {
         DynamicObject query;
         ch->getQuery(query, info->flags & ArrayQuery);
         pass = info->queryValidator->isValid(query);
      }
      if(pass && !info->contentValidator.isNull())
      {
         pass = info->contentValidator->isValid(content);
      }

      if(pass)
      {
         info->handler->handleRequest(ch);
      }
   }

   // if handling failed and nothing has been sent to the client yet, then
   // handle the exception
   if(!pass && !ch->hasSent())
   {
      ExceptionRef e = Exception::get();
      handleChannelException(ch, e);
   }
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "nvs.hpp"
#include "nvs_flash.h"
#include "nvs_storage.hpp"
#include "intrusive_list.h"
#include "nvs_platform.hpp"
#include "esp_partition.h"
#include "sdkconfig.h"

#ifdef ESP_PLATFORM
// Uncomment this line to force output from this module
// #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#include "esp_log.h"
static const char* TAG = "nvs";
#else
#define ESP_LOGD(...)
#endif

class HandleEntry : public intrusive_list_node<HandleEntry>
{
public:
    HandleEntry() {}

    HandleEntry(nvs_handle handle, bool readOnly, uint8_t nsIndex) :
        mHandle(handle),
        mReadOnly(readOnly),
        mNsIndex(nsIndex)
    {
    }

    nvs_handle mHandle;
    uint8_t mReadOnly;
    uint8_t mNsIndex;
};

#ifdef ESP_PLATFORM
SemaphoreHandle_t nvs::Lock::mSemaphore = NULL;
#endif

using namespace std;
using namespace nvs;

static intrusive_list<HandleEntry> s_nvs_handles;
static uint32_t s_nvs_next_handle = 1;
static nvs::Storage s_nvs_storage;

extern "C" void nvs_dump()
{
    Lock lock;
    s_nvs_storage.debugDump();
}

extern "C" esp_err_t nvs_flash_init_custom(uint32_t baseSector, uint32_t sectorCount)
{
    ESP_LOGD(TAG, "nvs_flash_init_custom start=%d count=%d", baseSector, sectorCount);
    s_nvs_handles.clear();
    return s_nvs_storage.init(baseSector, sectorCount);
}

#ifdef ESP_PLATFORM
extern "C" esp_err_t nvs_flash_init(void)
{
    Lock::init();
    Lock lock;
    if (s_nvs_storage.isValid()) {
        return ESP_OK;
    }
    const esp_partition_t* partition = esp_partition_find_first(
            ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL);
    if (partition == NULL) {
        return ESP_ERR_NOT_FOUND;
    }

    return nvs_flash_init_custom(partition->address / SPI_FLASH_SEC_SIZE,
            partition->size / SPI_FLASH_SEC_SIZE);
}

extern "C" esp_err_t nvs_flash_erase()
{
    const esp_partition_t* partition = esp_partition_find_first(
            ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL);
    if (partition == NULL) {
        return ESP_ERR_NOT_FOUND;
    }

    return esp_partition_erase_range(partition, 0, partition->size);
}
#endif

static esp_err_t nvs_find_ns_handle(nvs_handle handle, HandleEntry& entry)
{
    auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), [=](HandleEntry& e) -> bool {
        return e.mHandle == handle;
    });
    if (it == end(s_nvs_handles)) {
        return ESP_ERR_NVS_INVALID_HANDLE;
    }
    entry = *it;
    return ESP_OK;
}

extern "C" esp_err_t nvs_open(const char* name, nvs_open_mode open_mode, nvs_handle *out_handle)
{
    Lock lock;
    ESP_LOGD(TAG, "%s %s %d", __func__, name, open_mode);
    uint8_t nsIndex;
    esp_err_t err = s_nvs_storage.createOrOpenNamespace(name, open_mode == NVS_READWRITE, nsIndex);
    if (err != ESP_OK) {
        return err;
    }

    uint32_t handle = s_nvs_next_handle;
    ++s_nvs_next_handle;
    *out_handle = handle;

    s_nvs_handles.push_back(new HandleEntry(handle, open_mode==NVS_READONLY, nsIndex));
    return ESP_OK;
}

extern "C" void nvs_close(nvs_handle handle)
{
    Lock lock;
    ESP_LOGD(TAG, "%s %d", __func__, handle);
    auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), [=](HandleEntry& e) -> bool {
        return e.mHandle == handle;
    });
    if (it == end(s_nvs_handles)) {
        return;
    }
    s_nvs_handles.erase(it);
    delete static_cast<HandleEntry*>(it);
}

extern "C" esp_err_t nvs_erase_key(nvs_handle handle, const char* key)
{
    Lock lock;
    ESP_LOGD(TAG, "%s %s\r\n", __func__, key);
    HandleEntry entry;
    auto err = nvs_find_ns_handle(handle, entry);
    if (err != ESP_OK) {
        return err;
    }
    if (entry.mReadOnly) {
        return ESP_ERR_NVS_READ_ONLY;
    }
    return s_nvs_storage.eraseItem(entry.mNsIndex, key);
}

extern "C" esp_err_t nvs_erase_all(nvs_handle handle)
{
    Lock lock;
    ESP_LOGD(TAG, "%s\r\n", __func__);
    HandleEntry entry;
    auto err = nvs_find_ns_handle(handle, entry);
    if (err != ESP_OK) {
        return err;
    }
    if (entry.mReadOnly) {
        return ESP_ERR_NVS_READ_ONLY;
    }
    return s_nvs_storage.eraseNamespace(entry.mNsIndex);
}

template<typename T>
static esp_err_t nvs_set(nvs_handle handle, const char* key, T value)
{
    Lock lock;
    ESP_LOGD(TAG, "%s %s %d %d", __func__, key, sizeof(T), (uint32_t) value);
    HandleEntry entry;
    auto err = nvs_find_ns_handle(handle, entry);
    if (err != ESP_OK) {
        return err;
    }
    if (entry.mReadOnly) {
        return ESP_ERR_NVS_READ_ONLY;
    }
    return s_nvs_storage.writeItem(entry.mNsIndex, key, value);
}

extern "C" esp_err_t nvs_set_i8  (nvs_handle handle, const char* key, int8_t value)
{
    return nvs_set(handle, key, value);
}

extern "C" esp_err_t nvs_set_u8  (nvs_handle handle, const char* key, uint8_t value)
{
    return nvs_set(handle, key, value);
}

extern "C" esp_err_t nvs_set_i16 (nvs_handle handle, const char* key, int16_t value)
{
    return nvs_set(handle, key, value);
}

extern "C" esp_err_t nvs_set_u16 (nvs_handle handle, const char* key, uint16_t value)
{
    return nvs_set(handle, key, value);
}

extern "C" esp_err_t nvs_set_i32 (nvs_handle handle, const char* key, int32_t value)
{
    return nvs_set(handle, key, value);
}

extern "C" esp_err_t nvs_set_u32 (nvs_handle handle, const char* key, uint32_t value)
{
    return nvs_set(handle, key, value);
}

extern "C" esp_err_t nvs_set_i64 (nvs_handle handle, const char* key, int64_t value)
{
    return nvs_set(handle, key, value);
}

extern "C" esp_err_t nvs_set_u64 (nvs_handle handle, const char* key, uint64_t value)
{
    return nvs_set(handle, key, value);
}

extern "C" esp_err_t nvs_commit(nvs_handle handle)
{
    Lock lock;
    // no-op for now, to be used when intermediate cache is added
    HandleEntry entry;
    return nvs_find_ns_handle(handle, entry);
}

extern "C" esp_err_t nvs_set_str(nvs_handle handle, const char* key, const char* value)
{
    Lock lock;
    ESP_LOGD(TAG, "%s %s %s", __func__, key, value);
    HandleEntry entry;
    auto err = nvs_find_ns_handle(handle, entry);
    if (err != ESP_OK) {
        return err;
    }
    return s_nvs_storage.writeItem(entry.mNsIndex, nvs::ItemType::SZ, key, value, strlen(value) + 1);
}

extern "C" esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, size_t length)
{
    Lock lock;
    ESP_LOGD(TAG, "%s %s %d", __func__, key, length);
    HandleEntry entry;
    auto err = nvs_find_ns_handle(handle, entry);
    if (err != ESP_OK) {
        return err;
    }
    return s_nvs_storage.writeItem(entry.mNsIndex, nvs::ItemType::BLOB, key, value, length);
}

template<typename T>
static esp_err_t nvs_get(nvs_handle handle, const char* key, T* out_value)
{
    Lock lock;
    ESP_LOGD(TAG, "%s %s %d", __func__, key, sizeof(T));
    HandleEntry entry;
    auto err = nvs_find_ns_handle(handle, entry);
    if (err != ESP_OK) {
        return err;
    }
    return s_nvs_storage.readItem(entry.mNsIndex, key, *out_value);
}

extern "C" esp_err_t nvs_get_i8  (nvs_handle handle, const char* key, int8_t* out_value)
{
    return nvs_get(handle, key, out_value);
}

extern "C" esp_err_t nvs_get_u8  (nvs_handle handle, const char* key, uint8_t* out_value)
{
    return nvs_get(handle, key, out_value);
}

extern "C" esp_err_t nvs_get_i16 (nvs_handle handle, const char* key, int16_t* out_value)
{
    return nvs_get(handle, key, out_value);
}

extern "C" esp_err_t nvs_get_u16 (nvs_handle handle, const char* key, uint16_t* out_value)
{
    return nvs_get(handle, key, out_value);
}

extern "C" esp_err_t nvs_get_i32 (nvs_handle handle, const char* key, int32_t* out_value)
{
    return nvs_get(handle, key, out_value);
}

extern "C" esp_err_t nvs_get_u32 (nvs_handle handle, const char* key, uint32_t* out_value)
{
    return nvs_get(handle, key, out_value);
}

extern "C" esp_err_t nvs_get_i64 (nvs_handle handle, const char* key, int64_t* out_value)
{
    return nvs_get(handle, key, out_value);
}

extern "C" esp_err_t nvs_get_u64 (nvs_handle handle, const char* key, uint64_t* out_value)
{
    return nvs_get(handle, key, out_value);
}

static esp_err_t nvs_get_str_or_blob(nvs_handle handle, nvs::ItemType type, const char* key, void* out_value, size_t* length)
{
    Lock lock;
    ESP_LOGD(TAG, "%s %s", __func__, key);
    HandleEntry entry;
    auto err = nvs_find_ns_handle(handle, entry);
    if (err != ESP_OK) {
        return err;
    }

    size_t dataSize;
    err = s_nvs_storage.getItemDataSize(entry.mNsIndex, type, key, dataSize);
    if (err != ESP_OK) {
        return err;
    }

    if (length == nullptr) {
        return ESP_ERR_NVS_INVALID_LENGTH;
    } else if (out_value == nullptr) {
        *length = dataSize;
        return ESP_OK;
    } else if (*length < dataSize) {
        *length = dataSize;
        return ESP_ERR_NVS_INVALID_LENGTH;
    }

    return s_nvs_storage.readItem(entry.mNsIndex, type, key, out_value, dataSize);
}

extern "C" esp_err_t nvs_get_str(nvs_handle handle, const char* key, char* out_value, size_t* length)
{
    return nvs_get_str_or_blob(handle, nvs::ItemType::SZ, key, out_value, length);
}

extern "C" esp_err_t nvs_get_blob(nvs_handle handle, const char* key, void* out_value, size_t* length)
{
    return nvs_get_str_or_blob(handle, nvs::ItemType::BLOB, key, out_value, length);
}

<commit_msg>nvs_flash: Reduced visibility of handle counter<commit_after>// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "nvs.hpp"
#include "nvs_flash.h"
#include "nvs_storage.hpp"
#include "intrusive_list.h"
#include "nvs_platform.hpp"
#include "esp_partition.h"
#include "sdkconfig.h"

#ifdef ESP_PLATFORM
// Uncomment this line to force output from this module
// #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#include "esp_log.h"
static const char* TAG = "nvs";
#else
#define ESP_LOGD(...)
#endif

class HandleEntry : public intrusive_list_node<HandleEntry>
{
    static uint32_t s_nvs_next_handle;
public:
    HandleEntry() {}

    HandleEntry(bool readOnly, uint8_t nsIndex) :
        mHandle(++s_nvs_next_handle),  // Begin the handle value with 1
        mReadOnly(readOnly),
        mNsIndex(nsIndex)
    {
    }

    nvs_handle mHandle;
    uint8_t mReadOnly;
    uint8_t mNsIndex;
};

#ifdef ESP_PLATFORM
SemaphoreHandle_t nvs::Lock::mSemaphore = NULL;
#endif

using namespace std;
using namespace nvs;

static intrusive_list<HandleEntry> s_nvs_handles;
uint32_t HandleEntry::s_nvs_next_handle;
static nvs::Storage s_nvs_storage;

extern "C" void nvs_dump()
{
    Lock lock;
    s_nvs_storage.debugDump();
}

extern "C" esp_err_t nvs_flash_init_custom(uint32_t baseSector, uint32_t sectorCount)
{
    ESP_LOGD(TAG, "nvs_flash_init_custom start=%d count=%d", baseSector, sectorCount);
    s_nvs_handles.clear();
    return s_nvs_storage.init(baseSector, sectorCount);
}

#ifdef ESP_PLATFORM
extern "C" esp_err_t nvs_flash_init(void)
{
    Lock::init();
    Lock lock;
    if (s_nvs_storage.isValid()) {
        return ESP_OK;
    }
    const esp_partition_t* partition = esp_partition_find_first(
            ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL);
    if (partition == NULL) {
        return ESP_ERR_NOT_FOUND;
    }

    return nvs_flash_init_custom(partition->address / SPI_FLASH_SEC_SIZE,
            partition->size / SPI_FLASH_SEC_SIZE);
}

extern "C" esp_err_t nvs_flash_erase()
{
    const esp_partition_t* partition = esp_partition_find_first(
            ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL);
    if (partition == NULL) {
        return ESP_ERR_NOT_FOUND;
    }

    return esp_partition_erase_range(partition, 0, partition->size);
}
#endif

static esp_err_t nvs_find_ns_handle(nvs_handle handle, HandleEntry& entry)
{
    auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), [=](HandleEntry& e) -> bool {
        return e.mHandle == handle;
    });
    if (it == end(s_nvs_handles)) {
        return ESP_ERR_NVS_INVALID_HANDLE;
    }
    entry = *it;
    return ESP_OK;
}

extern "C" esp_err_t nvs_open(const char* name, nvs_open_mode open_mode, nvs_handle *out_handle)
{
    Lock lock;
    ESP_LOGD(TAG, "%s %s %d", __func__, name, open_mode);
    uint8_t nsIndex;
    esp_err_t err = s_nvs_storage.createOrOpenNamespace(name, open_mode == NVS_READWRITE, nsIndex);
    if (err != ESP_OK) {
        return err;
    }

    HandleEntry *handle_entry = new HandleEntry(open_mode==NVS_READONLY, nsIndex);
    s_nvs_handles.push_back(handle_entry);

    *out_handle = handle_entry->mHandle;

    return ESP_OK;
}

extern "C" void nvs_close(nvs_handle handle)
{
    Lock lock;
    ESP_LOGD(TAG, "%s %d", __func__, handle);
    auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), [=](HandleEntry& e) -> bool {
        return e.mHandle == handle;
    });
    if (it == end(s_nvs_handles)) {
        return;
    }
    s_nvs_handles.erase(it);
    delete static_cast<HandleEntry*>(it);
}

extern "C" esp_err_t nvs_erase_key(nvs_handle handle, const char* key)
{
    Lock lock;
    ESP_LOGD(TAG, "%s %s\r\n", __func__, key);
    HandleEntry entry;
    auto err = nvs_find_ns_handle(handle, entry);
    if (err != ESP_OK) {
        return err;
    }
    if (entry.mReadOnly) {
        return ESP_ERR_NVS_READ_ONLY;
    }
    return s_nvs_storage.eraseItem(entry.mNsIndex, key);
}

extern "C" esp_err_t nvs_erase_all(nvs_handle handle)
{
    Lock lock;
    ESP_LOGD(TAG, "%s\r\n", __func__);
    HandleEntry entry;
    auto err = nvs_find_ns_handle(handle, entry);
    if (err != ESP_OK) {
        return err;
    }
    if (entry.mReadOnly) {
        return ESP_ERR_NVS_READ_ONLY;
    }
    return s_nvs_storage.eraseNamespace(entry.mNsIndex);
}

template<typename T>
static esp_err_t nvs_set(nvs_handle handle, const char* key, T value)
{
    Lock lock;
    ESP_LOGD(TAG, "%s %s %d %d", __func__, key, sizeof(T), (uint32_t) value);
    HandleEntry entry;
    auto err = nvs_find_ns_handle(handle, entry);
    if (err != ESP_OK) {
        return err;
    }
    if (entry.mReadOnly) {
        return ESP_ERR_NVS_READ_ONLY;
    }
    return s_nvs_storage.writeItem(entry.mNsIndex, key, value);
}

extern "C" esp_err_t nvs_set_i8  (nvs_handle handle, const char* key, int8_t value)
{
    return nvs_set(handle, key, value);
}

extern "C" esp_err_t nvs_set_u8  (nvs_handle handle, const char* key, uint8_t value)
{
    return nvs_set(handle, key, value);
}

extern "C" esp_err_t nvs_set_i16 (nvs_handle handle, const char* key, int16_t value)
{
    return nvs_set(handle, key, value);
}

extern "C" esp_err_t nvs_set_u16 (nvs_handle handle, const char* key, uint16_t value)
{
    return nvs_set(handle, key, value);
}

extern "C" esp_err_t nvs_set_i32 (nvs_handle handle, const char* key, int32_t value)
{
    return nvs_set(handle, key, value);
}

extern "C" esp_err_t nvs_set_u32 (nvs_handle handle, const char* key, uint32_t value)
{
    return nvs_set(handle, key, value);
}

extern "C" esp_err_t nvs_set_i64 (nvs_handle handle, const char* key, int64_t value)
{
    return nvs_set(handle, key, value);
}

extern "C" esp_err_t nvs_set_u64 (nvs_handle handle, const char* key, uint64_t value)
{
    return nvs_set(handle, key, value);
}

extern "C" esp_err_t nvs_commit(nvs_handle handle)
{
    Lock lock;
    // no-op for now, to be used when intermediate cache is added
    HandleEntry entry;
    return nvs_find_ns_handle(handle, entry);
}

extern "C" esp_err_t nvs_set_str(nvs_handle handle, const char* key, const char* value)
{
    Lock lock;
    ESP_LOGD(TAG, "%s %s %s", __func__, key, value);
    HandleEntry entry;
    auto err = nvs_find_ns_handle(handle, entry);
    if (err != ESP_OK) {
        return err;
    }
    return s_nvs_storage.writeItem(entry.mNsIndex, nvs::ItemType::SZ, key, value, strlen(value) + 1);
}

extern "C" esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, size_t length)
{
    Lock lock;
    ESP_LOGD(TAG, "%s %s %d", __func__, key, length);
    HandleEntry entry;
    auto err = nvs_find_ns_handle(handle, entry);
    if (err != ESP_OK) {
        return err;
    }
    return s_nvs_storage.writeItem(entry.mNsIndex, nvs::ItemType::BLOB, key, value, length);
}

template<typename T>
static esp_err_t nvs_get(nvs_handle handle, const char* key, T* out_value)
{
    Lock lock;
    ESP_LOGD(TAG, "%s %s %d", __func__, key, sizeof(T));
    HandleEntry entry;
    auto err = nvs_find_ns_handle(handle, entry);
    if (err != ESP_OK) {
        return err;
    }
    return s_nvs_storage.readItem(entry.mNsIndex, key, *out_value);
}

extern "C" esp_err_t nvs_get_i8  (nvs_handle handle, const char* key, int8_t* out_value)
{
    return nvs_get(handle, key, out_value);
}

extern "C" esp_err_t nvs_get_u8  (nvs_handle handle, const char* key, uint8_t* out_value)
{
    return nvs_get(handle, key, out_value);
}

extern "C" esp_err_t nvs_get_i16 (nvs_handle handle, const char* key, int16_t* out_value)
{
    return nvs_get(handle, key, out_value);
}

extern "C" esp_err_t nvs_get_u16 (nvs_handle handle, const char* key, uint16_t* out_value)
{
    return nvs_get(handle, key, out_value);
}

extern "C" esp_err_t nvs_get_i32 (nvs_handle handle, const char* key, int32_t* out_value)
{
    return nvs_get(handle, key, out_value);
}

extern "C" esp_err_t nvs_get_u32 (nvs_handle handle, const char* key, uint32_t* out_value)
{
    return nvs_get(handle, key, out_value);
}

extern "C" esp_err_t nvs_get_i64 (nvs_handle handle, const char* key, int64_t* out_value)
{
    return nvs_get(handle, key, out_value);
}

extern "C" esp_err_t nvs_get_u64 (nvs_handle handle, const char* key, uint64_t* out_value)
{
    return nvs_get(handle, key, out_value);
}

static esp_err_t nvs_get_str_or_blob(nvs_handle handle, nvs::ItemType type, const char* key, void* out_value, size_t* length)
{
    Lock lock;
    ESP_LOGD(TAG, "%s %s", __func__, key);
    HandleEntry entry;
    auto err = nvs_find_ns_handle(handle, entry);
    if (err != ESP_OK) {
        return err;
    }

    size_t dataSize;
    err = s_nvs_storage.getItemDataSize(entry.mNsIndex, type, key, dataSize);
    if (err != ESP_OK) {
        return err;
    }

    if (length == nullptr) {
        return ESP_ERR_NVS_INVALID_LENGTH;
    } else if (out_value == nullptr) {
        *length = dataSize;
        return ESP_OK;
    } else if (*length < dataSize) {
        *length = dataSize;
        return ESP_ERR_NVS_INVALID_LENGTH;
    }

    return s_nvs_storage.readItem(entry.mNsIndex, type, key, out_value, dataSize);
}

extern "C" esp_err_t nvs_get_str(nvs_handle handle, const char* key, char* out_value, size_t* length)
{
    return nvs_get_str_or_blob(handle, nvs::ItemType::SZ, key, out_value, length);
}

extern "C" esp_err_t nvs_get_blob(nvs_handle handle, const char* key, void* out_value, size_t* length)
{
    return nvs_get_str_or_blob(handle, nvs::ItemType::BLOB, key, out_value, length);
}

<|endoftext|>