<commit_before>//
// ogles_gpgpu project - GPGPU for mobile devices and embedded systems using OpenGL ES 2.0
//
// Author: Markus Konrad <post@mkonrad.net>, Winter 2014/2015
// http://www.mkonrad.net
//
// See LICENSE file in project repository root for the license.
//

#include "memtransfer.h"

using namespace ogles_gpgpu;

#pragma mark static methods

bool MemTransfer::initPlatformOptimizations() {
    // always return false here. this method is only fully implemented
    // in platform-specialized classes of MemTransfer.
    return false;
}

#pragma mark constructor/deconstructor

MemTransfer::MemTransfer() {
    // set defaults
    inputW = inputH = outputW = outputH = 0;
    inputTexId = 0;
    outputTexId = 0;
    initialized = false;
    preparedInput = false;
    preparedOutput = false;
    inputPixelFormat = GL_RGBA;
}

MemTransfer::~MemTransfer() {
    // release in- and output
    releaseInput();
    releaseOutput();
}

#pragma mark public methods

GLuint MemTransfer::prepareInput(int inTexW, int inTexH, GLenum inputPxFormat, void *inputDataPtr) {
    assert(initialized && inTexW > 0 && inTexH > 0);

    if (inputW == inTexW && inputH == inTexH && inputPixelFormat == inputPxFormat) {
        return inputTexId; // no change
    }

    if (preparedInput) {    // already prepared -- release buffers!
        releaseInput();
    }

    // set attributes
    inputW = inTexW;
    inputH = inTexH;
    inputPixelFormat = inputPxFormat;

    // generate texture id
    glGenTextures(1, &inputTexId);

    if (inputTexId == 0) {
        OG_LOGERR("MemTransfer", "no valid input texture generated");
        return 0;
    }

    // done
    preparedInput = true;

    return inputTexId;
}

GLuint MemTransfer::prepareOutput(int outTexW, int outTexH) {
    assert(initialized && outTexW > 0 && outTexH > 0);

    if (outputW == outTexW && outputH == outTexH) {
        return outputTexId; // no change
    }

    if (preparedOutput) {    // already prepared -- release buffers!
        releaseOutput();
    }

    // set attributes
    outputW = outTexW;
    outputH = outTexH;

    // generate texture id
    glGenTextures(1, &outputTexId);

    if (outputTexId == 0) {
        OG_LOGERR("MemTransfer", "no valid output texture generated");
        return 0;
    }

    // will bind the texture, too:
    setCommonTextureParams(outputTexId);

    Tools::checkGLErr("MemTransfer", "fbo texture parameters");

    // create empty texture space on GPU
    glTexImage2D(GL_TEXTURE_2D, 0,
		 GL_RGBA,
		 outTexW, outTexH, 0,
		 GL_RGBA, GL_UNSIGNED_BYTE,
		 NULL);	// we do not need to pass texture data -> it will be generated!

    Tools::checkGLErr("MemTransfer", "fbo texture creation");

    // done
    preparedOutput = true;

    return outputTexId;
}

void MemTransfer::releaseInput() {
    if (inputTexId > 0) {
        glDeleteTextures(1, &inputTexId);
        inputTexId = 0;
    }
}

void MemTransfer::releaseOutput() {
    if (outputTexId > 0) {
        glDeleteTextures(1, &outputTexId);
        outputTexId = 0;
    }
}

void MemTransfer::toGPU(const unsigned char *buf) {
    assert(preparedInput && inputTexId > 0 && buf);

    glBindTexture(GL_TEXTURE_2D, inputTexId);	// bind input texture

    // copy data as texture to GPU
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, inputW, inputH, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);

    // check for error
    Tools::checkGLErr("MemTransfer", "toGPU (glTexImage2D)");

    setCommonTextureParams(0);
}

void MemTransfer::fromGPU(unsigned char *buf) {
    assert(preparedOutput && outputTexId > 0 && buf);

    glBindTexture(GL_TEXTURE_2D, outputTexId);

    // default (and slow) way using glReadPixels:
    glReadPixels(0, 0, outputW, outputH, GL_RGBA, GL_UNSIGNED_BYTE, buf);

    // check for error
    Tools::checkGLErr("MemTransfer", "fromGPU (glReadPixels)");
}

#pragma mark protected methods

void MemTransfer::setCommonTextureParams(GLuint texId) {
    if (texId > 0) {
        glBindTexture(GL_TEXTURE_2D, texId);
    }

    // set clamping (allows NPOT textures)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
<commit_msg>Make GL_BGRA the default for generic opengl based toGPU calls<commit_after>//
// ogles_gpgpu project - GPGPU for mobile devices and embedded systems using OpenGL ES 2.0
//
// Author: Markus Konrad <post@mkonrad.net>, Winter 2014/2015
// http://www.mkonrad.net
//
// See LICENSE file in project repository root for the license.
//

#include "memtransfer.h"

using namespace ogles_gpgpu;

#pragma mark static methods

bool MemTransfer::initPlatformOptimizations() {
    // always return false here. this method is only fully implemented
    // in platform-specialized classes of MemTransfer.
    return false;
}

#pragma mark constructor/deconstructor

MemTransfer::MemTransfer() {
    // set defaults
    inputW = inputH = outputW = outputH = 0;
    inputTexId = 0;
    outputTexId = 0;
    initialized = false;
    preparedInput = false;
    preparedOutput = false;
    inputPixelFormat = GL_RGBA;
}

MemTransfer::~MemTransfer() {
    // release in- and output
    releaseInput();
    releaseOutput();
}

#pragma mark public methods

GLuint MemTransfer::prepareInput(int inTexW, int inTexH, GLenum inputPxFormat, void *inputDataPtr) {
    assert(initialized && inTexW > 0 && inTexH > 0);

    if (inputW == inTexW && inputH == inTexH && inputPixelFormat == inputPxFormat) {
        return inputTexId; // no change
    }

    if (preparedInput) {    // already prepared -- release buffers!
        releaseInput();
    }

    // set attributes
    inputW = inTexW;
    inputH = inTexH;
    inputPixelFormat = inputPxFormat;

    // generate texture id
    glGenTextures(1, &inputTexId);

    if (inputTexId == 0) {
        OG_LOGERR("MemTransfer", "no valid input texture generated");
        return 0;
    }

    // done
    preparedInput = true;

    return inputTexId;
}

GLuint MemTransfer::prepareOutput(int outTexW, int outTexH) {
    assert(initialized && outTexW > 0 && outTexH > 0);

    if (outputW == outTexW && outputH == outTexH) {
        return outputTexId; // no change
    }

    if (preparedOutput) {    // already prepared -- release buffers!
        releaseOutput();
    }

    // set attributes
    outputW = outTexW;
    outputH = outTexH;

    // generate texture id
    glGenTextures(1, &outputTexId);

    if (outputTexId == 0) {
        OG_LOGERR("MemTransfer", "no valid output texture generated");
        return 0;
    }

    // will bind the texture, too:
    setCommonTextureParams(outputTexId);

    Tools::checkGLErr("MemTransfer", "fbo texture parameters");

    // create empty texture space on GPU
    glTexImage2D(GL_TEXTURE_2D, 0,
		 GL_RGBA,
		 outTexW, outTexH, 0,
		 GL_RGBA, GL_UNSIGNED_BYTE,
		 NULL);	// we do not need to pass texture data -> it will be generated!

    Tools::checkGLErr("MemTransfer", "fbo texture creation");

    // done
    preparedOutput = true;

    return outputTexId;
}

void MemTransfer::releaseInput() {
    if (inputTexId > 0) {
        glDeleteTextures(1, &inputTexId);
        inputTexId = 0;
    }
}

void MemTransfer::releaseOutput() {
    if (outputTexId > 0) {
        glDeleteTextures(1, &outputTexId);
        outputTexId = 0;
    }
}

void MemTransfer::toGPU(const unsigned char *buf) {
    assert(preparedInput && inputTexId > 0 && buf);

    // set input texture
    glBindTexture(GL_TEXTURE_2D, inputTexId);	// bind input texture

    // copy data as texture to GPU (tested: OS X)
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, inputW, inputH, 0, GL_BGRA, GL_UNSIGNED_BYTE, buf);

    // check for error
    Tools::checkGLErr("MemTransfer", "toGPU (glTexImage2D)");

    setCommonTextureParams(0);
}

void MemTransfer::fromGPU(unsigned char *buf) {
    assert(preparedOutput && outputTexId > 0 && buf);

    glBindTexture(GL_TEXTURE_2D, outputTexId);

    // default (and slow) way using glReadPixels:
    glReadPixels(0, 0, outputW, outputH, GL_RGBA, GL_UNSIGNED_BYTE, buf);

    // check for error
    Tools::checkGLErr("MemTransfer", "fromGPU (glReadPixels)");
}

#pragma mark protected methods

void MemTransfer::setCommonTextureParams(GLuint texId) {
    if (texId > 0) {
        glBindTexture(GL_TEXTURE_2D, texId);
    }

    // set clamping (allows NPOT textures)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2016 Rhys Ulerich
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef DESCENDU_HEXMAP_H
#define DESCENDU_HEXMAP_H

#include <deque>
#include <functional>
#include <limits>
#include <stdexcept>
#include <tuple>
#include <unordered_map>
#include <utility>

#include "hex.hpp"
#include "optional.hpp"

namespace descendu {

template <class MappedType>
class hexmap : std::unordered_map<hex<int,spec::absolute>,MappedType>
{
    typedef std::unordered_map<hex<int,spec::absolute>,MappedType> base_type;

public:

    using typename base_type::const_iterator;
    using typename base_type::iterator;
    using typename base_type::key_type;
    using typename base_type::mapped_type;
    using typename base_type::size;
    using base_type::begin;
    using base_type::cbegin;
    using base_type::cend;
    using base_type::end;

    // Create or retrieve tile at the given hex
    mapped_type& conjure(const key_type& key) {
        return base_type::emplace(
                std::piecewise_construct,
                std::forward_as_tuple(key),
                std::forward_as_tuple()).first->second;
    }

    // Retrieve tile at the given hex should one exist
    std::experimental::optional<mapped_type&>
    lookup(const key_type& key) {
        const auto& result = this->find(key);
        return result == this->cend()
            ? std::experimental::optional<mapped_type&>()
            : std::experimental::make_optional(std::ref(result->second));
    }

    // Retrieve tile at the given hex should one exist
    std::experimental::optional<const mapped_type&>
    lookup(const key_type& key) const {
        const auto& result = this->find(key);
        return result == this->cend()
            ? std::experimental::optional<const mapped_type&>()
            : std::experimental::make_optional(std::cref(result->second));
    }

    // TODO Removal?

};

// When investigating some tile in the course of a search, should the
// tile be included as usable, excluded as unusable, or should the search
// stop immediately?
enum class search_result { stop, exclude, include };

// Breadth first search returning a map from destination to optional
// source, which may be traversed back to start for navigational purposes.
// The start is assumed to satisfy the query.  Destinations with no source
// value were considered but excluded.  If present in the map, the start
// is the only fixed point where destination equals source.
// Beware retval.lookup(...).value() is itself an optional.
template <class T>
hexmap<std::experimental::optional<typename hexmap<T>::key_type>>
breadth_first_search(
    const hexmap<T>& map,
    const typename hexmap<T>::key_type start,
    std::function<
        search_result(const typename hexmap<T>::mapped_type&)
    > query,
    const int max_distance = std::numeric_limits<int>::max())
{
    typedef typename hexmap<T>::key_type key_type;
    using std::experimental::make_optional;
    using std::experimental::optional;

    // Accumulates result as well as already-visited status
    hexmap<optional<key_type>> retval;

    // Enforce consistent semantics for the start in returned value
    if (map.lookup(start)) {
        retval.conjure(start) = make_optional(start);
    } else {
        retval.conjure(start) = optional<key_type>();
        return retval;
    }

    // Maintains yet-to-be searched (location, source, distance-from-start)
    std::deque<std::tuple<key_type,key_type,int>> frontier;

    // Seed search with the neighbors of the start
    for (const auto& neighbor : neighbors(start)) {
        frontier.emplace_back(std::forward_as_tuple(neighbor, start, 1));
    }

    // Proceed with breadth first search until one of exhaustion criteria met
    while (!frontier.empty()) {

        // Unpack current search location and associated details
        const auto& location = std::get<0>(frontier.front());
        const auto& source   = std::get<1>(frontier.front());
        const auto& distance = std::get<2>(frontier.front());
        const auto& contents = map.lookup(location);

        // Process current location reflecting any new neighbors
        if (distance <= max_distance && contents) {
            switch (query(contents.value())) {
            default:
                throw std::logic_error("missing case");
            case search_result::stop:
                goto done;
            case search_result::exclude:
                retval.conjure(location) = optional<key_type>();
                break;
            case search_result::include:
                for (const auto& neighbor : neighbors(location)) {
                    if (!retval.lookup(neighbor)) {
                        frontier.emplace_back(std::forward_as_tuple(
                            neighbor, location, distance + 1));
                    }
                }
                retval.conjure(location) = make_optional(source);
            }
        }

        // Move to following location
        frontier.pop_front();
    }

    done: return retval;
}

} // namespace

#endif
<commit_msg>Fix errant typename<commit_after>/*
 * Copyright (C) 2016 Rhys Ulerich
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef DESCENDU_HEXMAP_H
#define DESCENDU_HEXMAP_H

#include <deque>
#include <functional>
#include <limits>
#include <stdexcept>
#include <tuple>
#include <unordered_map>
#include <utility>

#include "hex.hpp"
#include "optional.hpp"

namespace descendu {

template <class MappedType>
class hexmap : std::unordered_map<hex<int,spec::absolute>,MappedType>
{
    typedef std::unordered_map<hex<int,spec::absolute>,MappedType> base_type;

public:

    using typename base_type::const_iterator;
    using typename base_type::iterator;
    using typename base_type::key_type;
    using typename base_type::mapped_type;
    using base_type::begin;
    using base_type::cbegin;
    using base_type::cend;
    using base_type::end;
    using base_type::size;

    // Create or retrieve tile at the given hex
    mapped_type& conjure(const key_type& key) {
        return base_type::emplace(
                std::piecewise_construct,
                std::forward_as_tuple(key),
                std::forward_as_tuple()).first->second;
    }

    // Retrieve tile at the given hex should one exist
    std::experimental::optional<mapped_type&>
    lookup(const key_type& key) {
        const auto& result = this->find(key);
        return result == this->cend()
            ? std::experimental::optional<mapped_type&>()
            : std::experimental::make_optional(std::ref(result->second));
    }

    // Retrieve tile at the given hex should one exist
    std::experimental::optional<const mapped_type&>
    lookup(const key_type& key) const {
        const auto& result = this->find(key);
        return result == this->cend()
            ? std::experimental::optional<const mapped_type&>()
            : std::experimental::make_optional(std::cref(result->second));
    }

    // TODO Removal?

};

// When investigating some tile in the course of a search, should the
// tile be included as usable, excluded as unusable, or should the search
// stop immediately?
enum class search_result { stop, exclude, include };

// Breadth first search returning a map from destination to optional
// source, which may be traversed back to start for navigational purposes.
// The start is assumed to satisfy the query.  Destinations with no source
// value were considered but excluded.  If present in the map, the start
// is the only fixed point where destination equals source.
// Beware retval.lookup(...).value() is itself an optional.
template <class T>
hexmap<std::experimental::optional<typename hexmap<T>::key_type>>
breadth_first_search(
    const hexmap<T>& map,
    const typename hexmap<T>::key_type start,
    std::function<
        search_result(const typename hexmap<T>::mapped_type&)
    > query,
    const int max_distance = std::numeric_limits<int>::max())
{
    typedef typename hexmap<T>::key_type key_type;
    using std::experimental::make_optional;
    using std::experimental::optional;

    // Accumulates result as well as already-visited status
    hexmap<optional<key_type>> retval;

    // Enforce consistent semantics for the start in returned value
    if (map.lookup(start)) {
        retval.conjure(start) = make_optional(start);
    } else {
        retval.conjure(start) = optional<key_type>();
        return retval;
    }

    // Maintains yet-to-be searched (location, source, distance-from-start)
    std::deque<std::tuple<key_type,key_type,int>> frontier;

    // Seed search with the neighbors of the start
    for (const auto& neighbor : neighbors(start)) {
        frontier.emplace_back(std::forward_as_tuple(neighbor, start, 1));
    }

    // Proceed with breadth first search until one of exhaustion criteria met
    while (!frontier.empty()) {

        // Unpack current search location and associated details
        const auto& location = std::get<0>(frontier.front());
        const auto& source   = std::get<1>(frontier.front());
        const auto& distance = std::get<2>(frontier.front());
        const auto& contents = map.lookup(location);

        // Process current location reflecting any new neighbors
        if (distance <= max_distance && contents) {
            switch (query(contents.value())) {
            default:
                throw std::logic_error("missing case");
            case search_result::stop:
                goto done;
            case search_result::exclude:
                retval.conjure(location) = optional<key_type>();
                break;
            case search_result::include:
                for (const auto& neighbor : neighbors(location)) {
                    if (!retval.lookup(neighbor)) {
                        frontier.emplace_back(std::forward_as_tuple(
                            neighbor, location, distance + 1));
                    }
                }
                retval.conjure(location) = make_optional(source);
            }
        }

        // Move to following location
        frontier.pop_front();
    }

    done: return retval;
}

} // namespace

#endif
<|endoftext|>


<commit_before>#include "Configuration.hpp"

#include <QTreeWidget>
#include <QTreeWidgetItem>

#include <stdio.h>
#include <assert.h>

#include <iostream>

std::list<Configurable*>* Configurable::_configurables;

// Role for tree column zero for storing ConfigItem pointers.
static const int ConfigItemRole = Qt::UserRole;

Q_DECLARE_METATYPE(ConfigItem*)  // FIXME: verify this

ConfigItem::ConfigItem(Configuration* config, const QString& name,
                       std::string description) {
    _config = config;
    _treeItem = nullptr;
    _path = name.split('/');
    _description = description;
}

ConfigItem::~ConfigItem() {
    if (_treeItem) {
        // FIXME - Things are getting deleted in a non-GUI thread
        // 		delete _treeItem;
        _treeItem = nullptr;
    }
}

void ConfigItem::valueChanged(const QString& str) {
    if (_treeItem) {
        _treeItem->setText(1, str);
    }
}

void ConfigItem::setupItem() { _treeItem->setText(1, toString()); }

////////

ConfigBool::ConfigBool(Configuration* tree, QString name, bool value,
                       std::string description)
    : ConfigItem(tree, name, std::string description) {
    _value = value;
    addItem();
}

QString ConfigBool::toString() { return _value ? "true" : "false"; }

bool ConfigBool::value() {
    if (_treeItem) {
        _value = _treeItem->checkState(1) == Qt::Checked;
    }
    return _value;
}

void ConfigBool::setValue(const QString& str) {
    if (str == "true") {
        _value = true;
    } else if (str == "false") {
        _value = false;
    } else {
        // Use what's in the tree in case this was called because the user
        // clicked on it
        _value = (_treeItem->checkState(1) == Qt::Checked);
    }
    setupItem();
}

void ConfigBool::setupItem() {
    if (_treeItem) {
        _treeItem->setCheckState(1, _value ? Qt::Checked : Qt::Unchecked);
        // FIXME - Can't change the checkbox anymore.  Why not?
        _treeItem->setFlags(_treeItem->flags() | Qt::ItemIsUserCheckable);
    }
}

////////

ConfigInt::ConfigInt(Configuration* config, QString name, int value,
                     std::string description)
    : ConfigItem(config, name, std::string description) {
    _value = value;
    addItem();
}

QString ConfigInt::toString() { return QString::number(_value); }

void ConfigInt::setValue(const QString& str) { _value = str.toInt(); }

////////

ConfigDouble::ConfigDouble(Configuration* config, QString name, double value,
                           std::string description)
    : ConfigItem(config, name, std::string description) {
    _value = value;
    addItem();
}

QString ConfigDouble::toString() { return QString::number(_value); }

void ConfigDouble::setValue(const QString& str) { _value = str.toDouble(); }

Configuration::Configuration() {
    _tree = nullptr;

    // Create the XML root element
    _doc.appendChild(_doc.createElement("config"));
}

std::shared_ptr<Configuration> Configuration::FromRegisteredConfigurables() {
    std::shared_ptr<Configuration> config = std::make_shared<Configuration>();
    for (Configurable* obj : Configurable::configurables()) {
        obj->createConfiguration(config.get());
    }
    return config;
}

void Configuration::addItem(ConfigItem* item) {
    _allItems.push_back(item);

    if (_tree) {
        addToTree(item);
    }
}

void Configuration::addToTree(ConfigItem* item) {
    // Find the parent of this item by following the tree through all but the
    // last item in the path
    QTreeWidgetItem* parent = _tree->invisibleRootItem();
    const QStringList& path = item->path();
    QStringList::const_iterator last = path.end();
    --last;
    for (QStringList::const_iterator i = path.begin(); i != last; ++i) {
        QTreeWidgetItem* next = nullptr;
        for (int j = 0; j < parent->childCount(); ++j) {
            QTreeWidgetItem* child = parent->child(j);
            if (child->text(0) == *i) {
                next = child;
                break;
            }
        }

        if (!next) {
            // Create this item
            next = new QTreeWidgetItem(parent);
            next->setText(0, *i);
        }

        parent = next;
    }

    // Create a tree item
    item->_treeItem = new QTreeWidgetItem(parent);
    item->_treeItem->setFlags(item->_treeItem->flags() | Qt::ItemIsEditable);
    item->_treeItem->setData(0, ConfigItemRole, QVariant::fromValue(item));
    item->_treeItem->setText(0, path.back());

    if (item->_description != "") {
        std::cout << item->_description << std::endl;
        item->_treeItem->setToolTip(0, QString(item->_description.c_str()));
    }

    item->setupItem();
}

void Configuration::tree(QTreeWidget* tree) {
    assert(!_tree);

    _tree = tree;
    connect(_tree, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this,
            SLOT(itemChanged(QTreeWidgetItem*, int)));

    // Add items that were created before we got a tree
    for (ConfigItem* item : _allItems) {
        addToTree(item);
    }
}

ConfigItem* Configuration::configItem(QTreeWidgetItem* ti) {
    return ti->data(0, ConfigItemRole).value<ConfigItem*>();
}

void Configuration::itemChanged(QTreeWidgetItem* item, int column) {
    if (column == 1) {
        ConfigItem* ci = configItem(item);
        if (ci) {
            ci->setValue(item->text(1));
        }
    }
}

ConfigItem* Configuration::nameLookup(const QString& name) const {
    QStringList path = name.split('/');
    for (ConfigItem* item : _allItems) {
        if (item->path() == path) {
            return item;
        }
    }
    return nullptr;
}

bool Configuration::load(const QString& filename, QString& error) {
    QFile file(filename);
    if (!file.open(QFile::ReadOnly)) {
        error = file.errorString();
        return false;
    }

    QDomDocument newDoc;
    QString domError;
    int errorLine = 0, errorColumn = 0;
    if (!newDoc.setContent(&file, &domError, &errorLine, &errorColumn)) {
        error = QString("%1:%2: %3")
                    .arg(QString::number(errorLine),
                         QString::number(errorColumn), domError);
        return false;
    }

    QDomElement root = newDoc.firstChildElement("config");
    if (root.isNull()) {
        error = "XML does not contain root <config> element";
        return false;
    }

    _doc = newDoc;
    for (ConfigItem* item : _allItems) {
        QDomElement el = root;
        for (QString str : item->path()) {
            bool isInt = false;
            int value = str.toInt(&isInt);
            if (isInt) {
                str = QString("item%1").arg(value);
            } else {
                // Sanitize the string
                str.replace(' ', '_');
            }

            // Find the element for the next part of the path
            el = el.firstChildElement(str);
            if (el.isNull()) {
                break;
            }
        }

        if (!el.isNull()) {
            QString str = el.attribute("value");
            if (!str.isNull()) {
                item->setValue(str);
                item->valueChanged(str);
            }
        }
    }

    return true;
}

bool Configuration::save(const QString& filename, QString& error) {
    QFile file(filename);
    if (!file.open(QFile::WriteOnly)) {
        error = file.errorString();
        return false;
    }

    QDomElement root = _doc.firstChildElement("config");

    // Update the DOM
    // FIXME - Remove superfluous vector elements
    for (ConfigItem* item : _allItems) {
        QDomElement el = root;
        for (QString str : item->path()) {
            bool isInt = false;
            int value = str.toInt(&isInt);
            if (isInt) {
                str = QString("item%1").arg(value);
            } else {
                // Sanitize the string
                str.replace(' ', '_');
            }

            // Find the element for the next part of the path
            QDomElement child = el.firstChildElement(str);
            if (child.isNull()) {
                child = _doc.createElement(str);
                el.appendChild(child);
            }

            el = child;
        }

        // Set the value
        el.setAttribute("value", item->toString());
    }

    // Write XML
    QByteArray data = _doc.toByteArray();
    bool ok = (file.write(data) == data.size());
    if (!ok) {
        // Didn't write all the data
        error = file.errorString();
    }

    return ok;
}

Configurable::Configurable() {
    if (!_configurables) {
        _configurables = new std::list<Configurable*>();
    }

    _configurables->push_back(this);
}

const std::list<Configurable*>& Configurable::configurables() {
    if (!_configurables) {
        _configurables = new std::list<Configurable*>();
    }

    return *_configurables;
}
<commit_msg>Fixed class definitions, removed an old debug statement<commit_after>#include "Configuration.hpp"

#include <QTreeWidget>
#include <QTreeWidgetItem>

#include <stdio.h>
#include <assert.h>

#include <iostream>

std::list<Configurable*>* Configurable::_configurables;

// Role for tree column zero for storing ConfigItem pointers.
static const int ConfigItemRole = Qt::UserRole;

Q_DECLARE_METATYPE(ConfigItem*)  // FIXME: verify this

ConfigItem::ConfigItem(Configuration* config, const QString& name,
                       std::string description) {
    _config = config;
    _treeItem = nullptr;
    _path = name.split('/');
    _description = description;
}

ConfigItem::~ConfigItem() {
    if (_treeItem) {
        // FIXME - Things are getting deleted in a non-GUI thread
        // 		delete _treeItem;
        _treeItem = nullptr;
    }
}

void ConfigItem::valueChanged(const QString& str) {
    if (_treeItem) {
        _treeItem->setText(1, str);
    }
}

void ConfigItem::setupItem() { _treeItem->setText(1, toString()); }

////////

ConfigBool::ConfigBool(Configuration* tree, QString name, bool value,
                       std::string description)
    : ConfigItem(tree, name, description) {
    _value = value;
    addItem();
}

QString ConfigBool::toString() { return _value ? "true" : "false"; }

bool ConfigBool::value() {
    if (_treeItem) {
        _value = _treeItem->checkState(1) == Qt::Checked;
    }
    return _value;
}

void ConfigBool::setValue(const QString& str) {
    if (str == "true") {
        _value = true;
    } else if (str == "false") {
        _value = false;
    } else {
        // Use what's in the tree in case this was called because the user
        // clicked on it
        _value = (_treeItem->checkState(1) == Qt::Checked);
    }
    setupItem();
}

void ConfigBool::setupItem() {
    if (_treeItem) {
        _treeItem->setCheckState(1, _value ? Qt::Checked : Qt::Unchecked);
        // FIXME - Can't change the checkbox anymore.  Why not?
        _treeItem->setFlags(_treeItem->flags() | Qt::ItemIsUserCheckable);
    }
}

////////

ConfigInt::ConfigInt(Configuration* config, QString name, int value,
                     std::string description)
    : ConfigItem(config, name, description) {
    _value = value;
    addItem();
}

QString ConfigInt::toString() { return QString::number(_value); }

void ConfigInt::setValue(const QString& str) { _value = str.toInt(); }

////////

ConfigDouble::ConfigDouble(Configuration* config, QString name, double value,
                           std::string description)
    : ConfigItem(config, name, description) {
    _value = value;
    addItem();
}

QString ConfigDouble::toString() { return QString::number(_value); }

void ConfigDouble::setValue(const QString& str) { _value = str.toDouble(); }

Configuration::Configuration() {
    _tree = nullptr;

    // Create the XML root element
    _doc.appendChild(_doc.createElement("config"));
}

std::shared_ptr<Configuration> Configuration::FromRegisteredConfigurables() {
    std::shared_ptr<Configuration> config = std::make_shared<Configuration>();
    for (Configurable* obj : Configurable::configurables()) {
        obj->createConfiguration(config.get());
    }
    return config;
}

void Configuration::addItem(ConfigItem* item) {
    _allItems.push_back(item);

    if (_tree) {
        addToTree(item);
    }
}

void Configuration::addToTree(ConfigItem* item) {
    // Find the parent of this item by following the tree through all but the
    // last item in the path
    QTreeWidgetItem* parent = _tree->invisibleRootItem();
    const QStringList& path = item->path();
    QStringList::const_iterator last = path.end();
    --last;
    for (QStringList::const_iterator i = path.begin(); i != last; ++i) {
        QTreeWidgetItem* next = nullptr;
        for (int j = 0; j < parent->childCount(); ++j) {
            QTreeWidgetItem* child = parent->child(j);
            if (child->text(0) == *i) {
                next = child;
                break;
            }
        }

        if (!next) {
            // Create this item
            next = new QTreeWidgetItem(parent);
            next->setText(0, *i);
        }

        parent = next;
    }

    // Create a tree item
    item->_treeItem = new QTreeWidgetItem(parent);
    item->_treeItem->setFlags(item->_treeItem->flags() | Qt::ItemIsEditable);
    item->_treeItem->setData(0, ConfigItemRole, QVariant::fromValue(item));
    item->_treeItem->setText(0, path.back());

    if (item->_description != "") {
        item->_treeItem->setToolTip(0, QString(item->_description.c_str()));
    }

    item->setupItem();
}

void Configuration::tree(QTreeWidget* tree) {
    assert(!_tree);

    _tree = tree;
    connect(_tree, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this,
            SLOT(itemChanged(QTreeWidgetItem*, int)));

    // Add items that were created before we got a tree
    for (ConfigItem* item : _allItems) {
        addToTree(item);
    }
}

ConfigItem* Configuration::configItem(QTreeWidgetItem* ti) {
    return ti->data(0, ConfigItemRole).value<ConfigItem*>();
}

void Configuration::itemChanged(QTreeWidgetItem* item, int column) {
    if (column == 1) {
        ConfigItem* ci = configItem(item);
        if (ci) {
            ci->setValue(item->text(1));
        }
    }
}

ConfigItem* Configuration::nameLookup(const QString& name) const {
    QStringList path = name.split('/');
    for (ConfigItem* item : _allItems) {
        if (item->path() == path) {
            return item;
        }
    }
    return nullptr;
}

bool Configuration::load(const QString& filename, QString& error) {
    QFile file(filename);
    if (!file.open(QFile::ReadOnly)) {
        error = file.errorString();
        return false;
    }

    QDomDocument newDoc;
    QString domError;
    int errorLine = 0, errorColumn = 0;
    if (!newDoc.setContent(&file, &domError, &errorLine, &errorColumn)) {
        error = QString("%1:%2: %3")
                    .arg(QString::number(errorLine),
                         QString::number(errorColumn), domError);
        return false;
    }

    QDomElement root = newDoc.firstChildElement("config");
    if (root.isNull()) {
        error = "XML does not contain root <config> element";
        return false;
    }

    _doc = newDoc;
    for (ConfigItem* item : _allItems) {
        QDomElement el = root;
        for (QString str : item->path()) {
            bool isInt = false;
            int value = str.toInt(&isInt);
            if (isInt) {
                str = QString("item%1").arg(value);
            } else {
                // Sanitize the string
                str.replace(' ', '_');
            }

            // Find the element for the next part of the path
            el = el.firstChildElement(str);
            if (el.isNull()) {
                break;
            }
        }

        if (!el.isNull()) {
            QString str = el.attribute("value");
            if (!str.isNull()) {
                item->setValue(str);
                item->valueChanged(str);
            }
        }
    }

    return true;
}

bool Configuration::save(const QString& filename, QString& error) {
    QFile file(filename);
    if (!file.open(QFile::WriteOnly)) {
        error = file.errorString();
        return false;
    }

    QDomElement root = _doc.firstChildElement("config");

    // Update the DOM
    // FIXME - Remove superfluous vector elements
    for (ConfigItem* item : _allItems) {
        QDomElement el = root;
        for (QString str : item->path()) {
            bool isInt = false;
            int value = str.toInt(&isInt);
            if (isInt) {
                str = QString("item%1").arg(value);
            } else {
                // Sanitize the string
                str.replace(' ', '_');
            }

            // Find the element for the next part of the path
            QDomElement child = el.firstChildElement(str);
            if (child.isNull()) {
                child = _doc.createElement(str);
                el.appendChild(child);
            }

            el = child;
        }

        // Set the value
        el.setAttribute("value", item->toString());
    }

    // Write XML
    QByteArray data = _doc.toByteArray();
    bool ok = (file.write(data) == data.size());
    if (!ok) {
        // Didn't write all the data
        error = file.errorString();
    }

    return ok;
}

Configurable::Configurable() {
    if (!_configurables) {
        _configurables = new std::list<Configurable*>();
    }

    _configurables->push_back(this);
}

const std::list<Configurable*>& Configurable::configurables() {
    if (!_configurables) {
        _configurables = new std::list<Configurable*>();
    }

    return *_configurables;
}
<|endoftext|>


<commit_before>#include <common/buffer.h>
#include <common/endian.h>

#include <event/action.h>
#include <event/callback.h>
#include <event/event_system.h>

#include <io/pipe.h>
#include <io/pipe_link.h>
#include <io/pipe_null.h>
#include <io/socket.h>
#include <io/splice.h>
#include <io/splice_pair.h>

#include <net/tcp_client.h>

#include "proxy_client.h"

ProxyClient::ProxyClient(XCodec *local_codec, XCodec *remote_codec,
			 Socket *local_socket, SocketAddressFamily family,
			 const std::string& remote_name)
: log_("/wanproxy/proxy/client"),
  stop_action_(NULL),
  local_action_(NULL),
  local_codec_(local_codec),
  local_socket_(local_socket),
  remote_action_(NULL),
  remote_codec_(remote_codec),
  remote_socket_(NULL),
  pipes_(),
  incoming_splice_(NULL),
  outgoing_splice_(NULL),
  splice_pair_(NULL),
  splice_action_(NULL)
{
	EventCallback *cb = callback(this, &ProxyClient::connect_complete);
	remote_action_ = TCPClient::connect(&remote_socket_, family, remote_name, cb);
	if (remote_action_ == NULL) {
		ASSERT(remote_socket_ == NULL);

		ERROR(log_) << "Could not connect to: " << remote_name;

		EventCallback *lcb = callback(this, &ProxyClient::close_complete,
					      (void *)local_socket_);
		local_action_ = local_socket_->close(lcb);
		return;
	}

	Callback *scb = callback(this, &ProxyClient::stop);
	stop_action_ = EventSystem::instance()->register_interest(EventInterestStop, scb);
}

ProxyClient::~ProxyClient()
{
	ASSERT(stop_action_ == NULL);
	ASSERT(local_action_ == NULL);
	ASSERT(local_socket_ == NULL);
	ASSERT(remote_action_ == NULL);
	ASSERT(remote_socket_ == NULL);
	ASSERT(incoming_splice_ == NULL);
	ASSERT(outgoing_splice_ == NULL);
	ASSERT(splice_pair_ == NULL);
	ASSERT(splice_action_ == NULL);

	std::set<Pipe *>::iterator it;
	while ((it = pipes_.begin()) != pipes_.end()) {
		Pipe *pipe = *it;
		pipes_.erase(it);

		delete pipe;
	}
}

void
ProxyClient::close_complete(Event e, void *channel)
{
	if (channel == (void *)local_socket_) {
		local_action_->cancel();
		local_action_ = NULL;
	}

	if (channel == (void *)remote_socket_) {
		remote_action_->cancel();
		remote_action_ = NULL;
	}

	switch (e.type_) {
	case Event::Done:
		break;
	default:
		/* XXX Never sure what to do here.  */
		ERROR(log_) << "Unexpected event: " << e;
		return;
	}

	if (channel == (void *)local_socket_) {
		ASSERT(local_socket_ != NULL);
		delete local_socket_;
		local_socket_ = NULL;
	}

	if (channel == (void *)remote_socket_) {
		ASSERT(remote_socket_ != NULL);
		delete remote_socket_;
		remote_socket_ = NULL;
	}

	if (local_socket_ == NULL && remote_socket_ == NULL) {
		delete this;
	}
}

void
ProxyClient::connect_complete(Event e)
{
	remote_action_->cancel();
	remote_action_ = NULL;

	switch (e.type_) {
	case Event::Done:
		break;
	case Event::Error:
		INFO(log_) << "Connect failed: " << e;
		schedule_close();
		return;
	default:
		ERROR(log_) << "Unexpected event: " << e;
		schedule_close();
		return;
	}

	Pipe *incoming_left = new PipeNull();
	pipes_.insert(incoming_left);

	Pipe *incoming_right = new PipeNull();
	pipes_.insert(incoming_right);

	Pipe *incoming_link = new PipeLink(incoming_left, incoming_right);
	pipes_.insert(incoming_link);

	incoming_splice_ = new Splice(remote_socket_, incoming_link, local_socket_);

	Pipe *outgoing_left = new PipeNull();
	pipes_.insert(outgoing_left);

	Pipe *outgoing_right = new PipeNull();
	pipes_.insert(outgoing_right);

	Pipe *outgoing_link = new PipeLink(outgoing_left, outgoing_right);
	pipes_.insert(outgoing_link);

	outgoing_splice_ = new Splice(local_socket_, outgoing_link, remote_socket_);

	splice_pair_ = new SplicePair(outgoing_splice_, incoming_splice_);

	EventCallback *cb = callback(this, &ProxyClient::splice_complete);
	splice_action_ = splice_pair_->start(cb);
}

void
ProxyClient::splice_complete(Event e)
{
	splice_action_->cancel();
	splice_action_ = NULL;

	delete splice_pair_;
	splice_pair_ = NULL;

	delete outgoing_splice_;
	outgoing_splice_ = NULL;

	delete incoming_splice_;
	incoming_splice_ = NULL;

	switch (e.type_) {
	case Event::Done:
		break;
	default:
		ERROR(log_) << "Unexpected event: " << e;
		break;
	}

	schedule_close();
}

void
ProxyClient::stop(void)
{
	stop_action_->cancel();
	stop_action_ = NULL;

	/*
	 * Connecting.
	 */
	if (local_action_ == NULL && remote_action_ != NULL &&
	    splice_action_ == NULL) {
		remote_action_->cancel();
		remote_action_ = NULL;

		schedule_close();
		return;
	}

	/*
	 * Already closing.  Should not happen.
	 */
	if (local_action_ != NULL || remote_action_ != NULL) {
		HALT(log_) << "Client already closing during stop.";
		return;
	}

	schedule_close();
}

void
ProxyClient::schedule_close(void)
{
	if (stop_action_ != NULL) {
		stop_action_->cancel();
		stop_action_ = NULL;
	}

	if (splice_pair_ != NULL) {
		if (splice_action_ != NULL) {
			splice_action_->cancel();
			splice_action_ = NULL;
		}

		ASSERT(outgoing_splice_ != NULL);
		ASSERT(incoming_splice_ != NULL);

		delete splice_pair_;
		splice_pair_ = NULL;

		delete outgoing_splice_;
		outgoing_splice_ = NULL;

		delete incoming_splice_;
		incoming_splice_ = NULL;
	}

	ASSERT(local_action_ == NULL);
	ASSERT(local_socket_ != NULL);
	EventCallback *lcb = callback(this, &ProxyClient::close_complete,
				      (void *)local_socket_);
	local_action_ = local_socket_->close(lcb);

	ASSERT(remote_action_ == NULL);
	ASSERT(remote_socket_ != NULL);
	EventCallback *rcb = callback(this, &ProxyClient::close_complete,
				      (void *)remote_socket_);
	remote_action_ = remote_socket_->close(rcb);
}
<commit_msg>Include headers for the XCodec Pipes.<commit_after>#include <common/buffer.h>
#include <common/endian.h>

#include <event/action.h>
#include <event/callback.h>
#include <event/event_system.h>

#include <io/pipe.h>
#include <io/pipe_link.h>
#include <io/pipe_null.h>
#include <io/pipe_pair.h>
#include <io/socket.h>
#include <io/splice.h>
#include <io/splice_pair.h>

#include <net/tcp_client.h>

#include <xcodec/xcodec.h>
#include <xcodec/xcodec_decoder.h>
#include <xcodec/xcodec_encoder.h>
#include <xcodec/xcodec_pipe_pair.h>

#include "proxy_client.h"

ProxyClient::ProxyClient(XCodec *local_codec, XCodec *remote_codec,
			 Socket *local_socket, SocketAddressFamily family,
			 const std::string& remote_name)
: log_("/wanproxy/proxy/client"),
  stop_action_(NULL),
  local_action_(NULL),
  local_codec_(local_codec),
  local_socket_(local_socket),
  remote_action_(NULL),
  remote_codec_(remote_codec),
  remote_socket_(NULL),
  pipes_(),
  incoming_splice_(NULL),
  outgoing_splice_(NULL),
  splice_pair_(NULL),
  splice_action_(NULL)
{
	EventCallback *cb = callback(this, &ProxyClient::connect_complete);
	remote_action_ = TCPClient::connect(&remote_socket_, family, remote_name, cb);
	if (remote_action_ == NULL) {
		ASSERT(remote_socket_ == NULL);

		ERROR(log_) << "Could not connect to: " << remote_name;

		EventCallback *lcb = callback(this, &ProxyClient::close_complete,
					      (void *)local_socket_);
		local_action_ = local_socket_->close(lcb);
		return;
	}

	Callback *scb = callback(this, &ProxyClient::stop);
	stop_action_ = EventSystem::instance()->register_interest(EventInterestStop, scb);
}

ProxyClient::~ProxyClient()
{
	ASSERT(stop_action_ == NULL);
	ASSERT(local_action_ == NULL);
	ASSERT(local_socket_ == NULL);
	ASSERT(remote_action_ == NULL);
	ASSERT(remote_socket_ == NULL);
	ASSERT(incoming_splice_ == NULL);
	ASSERT(outgoing_splice_ == NULL);
	ASSERT(splice_pair_ == NULL);
	ASSERT(splice_action_ == NULL);

	std::set<Pipe *>::iterator it;
	while ((it = pipes_.begin()) != pipes_.end()) {
		Pipe *pipe = *it;
		pipes_.erase(it);

		delete pipe;
	}
}

void
ProxyClient::close_complete(Event e, void *channel)
{
	if (channel == (void *)local_socket_) {
		local_action_->cancel();
		local_action_ = NULL;
	}

	if (channel == (void *)remote_socket_) {
		remote_action_->cancel();
		remote_action_ = NULL;
	}

	switch (e.type_) {
	case Event::Done:
		break;
	default:
		/* XXX Never sure what to do here.  */
		ERROR(log_) << "Unexpected event: " << e;
		return;
	}

	if (channel == (void *)local_socket_) {
		ASSERT(local_socket_ != NULL);
		delete local_socket_;
		local_socket_ = NULL;
	}

	if (channel == (void *)remote_socket_) {
		ASSERT(remote_socket_ != NULL);
		delete remote_socket_;
		remote_socket_ = NULL;
	}

	if (local_socket_ == NULL && remote_socket_ == NULL) {
		delete this;
	}
}

void
ProxyClient::connect_complete(Event e)
{
	remote_action_->cancel();
	remote_action_ = NULL;

	switch (e.type_) {
	case Event::Done:
		break;
	case Event::Error:
		INFO(log_) << "Connect failed: " << e;
		schedule_close();
		return;
	default:
		ERROR(log_) << "Unexpected event: " << e;
		schedule_close();
		return;
	}

	Pipe *incoming_left = new PipeNull();
	pipes_.insert(incoming_left);

	Pipe *incoming_right = new PipeNull();
	pipes_.insert(incoming_right);

	Pipe *incoming_link = new PipeLink(incoming_left, incoming_right);
	pipes_.insert(incoming_link);

	incoming_splice_ = new Splice(remote_socket_, incoming_link, local_socket_);

	Pipe *outgoing_left = new PipeNull();
	pipes_.insert(outgoing_left);

	Pipe *outgoing_right = new PipeNull();
	pipes_.insert(outgoing_right);

	Pipe *outgoing_link = new PipeLink(outgoing_left, outgoing_right);
	pipes_.insert(outgoing_link);

	outgoing_splice_ = new Splice(local_socket_, outgoing_link, remote_socket_);

	splice_pair_ = new SplicePair(outgoing_splice_, incoming_splice_);

	EventCallback *cb = callback(this, &ProxyClient::splice_complete);
	splice_action_ = splice_pair_->start(cb);
}

void
ProxyClient::splice_complete(Event e)
{
	splice_action_->cancel();
	splice_action_ = NULL;

	delete splice_pair_;
	splice_pair_ = NULL;

	delete outgoing_splice_;
	outgoing_splice_ = NULL;

	delete incoming_splice_;
	incoming_splice_ = NULL;

	switch (e.type_) {
	case Event::Done:
		break;
	default:
		ERROR(log_) << "Unexpected event: " << e;
		break;
	}

	schedule_close();
}

void
ProxyClient::stop(void)
{
	stop_action_->cancel();
	stop_action_ = NULL;

	/*
	 * Connecting.
	 */
	if (local_action_ == NULL && remote_action_ != NULL &&
	    splice_action_ == NULL) {
		remote_action_->cancel();
		remote_action_ = NULL;

		schedule_close();
		return;
	}

	/*
	 * Already closing.  Should not happen.
	 */
	if (local_action_ != NULL || remote_action_ != NULL) {
		HALT(log_) << "Client already closing during stop.";
		return;
	}

	schedule_close();
}

void
ProxyClient::schedule_close(void)
{
	if (stop_action_ != NULL) {
		stop_action_->cancel();
		stop_action_ = NULL;
	}

	if (splice_pair_ != NULL) {
		if (splice_action_ != NULL) {
			splice_action_->cancel();
			splice_action_ = NULL;
		}

		ASSERT(outgoing_splice_ != NULL);
		ASSERT(incoming_splice_ != NULL);

		delete splice_pair_;
		splice_pair_ = NULL;

		delete outgoing_splice_;
		outgoing_splice_ = NULL;

		delete incoming_splice_;
		incoming_splice_ = NULL;
	}

	ASSERT(local_action_ == NULL);
	ASSERT(local_socket_ != NULL);
	EventCallback *lcb = callback(this, &ProxyClient::close_complete,
				      (void *)local_socket_);
	local_action_ = local_socket_->close(lcb);

	ASSERT(remote_action_ == NULL);
	ASSERT(remote_socket_ != NULL);
	EventCallback *rcb = callback(this, &ProxyClient::close_complete,
				      (void *)remote_socket_);
	remote_action_ = remote_socket_->close(rcb);
}
<|endoftext|>


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

#include "net/third_party/quiche/src/quic/core/quic_bandwidth.h"
#include "net/third_party/quiche/src/quic/core/quic_time.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h"
#include "net/third_party/quiche/src/quic/quartc/test/bidi_test_runner.h"
#include "net/third_party/quiche/src/quic/quartc/test/quic_trace_interceptor.h"
#include "net/third_party/quiche/src/quic/quartc/test/random_delay_link.h"
#include "net/third_party/quiche/src/quic/quartc/test/random_packet_filter.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h"

namespace quic {
namespace test {
namespace {

class QuartcBidiTest : public QuicTest {
 protected:
  QuartcBidiTest() {
    uint64_t seed = QuicRandom::GetInstance()->RandUint64();
    QUIC_LOG(INFO) << "Setting random seed to " << seed;
    random_.set_seed(seed);
    simulator_.set_random_generator(&random_);

    client_trace_interceptor_ = QuicMakeUnique<QuicTraceInterceptor>("client");
    server_trace_interceptor_ = QuicMakeUnique<QuicTraceInterceptor>("server");
  }

  void CreateTransports(QuicBandwidth bandwidth,
                        QuicTime::Delta propagation_delay,
                        QuicByteCount queue_length,
                        int loss_percent) {
    client_transport_ =
        QuicMakeUnique<simulator::SimulatedQuartcPacketTransport>(
            &simulator_, "client_transport", "server_transport", queue_length);
    server_transport_ =
        QuicMakeUnique<simulator::SimulatedQuartcPacketTransport>(
            &simulator_, "server_transport", "client_transport", queue_length);
    client_filter_ = QuicMakeUnique<simulator::RandomPacketFilter>(
        &simulator_, "client_filter", client_transport_.get());
    server_filter_ = QuicMakeUnique<simulator::RandomPacketFilter>(
        &simulator_, "server_filter", server_transport_.get());
    client_server_link_ = QuicMakeUnique<simulator::SymmetricRandomDelayLink>(
        client_filter_.get(), server_filter_.get(), bandwidth,
        propagation_delay);
    client_filter_->set_loss_percent(loss_percent);
    server_filter_->set_loss_percent(loss_percent);
  }

  simulator::Simulator simulator_;
  SimpleRandom random_;

  std::unique_ptr<simulator::SimulatedQuartcPacketTransport> client_transport_;
  std::unique_ptr<simulator::SimulatedQuartcPacketTransport> server_transport_;
  std::unique_ptr<simulator::RandomPacketFilter> client_filter_;
  std::unique_ptr<simulator::RandomPacketFilter> server_filter_;
  std::unique_ptr<simulator::SymmetricRandomDelayLink> client_server_link_;

  std::unique_ptr<QuicTraceInterceptor> client_trace_interceptor_;
  std::unique_ptr<QuicTraceInterceptor> server_trace_interceptor_;
};

TEST_F(QuartcBidiTest, Basic300kbps200ms) {
  CreateTransports(QuicBandwidth::FromKBitsPerSecond(300),
                   QuicTime::Delta::FromMilliseconds(200),
                   10 * kDefaultMaxPacketSize, /*loss_percent=*/0);
  BidiTestRunner runner(&simulator_, client_transport_.get(),
                        server_transport_.get());
  runner.set_client_interceptor(client_trace_interceptor_.get());
  runner.set_server_interceptor(server_trace_interceptor_.get());
  EXPECT_TRUE(runner.RunTest(QuicTime::Delta::FromSeconds(30)));
}

TEST_F(QuartcBidiTest, 300kbps200ms2PercentLoss) {
  CreateTransports(QuicBandwidth::FromKBitsPerSecond(300),
                   QuicTime::Delta::FromMilliseconds(200),
                   10 * kDefaultMaxPacketSize, /*loss_percent=*/2);
  BidiTestRunner runner(&simulator_, client_transport_.get(),
                        server_transport_.get());
  runner.set_client_interceptor(client_trace_interceptor_.get());
  runner.set_server_interceptor(server_trace_interceptor_.get());
  EXPECT_TRUE(runner.RunTest(QuicTime::Delta::FromSeconds(30)));
}

TEST_F(QuartcBidiTest, 300kbps200ms25msRandom2PercentLoss) {
  CreateTransports(QuicBandwidth::FromKBitsPerSecond(300),
                   QuicTime::Delta::FromMilliseconds(200),
                   10 * kDefaultMaxPacketSize, /*loss_percent=*/2);
  client_server_link_->set_median_random_delay(
      QuicTime::Delta::FromMilliseconds(25));
  BidiTestRunner runner(&simulator_, client_transport_.get(),
                        server_transport_.get());
  runner.set_client_interceptor(client_trace_interceptor_.get());
  runner.set_server_interceptor(server_trace_interceptor_.get());
  EXPECT_TRUE(runner.RunTest(QuicTime::Delta::FromSeconds(30)));
}

}  // namespace
}  // namespace test
}  // namespace quic
<commit_msg>Replace random delay test case with a competing flow case in QuartcBidiTest.<commit_after>// Copyright (c) 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/third_party/quiche/src/quic/core/quic_bandwidth.h"
#include "net/third_party/quiche/src/quic/core/quic_time.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h"
#include "net/third_party/quiche/src/quic/quartc/test/bidi_test_runner.h"
#include "net/third_party/quiche/src/quic/quartc/test/quic_trace_interceptor.h"
#include "net/third_party/quiche/src/quic/quartc/test/random_packet_filter.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
#include "net/third_party/quiche/src/quic/test_tools/simulator/link.h"
#include "net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h"
#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h"
#include "net/third_party/quiche/src/quic/test_tools/simulator/switch.h"

namespace quic {
namespace test {
namespace {

class CompetingTransferAlarmDelegate : public quic::QuicAlarm::Delegate {
 public:
  CompetingTransferAlarmDelegate(quic::simulator::QuicEndpoint* endpoint,
                                 QuicByteCount bytes)
      : endpoint_(endpoint), bytes_(bytes) {}

  void OnAlarm() override { endpoint_->AddBytesToTransfer(bytes_); }

 private:
  quic::simulator::QuicEndpoint* const endpoint_;
  const QuicByteCount bytes_;
};

class QuartcBidiTest : public QuicTest {
 protected:
  QuartcBidiTest() {
    uint64_t seed = QuicRandom::GetInstance()->RandUint64();
    QUIC_LOG(INFO) << "Setting random seed to " << seed;
    random_.set_seed(seed);
    simulator_.set_random_generator(&random_);

    client_trace_interceptor_ = QuicMakeUnique<QuicTraceInterceptor>("client");
    server_trace_interceptor_ = QuicMakeUnique<QuicTraceInterceptor>("server");
  }

  void CreateTransports(QuicBandwidth bandwidth,
                        QuicTime::Delta propagation_delay,
                        QuicByteCount queue_length,
                        int loss_percent) {
    // Endpoints which serve as the transports for client and server.
    client_transport_ =
        QuicMakeUnique<simulator::SimulatedQuartcPacketTransport>(
            &simulator_, "client_transport", "server_transport", queue_length);
    server_transport_ =
        QuicMakeUnique<simulator::SimulatedQuartcPacketTransport>(
            &simulator_, "server_transport", "client_transport", queue_length);

    // Filters on each of the endpoints facilitate random packet loss.
    client_filter_ = QuicMakeUnique<simulator::RandomPacketFilter>(
        &simulator_, "client_filter", client_transport_.get());
    server_filter_ = QuicMakeUnique<simulator::RandomPacketFilter>(
        &simulator_, "server_filter", server_transport_.get());
    client_filter_->set_loss_percent(loss_percent);
    server_filter_->set_loss_percent(loss_percent);

    // Each endpoint connects directly to a switch.
    client_switch_ = QuicMakeUnique<simulator::Switch>(
        &simulator_, "client_switch", /*port_count=*/8, 2 * queue_length);
    server_switch_ = QuicMakeUnique<simulator::Switch>(
        &simulator_, "server_switch", /*port_count=*/8, 2 * queue_length);

    // Links to the switch have significantly higher bandwdith than the
    // bottleneck and insignificant propagation delay.
    client_link_ = QuicMakeUnique<simulator::SymmetricLink>(
        client_filter_.get(), client_switch_->port(1), 10 * bandwidth,
        QuicTime::Delta::FromMicroseconds(1));
    server_link_ = QuicMakeUnique<simulator::SymmetricLink>(
        server_filter_.get(), server_switch_->port(1), 10 * bandwidth,
        QuicTime::Delta::FromMicroseconds(1));

    // The bottleneck link connects the two switches with the bandwidth and
    // propagation delay specified by the test case.
    bottleneck_link_ = QuicMakeUnique<simulator::SymmetricLink>(
        client_switch_->port(2), server_switch_->port(2), bandwidth,
        propagation_delay);
  }

  void SetupCompetingEndpoints(QuicBandwidth bandwidth) {
    competing_client_ = absl::make_unique<quic::simulator::QuicEndpoint>(
        &simulator_, "competing_client", "competing_server",
        quic::Perspective::IS_CLIENT, quic::test::TestConnectionId(3));
    competing_server_ = absl::make_unique<quic::simulator::QuicEndpoint>(
        &simulator_, "competing_server", "competing_client",
        quic::Perspective::IS_SERVER, quic::test::TestConnectionId(3));

    competing_client_link_ = absl::make_unique<quic::simulator::SymmetricLink>(
        competing_client_.get(), client_switch_->port(3), 10 * bandwidth,
        QuicTime::Delta::FromMicroseconds(1));
    competing_server_link_ = absl::make_unique<quic::simulator::SymmetricLink>(
        competing_server_.get(), server_switch_->port(3), 10 * bandwidth,
        QuicTime::Delta::FromMicroseconds(1));
  }

  simulator::Simulator simulator_;
  SimpleRandom random_;

  std::unique_ptr<simulator::SimulatedQuartcPacketTransport> client_transport_;
  std::unique_ptr<simulator::SimulatedQuartcPacketTransport> server_transport_;
  std::unique_ptr<simulator::RandomPacketFilter> client_filter_;
  std::unique_ptr<simulator::RandomPacketFilter> server_filter_;
  std::unique_ptr<simulator::Switch> client_switch_;
  std::unique_ptr<simulator::Switch> server_switch_;
  std::unique_ptr<simulator::SymmetricLink> client_link_;
  std::unique_ptr<simulator::SymmetricLink> server_link_;
  std::unique_ptr<simulator::SymmetricLink> bottleneck_link_;

  std::unique_ptr<simulator::QuicEndpoint> competing_client_;
  std::unique_ptr<simulator::QuicEndpoint> competing_server_;
  std::unique_ptr<simulator::SymmetricLink> competing_client_link_;
  std::unique_ptr<simulator::SymmetricLink> competing_server_link_;

  std::unique_ptr<QuicTraceInterceptor> client_trace_interceptor_;
  std::unique_ptr<QuicTraceInterceptor> server_trace_interceptor_;
};

TEST_F(QuartcBidiTest, Basic300kbps200ms) {
  CreateTransports(QuicBandwidth::FromKBitsPerSecond(300),
                   QuicTime::Delta::FromMilliseconds(200),
                   10 * kDefaultMaxPacketSize, /*loss_percent=*/0);
  BidiTestRunner runner(&simulator_, client_transport_.get(),
                        server_transport_.get());
  runner.set_client_interceptor(client_trace_interceptor_.get());
  runner.set_server_interceptor(server_trace_interceptor_.get());
  EXPECT_TRUE(runner.RunTest(QuicTime::Delta::FromSeconds(30)));
}

TEST_F(QuartcBidiTest, 300kbps200ms2PercentLoss) {
  CreateTransports(QuicBandwidth::FromKBitsPerSecond(300),
                   QuicTime::Delta::FromMilliseconds(200),
                   10 * kDefaultMaxPacketSize, /*loss_percent=*/2);
  BidiTestRunner runner(&simulator_, client_transport_.get(),
                        server_transport_.get());
  runner.set_client_interceptor(client_trace_interceptor_.get());
  runner.set_server_interceptor(server_trace_interceptor_.get());
  EXPECT_TRUE(runner.RunTest(QuicTime::Delta::FromSeconds(30)));
}

TEST_F(QuartcBidiTest, 300kbps200ms2PercentLossCompetingBurst) {
  QuicBandwidth bandwidth = QuicBandwidth::FromKBitsPerSecond(300);
  CreateTransports(bandwidth, QuicTime::Delta::FromMilliseconds(200),
                   10 * quic::kDefaultMaxPacketSize, /*loss_percent=*/2);
  SetupCompetingEndpoints(bandwidth);

  QuicTime competing_burst_time =
      simulator_.GetClock()->Now() + QuicTime::Delta::FromSeconds(15);
  std::unique_ptr<quic::QuicAlarm> competing_client_burst_alarm_ =
      absl::WrapUnique(simulator_.GetAlarmFactory()->CreateAlarm(
          new CompetingTransferAlarmDelegate(competing_client_.get(),
                                             /*bytes=*/50 * 1024)));
  std::unique_ptr<quic::QuicAlarm> competing_server_burst_alarm_ =
      absl::WrapUnique(simulator_.GetAlarmFactory()->CreateAlarm(
          new CompetingTransferAlarmDelegate(competing_server_.get(),
                                             /*bytes=*/50 * 1024)));
  competing_client_burst_alarm_->Set(competing_burst_time);
  competing_server_burst_alarm_->Set(competing_burst_time);

  quic::test::BidiTestRunner runner(&simulator_, client_transport_.get(),
                                    server_transport_.get());
  runner.set_client_interceptor(client_trace_interceptor_.get());
  runner.set_server_interceptor(server_trace_interceptor_.get());
  EXPECT_TRUE(runner.RunTest(QuicTime::Delta::FromSeconds(30)));
}

}  // namespace
}  // namespace test
}  // namespace quic
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2006-2007 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#include "base/arch_check.h"

#include <cstring>
#include <errno.h>
#include <fstream>
#include <iostream>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string>
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include "tracechild.hh"

using namespace std;

void
printUsage(const char * execName)
{
    cout << execName << " <options> -- <command> <arguments>" << endl;
    cout << "options:" << endl;
    cout << "         -h          print this help" << endl;
    cout << "         --host      remote m5 host to connect to" << endl;
    cout << "         -i          print initial stack state" << endl;
    cout << "         -nt         don't print an instruction trace" << endl;
}

int
main(int argc, char * argv[], char * envp[])
{
    TraceChild * child = genTraceChild();
    string args;
    int startProgramArgs;

    //Parse the command line arguments
    bool printInitial = false;
    bool printTrace = true;
    string host = "localhost";

    if (argc == 1) {
        printUsage(argv[0]);
        return 0;
    }
    for (int x = 1; x < argc; x++) {
        if (!strcmp(argv[x], "-h")) {
            printUsage(argv[0]);
            return 0;
        }
        if (!strcmp(argv[x], "--host")) {
            x++;
            if (x >= argc) {
                cerr << "Incorrect usage.\n" << endl;
                printUsage(argv[0]);
                return 1;
            }
            host = argv[x];
        } else if (!strcmp(argv[x], "-i")) {
            printInitial = true;
        } else if (!strcmp(argv[x], "-nt")) {
            printTrace = false;
        } else if (!strcmp(argv[x], "--")) {
            x++;
            if (x >= argc) {
                cerr << "Incorrect usage.\n" << endl;
                printUsage(argv[0]);
                return 1;
            }
            startProgramArgs = x;
            break;
        } else {
            cerr << "Incorrect usage.\n" << endl;
            printUsage(argv[0]);
            return 1;
        }
    }
    if (!child->startTracing(argv[startProgramArgs],
                argv + startProgramArgs)) {
        cerr << "Couldn't start target program" << endl;
        return 1;
    }
    child->step();
    if (printInitial)
        child->outputStartState(cout);
    if (printTrace) {
        // Connect to m5
        bool portSet = false;
        int port;
        int sock = socket(AF_INET, SOCK_STREAM, 0);
        if (sock < 0) {
            cerr << "Error opening socket! " << strerror(errno) << endl;
            return 1;
        }
        struct hostent *server;
        server = gethostbyname(host.c_str());
        if (!server) {
            cerr << "Couldn't get host ip! " << strerror(errno) << endl;
            return 1;
        }
        struct sockaddr_in serv_addr;
        bzero((char *)&serv_addr, sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        bcopy((char *)server->h_addr,
                (char *)&serv_addr.sin_addr.s_addr,
                server->h_length);
        serv_addr.sin_port = htons(8000);
        if (connect(sock, (sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
            cerr << "Couldn't connect to server! " << strerror(errno) << endl;
            return 1;
        }
        while (child->isTracing()) {
            if (!child->sendState(sock))
                break;
            child->step();
        }
    }
    if (!child->stopTracing()) {
        cerr << "Couldn't stop child" << endl;
        return 1;
    }
    return 0;
}

<commit_msg>Statetrace: Tweak the help for the -nt option.<commit_after>/*
 * Copyright (c) 2006-2007 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#include "base/arch_check.h"

#include <cstring>
#include <errno.h>
#include <fstream>
#include <iostream>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string>
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include "tracechild.hh"

using namespace std;

void
printUsage(const char * execName)
{
    cout << execName << " <options> -- <command> <arguments>" << endl;
    cout << "options:" << endl;
    cout << "         -h          print this help" << endl;
    cout << "         --host      remote m5 host to connect to" << endl;
    cout << "         -i          print initial stack state" << endl;
    cout << "         -nt         don't trace execution" << endl;
}

int
main(int argc, char * argv[], char * envp[])
{
    TraceChild * child = genTraceChild();
    string args;
    int startProgramArgs;

    //Parse the command line arguments
    bool printInitial = false;
    bool printTrace = true;
    string host = "localhost";

    if (argc == 1) {
        printUsage(argv[0]);
        return 0;
    }
    for (int x = 1; x < argc; x++) {
        if (!strcmp(argv[x], "-h")) {
            printUsage(argv[0]);
            return 0;
        }
        if (!strcmp(argv[x], "--host")) {
            x++;
            if (x >= argc) {
                cerr << "Incorrect usage.\n" << endl;
                printUsage(argv[0]);
                return 1;
            }
            host = argv[x];
        } else if (!strcmp(argv[x], "-i")) {
            printInitial = true;
        } else if (!strcmp(argv[x], "-nt")) {
            printTrace = false;
        } else if (!strcmp(argv[x], "--")) {
            x++;
            if (x >= argc) {
                cerr << "Incorrect usage.\n" << endl;
                printUsage(argv[0]);
                return 1;
            }
            startProgramArgs = x;
            break;
        } else {
            cerr << "Incorrect usage.\n" << endl;
            printUsage(argv[0]);
            return 1;
        }
    }
    if (!child->startTracing(argv[startProgramArgs],
                argv + startProgramArgs)) {
        cerr << "Couldn't start target program" << endl;
        return 1;
    }
    child->step();
    if (printInitial)
        child->outputStartState(cout);
    if (printTrace) {
        // Connect to m5
        bool portSet = false;
        int port;
        int sock = socket(AF_INET, SOCK_STREAM, 0);
        if (sock < 0) {
            cerr << "Error opening socket! " << strerror(errno) << endl;
            return 1;
        }
        struct hostent *server;
        server = gethostbyname(host.c_str());
        if (!server) {
            cerr << "Couldn't get host ip! " << strerror(errno) << endl;
            return 1;
        }
        struct sockaddr_in serv_addr;
        bzero((char *)&serv_addr, sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        bcopy((char *)server->h_addr,
                (char *)&serv_addr.sin_addr.s_addr,
                server->h_length);
        serv_addr.sin_port = htons(8000);
        if (connect(sock, (sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
            cerr << "Couldn't connect to server! " << strerror(errno) << endl;
            return 1;
        }
        while (child->isTracing()) {
            if (!child->sendState(sock))
                break;
            child->step();
        }
    }
    if (!child->stopTracing()) {
        cerr << "Couldn't stop child" << endl;
        return 1;
    }
    return 0;
}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: regactivex.cxx,v $
 *
 *  $Revision: 1.13 $
 *
 *  last change: $Author: vg $ $Date: 2006-09-25 13:07:48 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#define UNICODE

#pragma warning(push, 1) /* disable warnings within system headers */
#include <windows.h>
#include <msiquery.h>
#pragma warning(pop)

#include <string.h>
#include <malloc.h>

#define CHART_COMPONENT 1
#define DRAW_COMPONENT 2
#define IMPRESS_COMPONENT 4
#define CALC_COMPONENT 8
#define WRITER_COMPONENT 16
#define MATH_COMPONENT 32

// #define OWN_DEBUG_PRINT

typedef int ( __stdcall * DllNativeProc ) ( int, BOOL );

BOOL UnicodeEquals( wchar_t* pStr1, wchar_t* pStr2 )
{
    if ( pStr1 == NULL && pStr2 == NULL )
        return TRUE;
    else if ( pStr1 == NULL || pStr2 == NULL )
        return FALSE;

    while( *pStr1 == *pStr2 && *pStr1 && *pStr2 )
        pStr1++, pStr2++;

    return ( *pStr1 == 0 && *pStr2 == 0 );
}

//----------------------------------------------------------
char* UnicodeToAnsiString( wchar_t* pUniString )
{
    int len = WideCharToMultiByte(
        CP_ACP, 0, pUniString, -1, 0, 0, 0, 0 );

    char* buff = reinterpret_cast<char*>( malloc( len ) );

    WideCharToMultiByte(
        CP_ACP, 0, pUniString, -1, buff, len, 0, 0 );

    return buff;
}

#ifdef OWN_DEBUG_PRINT
void WarningMessageInt( wchar_t* pWarning, unsigned int nValue )
{
    wchar_t pStr[5] = { nValue%10000/1000 + 48, nValue%1000/100 + 48, nValue%100/10 + 48, nValue%10 + 48, 0 };
       MessageBox(NULL, pStr, pWarning, MB_OK | MB_ICONINFORMATION);
}
#endif

//----------------------------------------------------------
void RegisterActiveXNative( const char* pActiveXPath, int nMode, BOOL InstallForAllUser )
{
    // For Win98/WinME the values should be written to the local machine
    OSVERSIONINFO       aVerInfo;
    aVerInfo.dwOSVersionInfoSize = sizeof( aVerInfo );
    if ( GetVersionEx( &aVerInfo ) && aVerInfo.dwPlatformId != VER_PLATFORM_WIN32_NT )
        InstallForAllUser = TRUE;

    HINSTANCE hModule = LoadLibraryExA( pActiveXPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
    if( !( hModule <= ( HINSTANCE )HINSTANCE_ERROR ) )
    {
        DllNativeProc pNativeProc = ( DllNativeProc )GetProcAddress( hModule, "DllRegisterServerNative" );
        if( pNativeProc!=NULL )
            ( *pNativeProc )( nMode, InstallForAllUser );

        FreeLibrary( hModule );
    }
}

//----------------------------------------------------------
void UnregisterActiveXNative( const char* pActiveXPath, int nMode, BOOL InstallForAllUser )
{
    // For Win98/WinME the values should be written to the local machine
    OSVERSIONINFO       aVerInfo;
    aVerInfo.dwOSVersionInfoSize = sizeof( aVerInfo );
    if ( GetVersionEx( &aVerInfo ) && aVerInfo.dwPlatformId != VER_PLATFORM_WIN32_NT )
        InstallForAllUser = TRUE;

    HINSTANCE hModule = LoadLibraryExA( pActiveXPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
    if( !( hModule <= ( HINSTANCE )HINSTANCE_ERROR ) )
    {
        DllNativeProc pNativeProc = ( DllNativeProc )GetProcAddress( hModule, "DllUnregisterServerNative" );
        if( pNativeProc!=NULL )
            ( *pNativeProc )( nMode, InstallForAllUser );

        FreeLibrary( hModule );
    }
}

//----------------------------------------------------------
BOOL GetMsiProp( MSIHANDLE hMSI, const wchar_t* pPropName, wchar_t** ppValue )
{
    DWORD sz = 0;
       if ( MsiGetProperty( hMSI, pPropName, L"", &sz ) == ERROR_MORE_DATA )
       {
           sz++;
           DWORD nbytes = sz * sizeof( wchar_t );
           wchar_t* buff = reinterpret_cast<wchar_t*>( malloc( nbytes ) );
           ZeroMemory( buff, nbytes );
           MsiGetProperty( hMSI, pPropName, buff, &sz );
           *ppValue = buff;

        return TRUE;
    }

    return FALSE;
}

//----------------------------------------------------------
BOOL GetActiveXControlPath( MSIHANDLE hMSI, char** ppActiveXPath )
{
    wchar_t* pProgPath = NULL;
    if ( GetMsiProp( hMSI, L"INSTALLLOCATION", &pProgPath ) && pProgPath )
       {
        char* pCharProgPath = UnicodeToAnsiString( pProgPath );
        if ( pCharProgPath )
        {
            int nLen = strlen( pCharProgPath );
            *ppActiveXPath = reinterpret_cast<char*>( malloc( nLen + 23 ) );
            strncpy( *ppActiveXPath, pCharProgPath, nLen );
            strncpy( (*ppActiveXPath) + nLen, "program\\so_activex.dll", 22 );
            (*ppActiveXPath)[nLen+22] = 0;

            free( pCharProgPath );

            return TRUE;
        }

        free( pProgPath );
    }

    return FALSE;
}

//----------------------------------------------------------
BOOL GetDelta( MSIHANDLE hMSI, int& nOldInstallMode, int& nInstallMode, int& nDeinstallMode )
{
    // for now the chart is always installed
    nOldInstallMode = CHART_COMPONENT;
    nInstallMode = CHART_COMPONENT;
    nDeinstallMode = 0;

    INSTALLSTATE current_state;
       INSTALLSTATE future_state;

    if ( ERROR_SUCCESS == MsiGetFeatureState( hMSI, L"gm_p_Wrt_Bin", &current_state, &future_state ) )
    {
#ifdef OWN_DEBUG_PRINT
        WarningMessageInt( L"writer current_state = ", current_state );
        WarningMessageInt( L"writer future_state = ", future_state );
#endif

        // analyze writer installation mode
        if ( current_state == INSTALLSTATE_LOCAL )
            nOldInstallMode |= WRITER_COMPONENT;

        if ( future_state == INSTALLSTATE_LOCAL
          || ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_UNKNOWN ) )
            nInstallMode |= WRITER_COMPONENT;
           else if ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_ABSENT )
            nDeinstallMode |= WRITER_COMPONENT;
    }
    else
    {
        // assert( FALSE );
    }

    if ( ERROR_SUCCESS == MsiGetFeatureState( hMSI, L"gm_p_Calc_Bin", &current_state, &future_state ) )
    {
#ifdef OWN_DEBUG_PRINT
        WarningMessageInt( L"calc current_state = ", current_state );
        WarningMessageInt( L"calc future_state = ", future_state );
#endif

        // analyze calc installation mode
        if ( current_state == INSTALLSTATE_LOCAL )
            nOldInstallMode |= CALC_COMPONENT;

        if ( future_state == INSTALLSTATE_LOCAL
          || ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_UNKNOWN ) )
            nInstallMode |= CALC_COMPONENT;
           else if ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_ABSENT )
            nDeinstallMode |= CALC_COMPONENT;
    }
    else
    {
        // assert( FALSE );
    }

    if ( ERROR_SUCCESS == MsiGetFeatureState( hMSI, L"gm_p_Draw_Bin", &current_state, &future_state ) )
    {
        // analyze draw installation mode
        if ( current_state == INSTALLSTATE_LOCAL )
            nOldInstallMode |= DRAW_COMPONENT;

        if ( future_state == INSTALLSTATE_LOCAL
          || ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_UNKNOWN ) )
            nInstallMode |= DRAW_COMPONENT;
           else if ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_ABSENT )
            nDeinstallMode |= DRAW_COMPONENT;
    }
    else
    {
        // assert( FALSE );
    }

    if ( ERROR_SUCCESS == MsiGetFeatureState( hMSI, L"gm_p_Impress_Bin", &current_state, &future_state ) )
    {
        // analyze impress installation mode
        if ( current_state == INSTALLSTATE_LOCAL )
            nOldInstallMode |= IMPRESS_COMPONENT;

        if ( future_state == INSTALLSTATE_LOCAL
          || ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_UNKNOWN ) )
            nInstallMode |= IMPRESS_COMPONENT;
           else if ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_ABSENT )
            nDeinstallMode |= IMPRESS_COMPONENT;
    }
    else
    {
        // assert( FALSE );
    }

    if ( ERROR_SUCCESS == MsiGetFeatureState( hMSI, L"gm_p_Math_Bin", &current_state, &future_state ) )
    {
        // analyze math installation mode
        if ( current_state == INSTALLSTATE_LOCAL )
            nOldInstallMode |= MATH_COMPONENT;

        if ( future_state == INSTALLSTATE_LOCAL
          || ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_UNKNOWN ) )
            nInstallMode |= MATH_COMPONENT;
           else if ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_ABSENT )
            nDeinstallMode |= MATH_COMPONENT;
    }
    else
    {
        // assert( FALSE );
    }

    return TRUE;
}

//----------------------------------------------------------
BOOL MakeInstallForAllUsers( MSIHANDLE hMSI )
{
    BOOL bResult = FALSE;
    wchar_t* pVal = NULL;
    if ( GetMsiProp( hMSI, L"ALLUSERS", &pVal ) && pVal )
    {
        bResult = UnicodeEquals( pVal , L"1" );
        free( pVal );
    }

    return bResult;
}

//----------------------------------------------------------
extern "C" UINT __stdcall InstallActiveXControl( MSIHANDLE hMSI )
{
    int nOldInstallMode = 0;
    int nInstallMode = 0;
    int nDeinstallMode = 0;

#ifdef OWN_DEBUG_PRINT
    MessageBox(NULL, L"InstallActiveXControl", L"Information", MB_OK | MB_ICONINFORMATION);
#endif

    INSTALLSTATE current_state;
    INSTALLSTATE future_state;

    if ( ERROR_SUCCESS == MsiGetFeatureState( hMSI, L"gm_o_Activexcontrol", &current_state, &future_state ) )
    {
#ifdef OWN_DEBUG_PRINT
        MessageBox(NULL, L"InstallActiveXControl Step2", L"Information", MB_OK | MB_ICONINFORMATION);
#endif

        BOOL bInstallForAllUser = MakeInstallForAllUsers( hMSI );
        char* pActiveXPath = NULL;
        if ( GetActiveXControlPath( hMSI, &pActiveXPath ) && pActiveXPath
        && GetDelta( hMSI, nOldInstallMode, nInstallMode, nDeinstallMode ) )
        {
#ifdef OWN_DEBUG_PRINT
            MessageBox(NULL, L"InstallActiveXControl Step3", L"Information", MB_OK | MB_ICONINFORMATION);
#endif

            if ( future_state == INSTALLSTATE_LOCAL
              || ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_UNKNOWN ) )
            {
#ifdef OWN_DEBUG_PRINT
                MessageBox(NULL, L"InstallActiveXControl, adjusting", L"Information", MB_OK | MB_ICONINFORMATION);
                WarningMessageInt( L"nInstallMode = ", nInstallMode );
#endif
                // the control is installed in the new selected configuration

                if ( current_state == INSTALLSTATE_LOCAL && nDeinstallMode )
                    UnregisterActiveXNative( pActiveXPath, nDeinstallMode, bInstallForAllUser );

                if ( nInstallMode )
                    RegisterActiveXNative( pActiveXPath, nInstallMode, bInstallForAllUser );
            }
            else if ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_ABSENT )
            {
#ifdef OWN_DEBUG_PRINT
                MessageBox(NULL, L"InstallActiveXControl, removing", L"Information", MB_OK | MB_ICONINFORMATION);
#endif
                if ( nOldInstallMode )
                    UnregisterActiveXNative( pActiveXPath, nOldInstallMode, bInstallForAllUser );
            }
        }

        if ( pActiveXPath )
            free( pActiveXPath );
    }
    else
    {
        // assert( FALSE );
    }

    return ERROR_SUCCESS;
}

//----------------------------------------------------------
extern "C" UINT __stdcall DeinstallActiveXControl( MSIHANDLE hMSI )
{
    INSTALLSTATE current_state;
    INSTALLSTATE future_state;

#ifdef OWN_DEBUG_PRINT
    MessageBox(NULL, L"DeinstallActiveXControl", L"Information", MB_OK | MB_ICONINFORMATION);
#endif

    if ( ERROR_SUCCESS == MsiGetFeatureState( hMSI, L"gm_o_Activexcontrol", &current_state, &future_state ) )
    {
        char* pActiveXPath = NULL;
        if ( current_state == INSTALLSTATE_LOCAL && GetActiveXControlPath( hMSI, &pActiveXPath ) && pActiveXPath )
        {
            BOOL bInstallForAllUser = MakeInstallForAllUsers( hMSI );

            {
                UnregisterActiveXNative( pActiveXPath,
                                        CHART_COMPONENT
                                        | DRAW_COMPONENT
                                        | IMPRESS_COMPONENT
                                        | CALC_COMPONENT
                                        | WRITER_COMPONENT
                                        | MATH_COMPONENT,
                                        bInstallForAllUser );
            }

            free( pActiveXPath );
        }
    }

    return ERROR_SUCCESS;
}
<commit_msg>INTEGRATION: CWS mingwport06 (1.13.90); FILE MERGED 2007/08/24 13:12:57 vg 1.13.90.1: #i75499# pragma is for MSVC<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: regactivex.cxx,v $
 *
 *  $Revision: 1.14 $
 *
 *  last change: $Author: kz $ $Date: 2007-09-06 13:33:15 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#define UNICODE

#ifdef _MSC_VER
#pragma warning(push, 1) /* disable warnings within system headers */
#endif
#include <windows.h>
#include <msiquery.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include <string.h>
#include <malloc.h>

#define CHART_COMPONENT 1
#define DRAW_COMPONENT 2
#define IMPRESS_COMPONENT 4
#define CALC_COMPONENT 8
#define WRITER_COMPONENT 16
#define MATH_COMPONENT 32

// #define OWN_DEBUG_PRINT

typedef int ( __stdcall * DllNativeProc ) ( int, BOOL );

BOOL UnicodeEquals( wchar_t* pStr1, wchar_t* pStr2 )
{
    if ( pStr1 == NULL && pStr2 == NULL )
        return TRUE;
    else if ( pStr1 == NULL || pStr2 == NULL )
        return FALSE;

    while( *pStr1 == *pStr2 && *pStr1 && *pStr2 )
        pStr1++, pStr2++;

    return ( *pStr1 == 0 && *pStr2 == 0 );
}

//----------------------------------------------------------
char* UnicodeToAnsiString( wchar_t* pUniString )
{
    int len = WideCharToMultiByte(
        CP_ACP, 0, pUniString, -1, 0, 0, 0, 0 );

    char* buff = reinterpret_cast<char*>( malloc( len ) );

    WideCharToMultiByte(
        CP_ACP, 0, pUniString, -1, buff, len, 0, 0 );

    return buff;
}

#ifdef OWN_DEBUG_PRINT
void WarningMessageInt( wchar_t* pWarning, unsigned int nValue )
{
    wchar_t pStr[5] = { nValue%10000/1000 + 48, nValue%1000/100 + 48, nValue%100/10 + 48, nValue%10 + 48, 0 };
       MessageBox(NULL, pStr, pWarning, MB_OK | MB_ICONINFORMATION);
}
#endif

//----------------------------------------------------------
void RegisterActiveXNative( const char* pActiveXPath, int nMode, BOOL InstallForAllUser )
{
    // For Win98/WinME the values should be written to the local machine
    OSVERSIONINFO       aVerInfo;
    aVerInfo.dwOSVersionInfoSize = sizeof( aVerInfo );
    if ( GetVersionEx( &aVerInfo ) && aVerInfo.dwPlatformId != VER_PLATFORM_WIN32_NT )
        InstallForAllUser = TRUE;

    HINSTANCE hModule = LoadLibraryExA( pActiveXPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
    if( !( hModule <= ( HINSTANCE )HINSTANCE_ERROR ) )
    {
        DllNativeProc pNativeProc = ( DllNativeProc )GetProcAddress( hModule, "DllRegisterServerNative" );
        if( pNativeProc!=NULL )
            ( *pNativeProc )( nMode, InstallForAllUser );

        FreeLibrary( hModule );
    }
}

//----------------------------------------------------------
void UnregisterActiveXNative( const char* pActiveXPath, int nMode, BOOL InstallForAllUser )
{
    // For Win98/WinME the values should be written to the local machine
    OSVERSIONINFO       aVerInfo;
    aVerInfo.dwOSVersionInfoSize = sizeof( aVerInfo );
    if ( GetVersionEx( &aVerInfo ) && aVerInfo.dwPlatformId != VER_PLATFORM_WIN32_NT )
        InstallForAllUser = TRUE;

    HINSTANCE hModule = LoadLibraryExA( pActiveXPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
    if( !( hModule <= ( HINSTANCE )HINSTANCE_ERROR ) )
    {
        DllNativeProc pNativeProc = ( DllNativeProc )GetProcAddress( hModule, "DllUnregisterServerNative" );
        if( pNativeProc!=NULL )
            ( *pNativeProc )( nMode, InstallForAllUser );

        FreeLibrary( hModule );
    }
}

//----------------------------------------------------------
BOOL GetMsiProp( MSIHANDLE hMSI, const wchar_t* pPropName, wchar_t** ppValue )
{
    DWORD sz = 0;
       if ( MsiGetProperty( hMSI, pPropName, L"", &sz ) == ERROR_MORE_DATA )
       {
           sz++;
           DWORD nbytes = sz * sizeof( wchar_t );
           wchar_t* buff = reinterpret_cast<wchar_t*>( malloc( nbytes ) );
           ZeroMemory( buff, nbytes );
           MsiGetProperty( hMSI, pPropName, buff, &sz );
           *ppValue = buff;

        return TRUE;
    }

    return FALSE;
}

//----------------------------------------------------------
BOOL GetActiveXControlPath( MSIHANDLE hMSI, char** ppActiveXPath )
{
    wchar_t* pProgPath = NULL;
    if ( GetMsiProp( hMSI, L"INSTALLLOCATION", &pProgPath ) && pProgPath )
       {
        char* pCharProgPath = UnicodeToAnsiString( pProgPath );
        if ( pCharProgPath )
        {
            int nLen = strlen( pCharProgPath );
            *ppActiveXPath = reinterpret_cast<char*>( malloc( nLen + 23 ) );
            strncpy( *ppActiveXPath, pCharProgPath, nLen );
            strncpy( (*ppActiveXPath) + nLen, "program\\so_activex.dll", 22 );
            (*ppActiveXPath)[nLen+22] = 0;

            free( pCharProgPath );

            return TRUE;
        }

        free( pProgPath );
    }

    return FALSE;
}

//----------------------------------------------------------
BOOL GetDelta( MSIHANDLE hMSI, int& nOldInstallMode, int& nInstallMode, int& nDeinstallMode )
{
    // for now the chart is always installed
    nOldInstallMode = CHART_COMPONENT;
    nInstallMode = CHART_COMPONENT;
    nDeinstallMode = 0;

    INSTALLSTATE current_state;
       INSTALLSTATE future_state;

    if ( ERROR_SUCCESS == MsiGetFeatureState( hMSI, L"gm_p_Wrt_Bin", &current_state, &future_state ) )
    {
#ifdef OWN_DEBUG_PRINT
        WarningMessageInt( L"writer current_state = ", current_state );
        WarningMessageInt( L"writer future_state = ", future_state );
#endif

        // analyze writer installation mode
        if ( current_state == INSTALLSTATE_LOCAL )
            nOldInstallMode |= WRITER_COMPONENT;

        if ( future_state == INSTALLSTATE_LOCAL
          || ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_UNKNOWN ) )
            nInstallMode |= WRITER_COMPONENT;
           else if ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_ABSENT )
            nDeinstallMode |= WRITER_COMPONENT;
    }
    else
    {
        // assert( FALSE );
    }

    if ( ERROR_SUCCESS == MsiGetFeatureState( hMSI, L"gm_p_Calc_Bin", &current_state, &future_state ) )
    {
#ifdef OWN_DEBUG_PRINT
        WarningMessageInt( L"calc current_state = ", current_state );
        WarningMessageInt( L"calc future_state = ", future_state );
#endif

        // analyze calc installation mode
        if ( current_state == INSTALLSTATE_LOCAL )
            nOldInstallMode |= CALC_COMPONENT;

        if ( future_state == INSTALLSTATE_LOCAL
          || ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_UNKNOWN ) )
            nInstallMode |= CALC_COMPONENT;
           else if ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_ABSENT )
            nDeinstallMode |= CALC_COMPONENT;
    }
    else
    {
        // assert( FALSE );
    }

    if ( ERROR_SUCCESS == MsiGetFeatureState( hMSI, L"gm_p_Draw_Bin", &current_state, &future_state ) )
    {
        // analyze draw installation mode
        if ( current_state == INSTALLSTATE_LOCAL )
            nOldInstallMode |= DRAW_COMPONENT;

        if ( future_state == INSTALLSTATE_LOCAL
          || ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_UNKNOWN ) )
            nInstallMode |= DRAW_COMPONENT;
           else if ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_ABSENT )
            nDeinstallMode |= DRAW_COMPONENT;
    }
    else
    {
        // assert( FALSE );
    }

    if ( ERROR_SUCCESS == MsiGetFeatureState( hMSI, L"gm_p_Impress_Bin", &current_state, &future_state ) )
    {
        // analyze impress installation mode
        if ( current_state == INSTALLSTATE_LOCAL )
            nOldInstallMode |= IMPRESS_COMPONENT;

        if ( future_state == INSTALLSTATE_LOCAL
          || ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_UNKNOWN ) )
            nInstallMode |= IMPRESS_COMPONENT;
           else if ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_ABSENT )
            nDeinstallMode |= IMPRESS_COMPONENT;
    }
    else
    {
        // assert( FALSE );
    }

    if ( ERROR_SUCCESS == MsiGetFeatureState( hMSI, L"gm_p_Math_Bin", &current_state, &future_state ) )
    {
        // analyze math installation mode
        if ( current_state == INSTALLSTATE_LOCAL )
            nOldInstallMode |= MATH_COMPONENT;

        if ( future_state == INSTALLSTATE_LOCAL
          || ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_UNKNOWN ) )
            nInstallMode |= MATH_COMPONENT;
           else if ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_ABSENT )
            nDeinstallMode |= MATH_COMPONENT;
    }
    else
    {
        // assert( FALSE );
    }

    return TRUE;
}

//----------------------------------------------------------
BOOL MakeInstallForAllUsers( MSIHANDLE hMSI )
{
    BOOL bResult = FALSE;
    wchar_t* pVal = NULL;
    if ( GetMsiProp( hMSI, L"ALLUSERS", &pVal ) && pVal )
    {
        bResult = UnicodeEquals( pVal , L"1" );
        free( pVal );
    }

    return bResult;
}

//----------------------------------------------------------
extern "C" UINT __stdcall InstallActiveXControl( MSIHANDLE hMSI )
{
    int nOldInstallMode = 0;
    int nInstallMode = 0;
    int nDeinstallMode = 0;

#ifdef OWN_DEBUG_PRINT
    MessageBox(NULL, L"InstallActiveXControl", L"Information", MB_OK | MB_ICONINFORMATION);
#endif

    INSTALLSTATE current_state;
    INSTALLSTATE future_state;

    if ( ERROR_SUCCESS == MsiGetFeatureState( hMSI, L"gm_o_Activexcontrol", &current_state, &future_state ) )
    {
#ifdef OWN_DEBUG_PRINT
        MessageBox(NULL, L"InstallActiveXControl Step2", L"Information", MB_OK | MB_ICONINFORMATION);
#endif

        BOOL bInstallForAllUser = MakeInstallForAllUsers( hMSI );
        char* pActiveXPath = NULL;
        if ( GetActiveXControlPath( hMSI, &pActiveXPath ) && pActiveXPath
        && GetDelta( hMSI, nOldInstallMode, nInstallMode, nDeinstallMode ) )
        {
#ifdef OWN_DEBUG_PRINT
            MessageBox(NULL, L"InstallActiveXControl Step3", L"Information", MB_OK | MB_ICONINFORMATION);
#endif

            if ( future_state == INSTALLSTATE_LOCAL
              || ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_UNKNOWN ) )
            {
#ifdef OWN_DEBUG_PRINT
                MessageBox(NULL, L"InstallActiveXControl, adjusting", L"Information", MB_OK | MB_ICONINFORMATION);
                WarningMessageInt( L"nInstallMode = ", nInstallMode );
#endif
                // the control is installed in the new selected configuration

                if ( current_state == INSTALLSTATE_LOCAL && nDeinstallMode )
                    UnregisterActiveXNative( pActiveXPath, nDeinstallMode, bInstallForAllUser );

                if ( nInstallMode )
                    RegisterActiveXNative( pActiveXPath, nInstallMode, bInstallForAllUser );
            }
            else if ( current_state == INSTALLSTATE_LOCAL && future_state == INSTALLSTATE_ABSENT )
            {
#ifdef OWN_DEBUG_PRINT
                MessageBox(NULL, L"InstallActiveXControl, removing", L"Information", MB_OK | MB_ICONINFORMATION);
#endif
                if ( nOldInstallMode )
                    UnregisterActiveXNative( pActiveXPath, nOldInstallMode, bInstallForAllUser );
            }
        }

        if ( pActiveXPath )
            free( pActiveXPath );
    }
    else
    {
        // assert( FALSE );
    }

    return ERROR_SUCCESS;
}

//----------------------------------------------------------
extern "C" UINT __stdcall DeinstallActiveXControl( MSIHANDLE hMSI )
{
    INSTALLSTATE current_state;
    INSTALLSTATE future_state;

#ifdef OWN_DEBUG_PRINT
    MessageBox(NULL, L"DeinstallActiveXControl", L"Information", MB_OK | MB_ICONINFORMATION);
#endif

    if ( ERROR_SUCCESS == MsiGetFeatureState( hMSI, L"gm_o_Activexcontrol", &current_state, &future_state ) )
    {
        char* pActiveXPath = NULL;
        if ( current_state == INSTALLSTATE_LOCAL && GetActiveXControlPath( hMSI, &pActiveXPath ) && pActiveXPath )
        {
            BOOL bInstallForAllUser = MakeInstallForAllUsers( hMSI );

            {
                UnregisterActiveXNative( pActiveXPath,
                                        CHART_COMPONENT
                                        | DRAW_COMPONENT
                                        | IMPRESS_COMPONENT
                                        | CALC_COMPONENT
                                        | WRITER_COMPONENT
                                        | MATH_COMPONENT,
                                        bInstallForAllUser );
            }

            free( pActiveXPath );
        }
    }

    return ERROR_SUCCESS;
}
<|endoftext|>