<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (testabilitydriver@nokia.com)
**
** This file is part of Testability Driver Qt Agent
**
** If you have questions regarding the use of this file, please contact
** Nokia at testabilitydriver@nokia.com .
**
** 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
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <QFontMetricsF>
#include <QTextCodec>

#if QT_VERSION >= 0x040700
#include <QDeclarativeItem>
#endif

#include "testabilityutils.h"
#include "tastraverseutils.h"
#include "taslogger.h"
#include "tasqtdatamodel.h"
#include "tasqtcommandmodel.h"

const char* const QT_PREFIX ="Qt_";

TasTraverseUtils::TasTraverseUtils()
{
    mTraverseFilter = new TasDataFilter();

}

TasTraverseUtils::~TasTraverseUtils()
{
    delete mTraverseFilter;
}

/*!
 * Createst a filter from the given data. A filter must always be cleared
 * after use.
 */
void TasTraverseUtils::createFilter(TasCommand* command)
{
    mTraverseFilter->initialize(command);
}

/*!
  Clears the filter.
 */
void TasTraverseUtils::clearFilter()
 {
    mTraverseFilter->clear();
}

void TasTraverseUtils::addObjectDetails(TasObject* objectInfo, QObject* object)
{
    objectInfo->setId(TasCoreUtils::objectId(object));

    //custom traversers may want to add their own types
    if(objectInfo->getType().isEmpty()){
        QString objectType = object->metaObject()->className();
        objectType.replace(QString(":"), QString("_"));
#if QT_VERSION >= 0x040700
        //strip dynamic qml strings from the class name
        if(qobject_cast<QDeclarativeItem*>(object)){
            QStringList stringList = objectType.split("_QML");
            QString strippedType = stringList.takeFirst();
            objectInfo->addAttribute("QML_TYPE_EXTENSION",  objectType.remove(strippedType));
            objectType = strippedType;
        }
#endif
        objectInfo->setType(objectType);
    }
    if(includeAttribute("parent")){
        objectInfo->setParentId(getParentId(object));
    }
    printProperties(objectInfo, object);
    objectInfo->setName(object->objectName());

}

QString TasTraverseUtils::getParentId(QObject* object)
{
    QString parentId;
    QGraphicsWidget* go = qobject_cast<QGraphicsWidget*>(object);
    if(go){
        QGraphicsItem* gParent = go->parentItem();
        parentId = gParent ? TestabilityUtils::graphicsItemId(gParent):"";
    }
    if(parentId == 0){
        QObject* parent = object->parent();
        parentId = parent ? TasCoreUtils::objectId(parent):"";
    }
    return parentId;
}

void TasTraverseUtils::addVariantValue(TasAttribute& attr, const QVariant& value)
{
    switch (value.type()) {
    case QVariant::Size:
        attr.addValue(value.toSize());
        break;
    case QVariant::SizeF:
        attr.addValue(value.toSizeF());
        break;
    case QVariant::Point:
        attr.addValue(value.toPoint());
        break;
    case QVariant::PointF:
        attr.addValue(value.toPointF());
        break;
    case QVariant::Rect:
        attr.addValue(value.toRect());
        break;
    case QVariant::RectF:
        attr.addValue(value.toRectF());
        break;
    case QVariant::DateTime:
        attr.addValue(QString::number(value.toDateTime().toTime_t()));
        break;
    case QVariant::Date:
        attr.addValue(value.toDate().toString("dd.MM.yyyy"));
        break;
    default:
        attr.addValue(value.toString());
        break;
    }

    if(QVariant::typeToName(value.type())){
        attr.setDataType(QVariant::typeToName(value.type()));
    }

}

/*
  Print metadata details to the model.
*/
void TasTraverseUtils::printProperties(TasObject* objectInfo, QObject* object)
{
    const QMetaObject *metaobject = object->metaObject();
    int count = metaobject->propertyCount();
    for (int i=0; i<count; i++){
        QMetaProperty metaproperty = metaobject->property(i);
        const char *name = metaproperty.name();
        if(includeAttribute(name)){
            TasAttribute& attr = objectInfo->addAttribute();
            //coordinates are always relative to something in the props
            if(QString(name) != "y" && QString(name) != "x" && QString(name) != "width" && QString(name) != "height"){
                attr.setName(name);
            }
            else{
                attr.setName(QString(QT_PREFIX)+name);
            }
            QVariant value = object->property(name);
            if(metaproperty.isEnumType() && !metaproperty.isFlagType()){
                QMetaEnum enumeration = metaproperty.enumerator();
                bool ok = false;
                int enumValue = value.toInt(&ok);
                if(ok){
                    attr.addValue(enumeration.valueToKey(enumValue));
                }
                else{
                    attr.addValue(value.toString());
                }
            }
            else{
                addVariantValue(attr, value);
            }

            if(mTraverseFilter == 0 || !mTraverseFilter->filterProperties()){
                QString propertyTypes = "";
                if(metaproperty.isReadable()){
                    propertyTypes = "readable";
                }
                if(metaproperty.isWritable ()){
                    if(!propertyTypes.isEmpty()){
                        propertyTypes += QString(", ");
                    }
                    propertyTypes += QString("writable");
                }
                attr.setType(propertyTypes);
            }
        }
    }

    QList<QByteArray> dynNames = object->dynamicPropertyNames();
    foreach(QByteArray bytes, dynNames) {
        QString name(bytes);
        TasAttribute& attr = objectInfo->addAttribute();
        attr.setName(name);
        addVariantValue(attr, object->property(bytes.data()));
    }
}

/*!
  Adds font details to the item. The prefix can be used in situations where one item can have multiple fonts.
 */
void TasTraverseUtils::addFont(TasObject* objectInfo, QFont font)
{
    if(includeAttribute("fontKey")){
        objectInfo->addAttribute("fontKey", font.key());
    }
    if(includeAttribute("fontFamily")){
        objectInfo->addAttribute("fontFamily", font.family());
    }
    if(includeAttribute("bold")){
        objectInfo->addBooleanAttribute("bold", font.bold());
    }
    if(includeAttribute("fixedPitch")){
        objectInfo->addBooleanAttribute("fixedPitch", font.fixedPitch());
    }
    if(includeAttribute("italic")){
        objectInfo->addBooleanAttribute("italic", font.italic());
    }
    if(includeAttribute("pixelSize")){
        objectInfo->addAttribute("pixelSize", font.pixelSize());
    }
    if(includeAttribute("pointSize")){
        objectInfo->addAttribute("pointSize", font.pointSizeF());
    }
    if(includeAttribute("letterSpacing")){
        objectInfo->addAttribute("letterSpacing", font.letterSpacing());
    }
    if(includeAttribute("kerning")){
        objectInfo->addBooleanAttribute("kerning", font.kerning());
    }
    if(includeAttribute("overline")){
        objectInfo->addBooleanAttribute("overline", font.overline());
    }
    if(includeAttribute("strikeOut")){
        objectInfo->addBooleanAttribute("strikeOut", font.strikeOut());
    }
    if(includeAttribute("capitalization")){
        objectInfo->addAttribute("capitalization", font.capitalization());
    }
    if(includeAttribute("fontWeight")){
        objectInfo->addAttribute("fontWeight", font.weight());
    }
    if(includeAttribute("wordSpacing")){
        objectInfo->addAttribute("wordSpacing", font.wordSpacing());
    }
}

bool TasTraverseUtils::includeAttribute(const QString& attributeName)
{
    if(mTraverseFilter){
        if(mTraverseFilter->includeAttribute(attributeName) || mTraverseFilter->includeAttribute(QT_PREFIX+attributeName)){
            return true;
        }
        return false;
    }
    return true;
}

QPair<QPoint,QPoint> TasTraverseUtils::addGraphicsItemCoordinates(TasObject* objectInfo,
                                                                 QGraphicsItem* graphicsItem,
                                                                 TasCommand* command)
{
    objectInfo->addAttribute("scenePos", graphicsItem->scenePos());
    ItemLocationDetails locationDetails = TestabilityUtils::getItemLocationDetails(graphicsItem, command);

    QPair<QPoint,QPoint> coords;
    if(true /*locationDetails.visible*/){
        objectInfo->addAttribute("x", locationDetails.windowPoint.x());
        objectInfo->addAttribute("y", locationDetails.windowPoint.y());

        objectInfo->addAttribute("x_absolute", locationDetails.screenPoint.x());
        objectInfo->addAttribute("y_absolute", locationDetails.screenPoint.y());

        coords.first = locationDetails.windowPoint;
        coords.second = locationDetails.screenPoint;

        objectInfo->addAttribute("width", locationDetails.width);
        objectInfo->addAttribute("height", locationDetails.height);
    }

    // if the onDisplay property is calculated by the fw, believe it if is set to false.
    /*
    QGraphicsObject* qobj = graphicsItem->toGraphicsObject();
    if (qobj) {
        QVariant onDisplay = qobj->property("onDisplay");
        if (onDisplay.isValid() && !onDisplay.toBool()) {
            objectInfo->addBooleanAttribute("visibleOnScreen", false);
        } else {
            objectInfo->addBooleanAttribute("visibleOnScreen", locationDetails.visible);
        }
    } else { */
        objectInfo->addBooleanAttribute("visibleOnScreen", locationDetails.visible);
    //}
    return coords;
}

/*!
  Add details about the text into the attribute. Including elide and coded details.
  Add the elided text, e.g. "This is a long text" -> "This is a long ...", into attributes
*/
void TasTraverseUtils::addTextInfo(TasObject* objectInfo, const QString& text,
                                  const QFont& font, qreal width, Qt::TextElideMode mode)
{
    QFontMetricsF metrics(font);

    QString elided = metrics.elidedText(text, mode, width);
    objectInfo->addAttribute("elidedText", elided);
    bool inFont = true;
    for (int i = 0; i < text.size(); ++i) {
        // endline char will always fail the comparison
        if (text.at(i) != '\n' && !metrics.inFont(text.at(i))) {
            inFont = false;
            break;
        }
    }
    objectInfo->addBooleanAttribute("canDisplayText", inFont);
}

/*!
    Print graphicsitem details that could be usable to the model.
*/
void TasTraverseUtils::printGraphicsItemProperties(TasObject* objectInfo, QGraphicsItem* graphicsItem)
{
    QGraphicsObject* gObject = graphicsItem->toGraphicsObject();

    if(mTraverseFilter->includeAttribute("visible")){
        if(gObject && !gObject->property("visible").isValid())
            objectInfo->addBooleanAttribute("visible", graphicsItem->isVisible());
    }
    if(mTraverseFilter->includeAttribute("enabled")){
        if(gObject && !gObject->property("enabled").isValid())
            objectInfo->addBooleanAttribute("enabled", graphicsItem->isEnabled());
    }
    if(mTraverseFilter->includeAttribute("selected")){
        if(gObject && !gObject->property("selected").isValid())
            objectInfo->addBooleanAttribute("selected", graphicsItem->isSelected());
    }
    if(mTraverseFilter->includeAttribute("obscured")){
        if(gObject && !gObject->property("obscured").isValid())
            objectInfo->addBooleanAttribute("obscured", graphicsItem->isObscured());
    }
    if(mTraverseFilter->includeAttribute("focus")){
        if(gObject && !gObject->property("focus").isValid())
            objectInfo->addBooleanAttribute("focus", graphicsItem->hasFocus());
    }
    if(mTraverseFilter->includeAttribute("under-mouse")){
        if(gObject && !gObject->property("under-mouse").isValid())
            objectInfo->addBooleanAttribute("under-mouse", graphicsItem->isUnderMouse());
    }
    if(mTraverseFilter->includeAttribute("droppable")){
        if(gObject && !gObject->property("droppable").isValid())
            objectInfo->addBooleanAttribute("droppable", graphicsItem->acceptDrops());
    }
    if(mTraverseFilter->includeAttribute("hoverable")){
        if(gObject && !gObject->property("hoverable").isValid())
            objectInfo->addBooleanAttribute("hoverable", graphicsItem->acceptHoverEvents());
    }
    if(mTraverseFilter->includeAttribute("tooltip")){
        if(gObject && !gObject->property("tooltip").isValid())
            objectInfo->addAttribute("tooltip", graphicsItem->toolTip());
    }
    if(mTraverseFilter->includeAttribute("z-value")){
        if(gObject && !gObject->property("z-value").isValid())
            objectInfo->addAttribute("z-value", QString::number(graphicsItem->zValue()));
    }
}

TasDataFilter::TasDataFilter()
{
    mExcludeProperties = true;
}

TasDataFilter::~TasDataFilter()
{
    clear();
}

void TasDataFilter::initialize(TasCommand* command)
{
    clear();
    if(!command){
        return;
    }
    //if the command contains filtering instructions
    //set the them for all traverser plugins
    QStringList attributeBlackList;
    if(!command->apiParameter("attributeBlackList").isEmpty()){
         mAttributeBlackList = command->apiParameter("attributeBlackList").split(",");
    }
    QStringList attributeWhiteList;
    if(!command->apiParameter("attributeWhiteList").isEmpty()){
        mAttributeWhiteList = command->apiParameter("attributeWhiteList").split(",");
    }
    mExcludeProperties = false;
    if(command->apiParameter("filterProperties") =="true"){
        mExcludeProperties = true;
    }
}

void TasDataFilter::clear()
{
    mAttributeWhiteList.clear();
    mAttributeBlackList.clear();
    mExcludeProperties = true;
}

bool TasDataFilter::filterProperties()
{
    return mExcludeProperties;
}

bool TasDataFilter::includeAttribute(const QString& attributeName)
{
    bool include = false;
    if(mAttributeWhiteList.isEmpty() && mAttributeBlackList.isEmpty()){
        include = true;
    }
    //black list is valued higher than white list
    else if(mAttributeWhiteList.contains(attributeName) && !mAttributeBlackList.contains(attributeName)){
        include = true;
    }
    else if(mAttributeWhiteList.isEmpty() && !mAttributeBlackList.contains(attributeName)){
        include = true;
    }
    return include;
}

<commit_msg>Enabled onDisplay checking again for meego MTF<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (testabilitydriver@nokia.com)
**
** This file is part of Testability Driver Qt Agent
**
** If you have questions regarding the use of this file, please contact
** Nokia at testabilitydriver@nokia.com .
**
** 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
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <QFontMetricsF>
#include <QTextCodec>

#if QT_VERSION >= 0x040700
#include <QDeclarativeItem>
#endif

#include "testabilityutils.h"
#include "tastraverseutils.h"
#include "taslogger.h"
#include "tasqtdatamodel.h"
#include "tasqtcommandmodel.h"

const char* const QT_PREFIX ="Qt_";

TasTraverseUtils::TasTraverseUtils()
{
    mTraverseFilter = new TasDataFilter();

}

TasTraverseUtils::~TasTraverseUtils()
{
    delete mTraverseFilter;
}

/*!
 * Createst a filter from the given data. A filter must always be cleared
 * after use.
 */
void TasTraverseUtils::createFilter(TasCommand* command)
{
    mTraverseFilter->initialize(command);
}

/*!
  Clears the filter.
 */
void TasTraverseUtils::clearFilter()
 {
    mTraverseFilter->clear();
}

void TasTraverseUtils::addObjectDetails(TasObject* objectInfo, QObject* object)
{
    objectInfo->setId(TasCoreUtils::objectId(object));

    //custom traversers may want to add their own types
    if(objectInfo->getType().isEmpty()){
        QString objectType = object->metaObject()->className();
        objectType.replace(QString(":"), QString("_"));
#if QT_VERSION >= 0x040700
        //strip dynamic qml strings from the class name
        if(qobject_cast<QDeclarativeItem*>(object)){
            QStringList stringList = objectType.split("_QML");
            QString strippedType = stringList.takeFirst();
            objectInfo->addAttribute("QML_TYPE_EXTENSION",  objectType.remove(strippedType));
            objectType = strippedType;
        }
#endif
        objectInfo->setType(objectType);
    }
    if(includeAttribute("parent")){
        objectInfo->setParentId(getParentId(object));
    }
    printProperties(objectInfo, object);
    objectInfo->setName(object->objectName());

}

QString TasTraverseUtils::getParentId(QObject* object)
{
    QString parentId;
    QGraphicsWidget* go = qobject_cast<QGraphicsWidget*>(object);
    if(go){
        QGraphicsItem* gParent = go->parentItem();
        parentId = gParent ? TestabilityUtils::graphicsItemId(gParent):"";
    }
    if(parentId == 0){
        QObject* parent = object->parent();
        parentId = parent ? TasCoreUtils::objectId(parent):"";
    }
    return parentId;
}

void TasTraverseUtils::addVariantValue(TasAttribute& attr, const QVariant& value)
{
    switch (value.type()) {
    case QVariant::Size:
        attr.addValue(value.toSize());
        break;
    case QVariant::SizeF:
        attr.addValue(value.toSizeF());
        break;
    case QVariant::Point:
        attr.addValue(value.toPoint());
        break;
    case QVariant::PointF:
        attr.addValue(value.toPointF());
        break;
    case QVariant::Rect:
        attr.addValue(value.toRect());
        break;
    case QVariant::RectF:
        attr.addValue(value.toRectF());
        break;
    case QVariant::DateTime:
        attr.addValue(QString::number(value.toDateTime().toTime_t()));
        break;
    case QVariant::Date:
        attr.addValue(value.toDate().toString("dd.MM.yyyy"));
        break;
    default:
        attr.addValue(value.toString());
        break;
    }

    if(QVariant::typeToName(value.type())){
        attr.setDataType(QVariant::typeToName(value.type()));
    }

}

/*
  Print metadata details to the model.
*/
void TasTraverseUtils::printProperties(TasObject* objectInfo, QObject* object)
{
    const QMetaObject *metaobject = object->metaObject();
    int count = metaobject->propertyCount();
    for (int i=0; i<count; i++){
        QMetaProperty metaproperty = metaobject->property(i);
        const char *name = metaproperty.name();
        if(includeAttribute(name)){
            TasAttribute& attr = objectInfo->addAttribute();
            //coordinates are always relative to something in the props
            if(QString(name) != "y" && QString(name) != "x" && QString(name) != "width" && QString(name) != "height"){
                attr.setName(name);
            }
            else{
                attr.setName(QString(QT_PREFIX)+name);
            }
            QVariant value = object->property(name);
            if(metaproperty.isEnumType() && !metaproperty.isFlagType()){
                QMetaEnum enumeration = metaproperty.enumerator();
                bool ok = false;
                int enumValue = value.toInt(&ok);
                if(ok){
                    attr.addValue(enumeration.valueToKey(enumValue));
                }
                else{
                    attr.addValue(value.toString());
                }
            }
            else{
                addVariantValue(attr, value);
            }

            if(mTraverseFilter == 0 || !mTraverseFilter->filterProperties()){
                QString propertyTypes = "";
                if(metaproperty.isReadable()){
                    propertyTypes = "readable";
                }
                if(metaproperty.isWritable ()){
                    if(!propertyTypes.isEmpty()){
                        propertyTypes += QString(", ");
                    }
                    propertyTypes += QString("writable");
                }
                attr.setType(propertyTypes);
            }
        }
    }

    QList<QByteArray> dynNames = object->dynamicPropertyNames();
    foreach(QByteArray bytes, dynNames) {
        QString name(bytes);
        TasAttribute& attr = objectInfo->addAttribute();
        attr.setName(name);
        addVariantValue(attr, object->property(bytes.data()));
    }
}

/*!
  Adds font details to the item. The prefix can be used in situations where one item can have multiple fonts.
 */
void TasTraverseUtils::addFont(TasObject* objectInfo, QFont font)
{
    if(includeAttribute("fontKey")){
        objectInfo->addAttribute("fontKey", font.key());
    }
    if(includeAttribute("fontFamily")){
        objectInfo->addAttribute("fontFamily", font.family());
    }
    if(includeAttribute("bold")){
        objectInfo->addBooleanAttribute("bold", font.bold());
    }
    if(includeAttribute("fixedPitch")){
        objectInfo->addBooleanAttribute("fixedPitch", font.fixedPitch());
    }
    if(includeAttribute("italic")){
        objectInfo->addBooleanAttribute("italic", font.italic());
    }
    if(includeAttribute("pixelSize")){
        objectInfo->addAttribute("pixelSize", font.pixelSize());
    }
    if(includeAttribute("pointSize")){
        objectInfo->addAttribute("pointSize", font.pointSizeF());
    }
    if(includeAttribute("letterSpacing")){
        objectInfo->addAttribute("letterSpacing", font.letterSpacing());
    }
    if(includeAttribute("kerning")){
        objectInfo->addBooleanAttribute("kerning", font.kerning());
    }
    if(includeAttribute("overline")){
        objectInfo->addBooleanAttribute("overline", font.overline());
    }
    if(includeAttribute("strikeOut")){
        objectInfo->addBooleanAttribute("strikeOut", font.strikeOut());
    }
    if(includeAttribute("capitalization")){
        objectInfo->addAttribute("capitalization", font.capitalization());
    }
    if(includeAttribute("fontWeight")){
        objectInfo->addAttribute("fontWeight", font.weight());
    }
    if(includeAttribute("wordSpacing")){
        objectInfo->addAttribute("wordSpacing", font.wordSpacing());
    }
}

bool TasTraverseUtils::includeAttribute(const QString& attributeName)
{
    if(mTraverseFilter){
        if(mTraverseFilter->includeAttribute(attributeName) || mTraverseFilter->includeAttribute(QT_PREFIX+attributeName)){
            return true;
        }
        return false;
    }
    return true;
}

QPair<QPoint,QPoint> TasTraverseUtils::addGraphicsItemCoordinates(TasObject* objectInfo,
                                                                 QGraphicsItem* graphicsItem,
                                                                 TasCommand* command)
{
    objectInfo->addAttribute("scenePos", graphicsItem->scenePos());
    ItemLocationDetails locationDetails = TestabilityUtils::getItemLocationDetails(graphicsItem, command);

    QPair<QPoint,QPoint> coords;
    if(true /*locationDetails.visible*/){
        objectInfo->addAttribute("x", locationDetails.windowPoint.x());
        objectInfo->addAttribute("y", locationDetails.windowPoint.y());

        objectInfo->addAttribute("x_absolute", locationDetails.screenPoint.x());
        objectInfo->addAttribute("y_absolute", locationDetails.screenPoint.y());

        coords.first = locationDetails.windowPoint;
        coords.second = locationDetails.screenPoint;

        objectInfo->addAttribute("width", locationDetails.width);
        objectInfo->addAttribute("height", locationDetails.height);
    }

    // if the onDisplay property is calculated by the fw, believe it if is set to false.
    QGraphicsObject* qobj = graphicsItem->toGraphicsObject();
    if (qobj) {
        QVariant onDisplay = qobj->property("onDisplay");
        if (onDisplay.isValid() && !onDisplay.toBool()) {
            objectInfo->addBooleanAttribute("visibleOnScreen", false);
        } else {
            objectInfo->addBooleanAttribute("visibleOnScreen", locationDetails.visible);
        }
    } else {
        objectInfo->addBooleanAttribute("visibleOnScreen", locationDetails.visible);
    }
    return coords;
}

/*!
  Add details about the text into the attribute. Including elide and coded details.
  Add the elided text, e.g. "This is a long text" -> "This is a long ...", into attributes
*/
void TasTraverseUtils::addTextInfo(TasObject* objectInfo, const QString& text,
                                  const QFont& font, qreal width, Qt::TextElideMode mode)
{
    QFontMetricsF metrics(font);

    QString elided = metrics.elidedText(text, mode, width);
    objectInfo->addAttribute("elidedText", elided);
    bool inFont = true;
    for (int i = 0; i < text.size(); ++i) {
        // endline char will always fail the comparison
        if (text.at(i) != '\n' && !metrics.inFont(text.at(i))) {
            inFont = false;
            break;
        }
    }
    objectInfo->addBooleanAttribute("canDisplayText", inFont);
}

/*!
    Print graphicsitem details that could be usable to the model.
*/
void TasTraverseUtils::printGraphicsItemProperties(TasObject* objectInfo, QGraphicsItem* graphicsItem)
{
    QGraphicsObject* gObject = graphicsItem->toGraphicsObject();

    if(mTraverseFilter->includeAttribute("visible")){
        if(gObject && !gObject->property("visible").isValid())
            objectInfo->addBooleanAttribute("visible", graphicsItem->isVisible());
    }
    if(mTraverseFilter->includeAttribute("enabled")){
        if(gObject && !gObject->property("enabled").isValid())
            objectInfo->addBooleanAttribute("enabled", graphicsItem->isEnabled());
    }
    if(mTraverseFilter->includeAttribute("selected")){
        if(gObject && !gObject->property("selected").isValid())
            objectInfo->addBooleanAttribute("selected", graphicsItem->isSelected());
    }
    if(mTraverseFilter->includeAttribute("obscured")){
        if(gObject && !gObject->property("obscured").isValid())
            objectInfo->addBooleanAttribute("obscured", graphicsItem->isObscured());
    }
    if(mTraverseFilter->includeAttribute("focus")){
        if(gObject && !gObject->property("focus").isValid())
            objectInfo->addBooleanAttribute("focus", graphicsItem->hasFocus());
    }
    if(mTraverseFilter->includeAttribute("under-mouse")){
        if(gObject && !gObject->property("under-mouse").isValid())
            objectInfo->addBooleanAttribute("under-mouse", graphicsItem->isUnderMouse());
    }
    if(mTraverseFilter->includeAttribute("droppable")){
        if(gObject && !gObject->property("droppable").isValid())
            objectInfo->addBooleanAttribute("droppable", graphicsItem->acceptDrops());
    }
    if(mTraverseFilter->includeAttribute("hoverable")){
        if(gObject && !gObject->property("hoverable").isValid())
            objectInfo->addBooleanAttribute("hoverable", graphicsItem->acceptHoverEvents());
    }
    if(mTraverseFilter->includeAttribute("tooltip")){
        if(gObject && !gObject->property("tooltip").isValid())
            objectInfo->addAttribute("tooltip", graphicsItem->toolTip());
    }
    if(mTraverseFilter->includeAttribute("z-value")){
        if(gObject && !gObject->property("z-value").isValid())
            objectInfo->addAttribute("z-value", QString::number(graphicsItem->zValue()));
    }
}

TasDataFilter::TasDataFilter()
{
    mExcludeProperties = true;
}

TasDataFilter::~TasDataFilter()
{
    clear();
}

void TasDataFilter::initialize(TasCommand* command)
{
    clear();
    if(!command){
        return;
    }
    //if the command contains filtering instructions
    //set the them for all traverser plugins
    QStringList attributeBlackList;
    if(!command->apiParameter("attributeBlackList").isEmpty()){
         mAttributeBlackList = command->apiParameter("attributeBlackList").split(",");
    }
    QStringList attributeWhiteList;
    if(!command->apiParameter("attributeWhiteList").isEmpty()){
        mAttributeWhiteList = command->apiParameter("attributeWhiteList").split(",");
    }
    mExcludeProperties = false;
    if(command->apiParameter("filterProperties") =="true"){
        mExcludeProperties = true;
    }
}

void TasDataFilter::clear()
{
    mAttributeWhiteList.clear();
    mAttributeBlackList.clear();
    mExcludeProperties = true;
}

bool TasDataFilter::filterProperties()
{
    return mExcludeProperties;
}

bool TasDataFilter::includeAttribute(const QString& attributeName)
{
    bool include = false;
    if(mAttributeWhiteList.isEmpty() && mAttributeBlackList.isEmpty()){
        include = true;
    }
    //black list is valued higher than white list
    else if(mAttributeWhiteList.contains(attributeName) && !mAttributeBlackList.contains(attributeName)){
        include = true;
    }
    else if(mAttributeWhiteList.isEmpty() && !mAttributeBlackList.contains(attributeName)){
        include = true;
    }
    return include;
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 Oleg Morozenkov
 * Copyright (c) 2018 Egor Pugin
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "tgbot/net/HttpClient.h"

#include <boost/asio/ssl.hpp>

using namespace std;
using namespace boost::asio;
using namespace boost::asio::ip;

namespace TgBot {

BoostHttpClient& BoostHttpClient::getInstance() {
	static BoostHttpClient result;
	return result;
}

string BoostHttpClient::makeRequest(const Url& url, const vector<HttpReqArg>& args) const {
	ssl::context context(ssl::context::sslv23);
	context.set_default_verify_paths();

	ssl::stream<tcp::socket> socket(_ioService, context);
	tcp::resolver resolver(_ioService);
	tcp::resolver::query query(url.host, url.protocol);

	connect(socket.lowest_layer(), resolver.resolve(query));

	#ifdef TGBOT_DISABLE_NAGLES_ALGORITHM
	socket.lowest_layer().set_option(tcp::no_delay(true));
	#endif //TGBOT_DISABLE_NAGLES_ALGORITHM

	#ifdef TGBOT_CHANGE_SOCKET_BUFFER_SIZE
	#if _WIN64 || __amd64__ || __x86_64__ || __MINGW64__ || __aarch64__ || __powerpc64__
	socket.lowest_layer().set_option(socket_base::send_buffer_size(65536));
	socket.lowest_layer().set_option(socket_base::receive_buffer_size(65536));
	#else //for 32-bit
	socket.lowest_layer().set_option(socket_base::send_buffer_size(32768));
	socket.lowest_layer().set_option(socket_base::receive_buffer_size(32768));
	#endif //Processor architecture
	#endif //TGBOT_CHANGE_SOCKET_BUFFER_SIZE

	socket.set_verify_mode(ssl::verify_none);
	socket.set_verify_callback(ssl::rfc2818_verification(url.host));
	socket.handshake(ssl::stream<tcp::socket>::client);

	string requestText = HttpParser::getInstance().generateRequest(url, args, false);
	write(socket, buffer(requestText.c_str(), requestText.length()));

	string response;

	#ifdef TGBOT_CHANGE_READ_BUFFER_SIZE
	#if _WIN64 || __amd64__ || __x86_64__ || __MINGW64__ || __aarch64__ || __powerpc64__
	char buff[65536];
	#else //for 32-bit
	char buff[32768];
	#endif //Processor architecture
	#else
	char buff[1024];
	#endif //TGBOT_CHANGE_READ_BUFFER_SIZE

	boost::system::error_code error;
	while (!error) {
		size_t bytes = read(socket, buffer(buff), error);
		response += string(buff, bytes);
	}

	return HttpParser::getInstance().parseResponse(response);
}

#ifdef HAVE_CURL

CurlHttpClient::CurlHttpClient() {
    curlSettings = curl_easy_init();
}

CurlHttpClient::~CurlHttpClient() {
    curl_easy_cleanup(curlSettings);
}

CurlHttpClient& CurlHttpClient::getInstance() {
    static CurlHttpClient result;
    return result;
}

static size_t curl_write_string(char *ptr, size_t size, size_t nmemb, void *userdata)
{
    std::string &s = *(std::string *)userdata;
    auto read = size * nmemb;
    s.append(ptr, ptr + read);
    return read;
};

string CurlHttpClient::makeRequest(const Url& url, const vector<HttpReqArg>& args) const {
    // Copy settings for each call because we change CURLOPT_URL and other stuff.
    // This also protects multithreaded case.
    auto curl = curl_easy_duphandle(curlSettings);

    auto u = url.protocol + "://" + url.host + url.path;
    curl_easy_setopt(curl, CURLOPT_URL, u.c_str());

    // disable keep-alive
    struct curl_slist *headers = NULL;
    headers = curl_slist_append(headers, "Connection: close");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

    std::string data;
    std::vector<char *> escaped;
    if (!args.empty())
    {
        for (auto &a : args)
        {
            escaped.push_back(curl_easy_escape(curl, a.name.c_str(), a.name.size()));
            data += escaped.back() + std::string("=");
            escaped.push_back(curl_easy_escape(curl, a.value.c_str(), a.value.size()));
            data += escaped.back() + std::string("&");
        }
        data.resize(data.size() - 1);
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
        curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)data.size());
    }

    std::string response;
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_string);

    auto res = curl_easy_perform(curl);
    long http_code;
    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
    curl_slist_free_all(headers);
    curl_easy_cleanup(curl);

    for (auto &e : escaped)
        curl_free(e);

    if (res != CURLE_OK)
        throw std::runtime_error(std::string("curl error: ") + curl_easy_strerror(res));
    if (http_code != 200)
        throw std::runtime_error("http request returned with code = " + std::to_string(http_code));

    return HttpParser::getInstance().parseResponse(response);
}

#endif

}
<commit_msg>Remove error on bad http request. It is handled by Api.<commit_after>/*
 * Copyright (c) 2015 Oleg Morozenkov
 * Copyright (c) 2018 Egor Pugin
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "tgbot/net/HttpClient.h"

#include <boost/asio/ssl.hpp>

using namespace std;
using namespace boost::asio;
using namespace boost::asio::ip;

namespace TgBot {

BoostHttpClient& BoostHttpClient::getInstance() {
	static BoostHttpClient result;
	return result;
}

string BoostHttpClient::makeRequest(const Url& url, const vector<HttpReqArg>& args) const {
	ssl::context context(ssl::context::sslv23);
	context.set_default_verify_paths();

	ssl::stream<tcp::socket> socket(_ioService, context);
	tcp::resolver resolver(_ioService);
	tcp::resolver::query query(url.host, url.protocol);

	connect(socket.lowest_layer(), resolver.resolve(query));

	#ifdef TGBOT_DISABLE_NAGLES_ALGORITHM
	socket.lowest_layer().set_option(tcp::no_delay(true));
	#endif //TGBOT_DISABLE_NAGLES_ALGORITHM

	#ifdef TGBOT_CHANGE_SOCKET_BUFFER_SIZE
	#if _WIN64 || __amd64__ || __x86_64__ || __MINGW64__ || __aarch64__ || __powerpc64__
	socket.lowest_layer().set_option(socket_base::send_buffer_size(65536));
	socket.lowest_layer().set_option(socket_base::receive_buffer_size(65536));
	#else //for 32-bit
	socket.lowest_layer().set_option(socket_base::send_buffer_size(32768));
	socket.lowest_layer().set_option(socket_base::receive_buffer_size(32768));
	#endif //Processor architecture
	#endif //TGBOT_CHANGE_SOCKET_BUFFER_SIZE

	socket.set_verify_mode(ssl::verify_none);
	socket.set_verify_callback(ssl::rfc2818_verification(url.host));
	socket.handshake(ssl::stream<tcp::socket>::client);

	string requestText = HttpParser::getInstance().generateRequest(url, args, false);
	write(socket, buffer(requestText.c_str(), requestText.length()));

	string response;

	#ifdef TGBOT_CHANGE_READ_BUFFER_SIZE
	#if _WIN64 || __amd64__ || __x86_64__ || __MINGW64__ || __aarch64__ || __powerpc64__
	char buff[65536];
	#else //for 32-bit
	char buff[32768];
	#endif //Processor architecture
	#else
	char buff[1024];
	#endif //TGBOT_CHANGE_READ_BUFFER_SIZE

	boost::system::error_code error;
	while (!error) {
		size_t bytes = read(socket, buffer(buff), error);
		response += string(buff, bytes);
	}

	return HttpParser::getInstance().parseResponse(response);
}

#ifdef HAVE_CURL

CurlHttpClient::CurlHttpClient() {
    curlSettings = curl_easy_init();
}

CurlHttpClient::~CurlHttpClient() {
    curl_easy_cleanup(curlSettings);
}

CurlHttpClient& CurlHttpClient::getInstance() {
    static CurlHttpClient result;
    return result;
}

static size_t curl_write_string(char *ptr, size_t size, size_t nmemb, void *userdata)
{
    std::string &s = *(std::string *)userdata;
    auto read = size * nmemb;
    s.append(ptr, ptr + read);
    return read;
};

string CurlHttpClient::makeRequest(const Url& url, const vector<HttpReqArg>& args) const {
    // Copy settings for each call because we change CURLOPT_URL and other stuff.
    // This also protects multithreaded case.
    auto curl = curl_easy_duphandle(curlSettings);

    auto u = url.protocol + "://" + url.host + url.path;
    curl_easy_setopt(curl, CURLOPT_URL, u.c_str());

    // disable keep-alive
    struct curl_slist *headers = NULL;
    headers = curl_slist_append(headers, "Connection: close");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

    std::string data;
    std::vector<char *> escaped;
    if (!args.empty())
    {
        for (auto &a : args)
        {
            escaped.push_back(curl_easy_escape(curl, a.name.c_str(), a.name.size()));
            data += escaped.back() + std::string("=");
            escaped.push_back(curl_easy_escape(curl, a.value.c_str(), a.value.size()));
            data += escaped.back() + std::string("&");
        }
        data.resize(data.size() - 1);
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
        curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)data.size());
    }

    std::string response;
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_string);

    auto res = curl_easy_perform(curl);
    curl_slist_free_all(headers);
    curl_easy_cleanup(curl);

    for (auto &e : escaped)
        curl_free(e);

    if (res != CURLE_OK)
        throw std::runtime_error(std::string("curl error: ") + curl_easy_strerror(res));

    return HttpParser::getInstance().parseResponse(response);
}

#endif

}
<|endoftext|>


<commit_before>/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)

This file is part of Daemon source code.

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

Daemon source code 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 General Public License for more details.

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

#include "../client/client.h"
#include "snd_codec.h"

/*
=================
FGetLittleLong
=================
*/
static int FGetLittleLong( fileHandle_t f )
{
	int		v;

	FS_Read( &v, sizeof( v ), f );

	return LittleLong( v );
}

/*
=================
FGetLittleShort
=================
*/
static short FGetLittleShort( fileHandle_t f )
{
	short	v;

	FS_Read( &v, sizeof( v ), f );

	return LittleShort( v );
}

/*
=================
S_ReadChunkInfo
=================
*/
static int S_ReadChunkInfo( fileHandle_t f, char *name )
{
	int len, r;

	name[4] = 0;

	r = FS_Read( name, 4, f );

	if ( r != 4 )
		return -1;

	len = FGetLittleLong( f );

	if ( len < 0 )
	{
		Com_Printf( S_COLOR_YELLOW "WARNING: Negative chunk length\n" );
		return -1;
	}

	return len;
}

/*
=================
S_FindRIFFChunk

Returns the length of the data in the chunk, or -1 if not found
=================
*/
static int S_FindRIFFChunk( fileHandle_t f, char *chunk )
{
	char	name[5];
	int		len;

	while ( ( len = S_ReadChunkInfo( f, name ) ) >= 0 )
	{
		// If this is the right chunk, return
		if ( !Q_strncmp( name, chunk, 4 ) )
			return len;

		len = PAD( len, 2 );

		// Not the right chunk - skip it
		FS_Seek( f, len, FS_SEEK_CUR );
	}

	return -1;
}

/*
=================
S_ByteSwapRawSamples
=================
*/
static void S_ByteSwapRawSamples( int samples, int width, int s_channels, const byte *data )
{
	int		i;

	if ( width != 2 )
	{
		return;
	}

	if ( LittleShort( 256 ) == 256 )
	{
		return;
	}

	if ( s_channels == 2 )
	{
		samples <<= 1;
	}

	for ( i = 0 ; i < samples ; i++ )
	{
		( ( short * )data )[i] = LittleShort( ( ( short * )data )[i] );
	}
}

/*
=================
S_ReadRIFFHeader
=================
*/
static qboolean S_ReadRIFFHeader( fileHandle_t file, snd_info_t *info )
{
	char dump[16];
	int bits;
	int fmtlen = 0;

	// skip the riff wav header
	FS_Read( dump, 12, file );

	// Scan for the format chunk
	if ( ( fmtlen = S_FindRIFFChunk( file, "fmt " ) ) < 0 )
	{
		Com_Printf( S_COLOR_RED "ERROR: Couldn't find \"fmt\" chunk\n" );
		return qfalse;
	}

	// Save the parameters
	FGetLittleShort( file ); // wav_format
	info->channels = FGetLittleShort( file );
	info->rate = FGetLittleLong( file );
	FGetLittleLong( file );
	FGetLittleShort( file );
	bits = FGetLittleShort( file );

	if ( bits < 8 )
	{
		Com_Printf( S_COLOR_RED "ERROR: Less than 8 bit sound is not supported\n" );
		return qfalse;
	}

	info->width = bits / 8;
	info->dataofs = 0;

	// Skip the rest of the format chunk if required
	if ( fmtlen > 16 )
	{
		fmtlen -= 16;
		FS_Seek( file, fmtlen, FS_SEEK_CUR );
	}

	// Scan for the data chunk
	if ( ( info->size = S_FindRIFFChunk( file, "data" ) ) < 0 )
	{
		Com_Printf( S_COLOR_RED "ERROR: Couldn't find \"data\" chunk\n" );
		return qfalse;
	}

	info->samples = ( info->size / info->width ) / info->channels;

	return qtrue;
}

// WAV codec
snd_codec_t wav_codec =
{
	"wav",
	S_WAV_CodecLoad,
	S_WAV_CodecOpenStream,
	S_WAV_CodecReadStream,
	S_WAV_CodecCloseStream,
	NULL
};

/*
=================
S_WAV_CodecLoad
=================
*/
void *S_WAV_CodecLoad( const char *filename, snd_info_t *info )
{
	fileHandle_t file;
	void *buffer;

	// Try to open the file
	FS_FOpenFileRead( filename, &file, qtrue );

	if ( !file )
	{
		return NULL;
	}

	// Read the RIFF header
	if ( !S_ReadRIFFHeader( file, info ) )
	{
		FS_FCloseFile( file );
		Com_Printf( S_COLOR_RED "ERROR: Incorrect/unsupported format in \"%s\"\n",
		            filename );
		return NULL;
	}

	// Allocate some memory
	buffer = Hunk_AllocateTempMemory( info->size );

	if ( !buffer )
	{
		FS_FCloseFile( file );
		Com_Printf( S_COLOR_RED "ERROR: Out of memory reading \"%s\"\n",
		            filename );
		return NULL;
	}

	// Read, byteswap
	FS_Read( buffer, info->size, file );
	S_ByteSwapRawSamples( info->samples, info->width, info->channels, ( byte * )buffer );

	// Close and return
	FS_FCloseFile( file );
	return buffer;
}

/*
=================
S_WAV_CodecOpenStream
=================
*/
snd_stream_t *S_WAV_CodecOpenStream( const char *filename )
{
	snd_stream_t *rv;

	// Open
	rv = S_CodecUtilOpen( filename, &wav_codec );

	if ( !rv )
		return NULL;

	// Read the RIFF header
	if ( !S_ReadRIFFHeader( rv->file, &rv->info ) )
	{
		S_CodecUtilClose( &rv );
		return NULL;
	}

	return rv;
}

/*
=================
S_WAV_CodecCloseStream
=================
*/
void S_WAV_CodecCloseStream( snd_stream_t *stream )
{
	S_CodecUtilClose( &stream );
}

/*
=================
S_WAV_CodecReadStream
=================
*/
int S_WAV_CodecReadStream( snd_stream_t *stream, int bytes, void *buffer )
{
	int remaining = stream->info.size - stream->pos;
	int samples;

	if ( remaining <= 0 )
		return 0;

	if ( bytes > remaining )
		bytes = remaining;

	stream->pos += bytes;
	samples = ( bytes / stream->info.width ) / stream->info.channels;
	FS_Read( buffer, bytes, stream->file );
	S_ByteSwapRawSamples( samples, stream->info.width, stream->info.channels, (byte*) buffer );
	return bytes;
}
<commit_msg>Don't trust the reported data chunk size in WAV files.<commit_after>/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)

This file is part of Daemon source code.

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

Daemon source code 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 General Public License for more details.

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

#include "../client/client.h"
#include "snd_codec.h"

/*
=================
FGetLittleLong
=================
*/
static int FGetLittleLong( fileHandle_t f )
{
	int		v;

	FS_Read( &v, sizeof( v ), f );

	return LittleLong( v );
}

/*
=================
FGetLittleShort
=================
*/
static short FGetLittleShort( fileHandle_t f )
{
	short	v;

	FS_Read( &v, sizeof( v ), f );

	return LittleShort( v );
}

/*
=================
S_ReadChunkInfo
=================
*/
static int S_ReadChunkInfo( fileHandle_t f, char *name )
{
	int len, r;

	name[4] = 0;

	r = FS_Read( name, 4, f );

	if ( r != 4 )
		return -1;

	len = FGetLittleLong( f );

	if ( len < 0 )
	{
		Com_Printf( S_COLOR_YELLOW "WARNING: Negative chunk length\n" );
		return -1;
	}

	return len;
}

/*
=================
S_FindRIFFChunk

Returns the length of the data in the chunk, or -1 if not found
=================
*/
static int S_FindRIFFChunk( fileHandle_t f, char *chunk )
{
	char	name[5];
	int		len;

	while ( ( len = S_ReadChunkInfo( f, name ) ) >= 0 )
	{
		// If this is the right chunk, return
		if ( !Q_strncmp( name, chunk, 4 ) )
			return len;

		len = PAD( len, 2 );

		// Not the right chunk - skip it
		FS_Seek( f, len, FS_SEEK_CUR );
	}

	return -1;
}

/*
=================
S_ByteSwapRawSamples
=================
*/
static void S_ByteSwapRawSamples( int samples, int width, int s_channels, const byte *data )
{
	int		i;

	if ( width != 2 )
	{
		return;
	}

	if ( LittleShort( 256 ) == 256 )
	{
		return;
	}

	if ( s_channels == 2 )
	{
		samples <<= 1;
	}

	for ( i = 0 ; i < samples ; i++ )
	{
		( ( short * )data )[i] = LittleShort( ( ( short * )data )[i] );
	}
}

/*
=================
S_ReadRIFFHeader
=================
*/
static qboolean S_ReadRIFFHeader( fileHandle_t file, snd_info_t *info )
{
	char dump[16];
	int bits;
	int fmtlen = 0;

	// skip the riff wav header
	FS_Read( dump, 12, file );

	// Scan for the format chunk
	if ( ( fmtlen = S_FindRIFFChunk( file, "fmt " ) ) < 0 )
	{
		Com_Printf( S_COLOR_RED "ERROR: Couldn't find \"fmt\" chunk\n" );
		return qfalse;
	}

	// Save the parameters
	FGetLittleShort( file ); // wav_format
	info->channels = FGetLittleShort( file );
	info->rate = FGetLittleLong( file );
	FGetLittleLong( file );
	FGetLittleShort( file );
	bits = FGetLittleShort( file );

	if ( bits < 8 )
	{
		Com_Printf( S_COLOR_RED "ERROR: Less than 8 bit sound is not supported\n" );
		return qfalse;
	}

	info->width = bits / 8;
	info->dataofs = 0;

	// Skip the rest of the format chunk if required
	if ( fmtlen > 16 )
	{
		fmtlen -= 16;
		FS_Seek( file, fmtlen, FS_SEEK_CUR );
	}

	// Scan for the data chunk
	if ( ( info->size = S_FindRIFFChunk( file, "data" ) ) < 0 )
	{
		Com_Printf( S_COLOR_RED "ERROR: Couldn't find \"data\" chunk\n" );
		return qfalse;
	}

	// Arbitrary size cutoff. 4MB gives 95s of audio (22050Hz 16b mono)
	if ( info->size > 4 * 1024 * 1024)
	{
		Com_Printf( S_COLOR_YELLOW "WARNING: Large sample – truncating\n" );
		info->size = 4 * 1024 * 1024;
	}

	info->samples = ( info->size / info->width ) / info->channels;

	return qtrue;
}

// WAV codec
snd_codec_t wav_codec =
{
	"wav",
	S_WAV_CodecLoad,
	S_WAV_CodecOpenStream,
	S_WAV_CodecReadStream,
	S_WAV_CodecCloseStream,
	NULL
};

/*
=================
S_WAV_CodecLoad
=================
*/
void *S_WAV_CodecLoad( const char *filename, snd_info_t *info )
{
	fileHandle_t file;
	void *buffer;

	// Try to open the file
	FS_FOpenFileRead( filename, &file, qtrue );

	if ( !file )
	{
		return NULL;
	}

	// Read the RIFF header
	if ( !S_ReadRIFFHeader( file, info ) )
	{
		FS_FCloseFile( file );
		Com_Printf( S_COLOR_RED "ERROR: Incorrect/unsupported format in \"%s\"\n",
		            filename );
		return NULL;
	}

	// Allocate some memory
	buffer = Hunk_AllocateTempMemory( info->size );

	if ( !buffer )
	{
		FS_FCloseFile( file );
		Com_Printf( S_COLOR_RED "ERROR: Out of memory reading \"%s\"\n",
		            filename );
		return NULL;
	}

	// Read, byteswap
	FS_Read( buffer, info->size, file );
	S_ByteSwapRawSamples( info->samples, info->width, info->channels, ( byte * )buffer );

	// Close and return
	FS_FCloseFile( file );
	return buffer;
}

/*
=================
S_WAV_CodecOpenStream
=================
*/
snd_stream_t *S_WAV_CodecOpenStream( const char *filename )
{
	snd_stream_t *rv;

	// Open
	rv = S_CodecUtilOpen( filename, &wav_codec );

	if ( !rv )
		return NULL;

	// Read the RIFF header
	if ( !S_ReadRIFFHeader( rv->file, &rv->info ) )
	{
		S_CodecUtilClose( &rv );
		return NULL;
	}

	return rv;
}

/*
=================
S_WAV_CodecCloseStream
=================
*/
void S_WAV_CodecCloseStream( snd_stream_t *stream )
{
	S_CodecUtilClose( &stream );
}

/*
=================
S_WAV_CodecReadStream
=================
*/
int S_WAV_CodecReadStream( snd_stream_t *stream, int bytes, void *buffer )
{
	int remaining = stream->info.size - stream->pos;
	int samples;

	if ( remaining <= 0 )
		return 0;

	if ( bytes > remaining )
		bytes = remaining;

	stream->pos += bytes;
	samples = ( bytes / stream->info.width ) / stream->info.channels;
	FS_Read( buffer, bytes, stream->file );
	S_ByteSwapRawSamples( samples, stream->info.width, stream->info.channels, (byte*) buffer );
	return bytes;
}
<|endoftext|>


<commit_before>#include "client.h"
#include "util/keyboard.h"
#include "init.h"
#include "globals.h"
#include "util/funcs.h"
#include "util/font.h"
#include <string>

using namespace std;

namespace Network{

void drawBox( const Bitmap & area, const Bitmap & copy, const string & str, const Font & font, bool hasFocus ){
	copy.Blit( area );
	area.drawingMode( Bitmap::MODE_TRANS );
	area.rectangleFill( 0, 0, area.getWidth(), area.getHeight(), Bitmap::makeColor( 0, 0, 0 ) );
	area.drawingMode( Bitmap::MODE_SOLID );
	int color = Bitmap::makeColor( 255, 255, 255 );
	if ( hasFocus ){
		color = Bitmap::makeColor( 255, 255, 0 );
	}
	area.rectangle( 0, 0, area.getWidth() - 1, area.getHeight() - 1, color );
	font.printf( 1, 0, Bitmap::makeColor( 255, 255, 255 ), area, str, 0 );
}

void networkClient(){
	Global::showTitleScreen();
	Global::speed_counter = 0;
	Keyboard keyboard;
	keyboard.setAllDelay( 200 );

	string host = "localhost";
	string port = "127.0.0.1";

	enum Focus{
		HOST, PORT, CONNECT, BACK
	};

	const Font & font = Font::getFont( Util::getDataPath() + Global::DEFAULT_FONT, 20, 20 );

	font.printf( 20, 100 - font.getHeight() - 1, Bitmap::makeColor( 255, 255, 255 ), *Bitmap::Screen, "Host", 0 );
	Bitmap hostBox( *Bitmap::Screen, 20, 100, 200, font.getHeight() );
	Bitmap copyHostBox( hostBox.getWidth(), hostBox.getHeight() );
	hostBox.Blit( copyHostBox );

	font.printf( 20, 100 + font.getHeight() * 2 - font.getHeight() - 1, Bitmap::makeColor( 255, 255, 255 ), *Bitmap::Screen, "Port", 0 );
	Bitmap portBox( *Bitmap::Screen, 20, 100 + font.getHeight() * 2, 200, font.getHeight() );
	Bitmap copyPortBox( portBox.getWidth(), portBox.getHeight() );
	portBox.Blit( copyPortBox );

	font.printf( 20, 20, Bitmap::makeColor( 255, 255, 255 ), *Bitmap::Screen, "Press TAB to cycle the next input", 0 );

	Focus focus = HOST;

	bool done = false;
	bool draw = true;
	while ( ! done ){
		int think = Global::speed_counter;
		while ( think > 0 ){
			think -= 1;
			Global::speed_counter = 0;
			keyboard.poll();

			if ( keyboard[ Keyboard::Key_TAB ] ){
				draw = true;
				switch ( focus ){
					case HOST : focus = PORT; break;
					case PORT : focus = CONNECT; break;
					case CONNECT : focus = BACK; break;
					case BACK : focus = HOST; break;
					default : focus = HOST;
				}
			}

			if ( keyboard[ Keyboard::Key_ESC ] ){
				done = true;
			}

			if ( keyboard[ Keyboard::Key_ENTER ] ){
				if ( focus == BACK ){
					done = true;
				}
			}
		}

		if ( draw ){
			draw = false;
			int focusColor = Bitmap::makeColor( 255, 255, 0 );
			int unFocusColor = Bitmap::makeColor( 255, 255, 255 );

			drawBox( hostBox, copyHostBox, host, font, focus == HOST );
			drawBox( portBox, copyPortBox, port, font, focus == PORT );
			font.printf( 20, 100 + font.getHeight() * 5, focus == CONNECT ? focusColor : unFocusColor, *Bitmap::Screen, "Connect", 0 );
			font.printf( 20, 100 + font.getHeight() * 6 + 5, focus == BACK ? focusColor : unFocusColor, *Bitmap::Screen, "Back", 0 );
		}

		while ( Global::speed_counter == 0 ){
			Util::rest( 1 );
			keyboard.poll();
		}
	}
}

}
<commit_msg>handle keyboard input<commit_after>#include "client.h"
#include "util/keyboard.h"
#include "init.h"
#include "globals.h"
#include "util/funcs.h"
#include "util/font.h"
#include <string>

using namespace std;

namespace Network{

static void drawBox( const Bitmap & area, const Bitmap & copy, const string & str, const Font & font, bool hasFocus ){
	copy.Blit( area );
	area.drawingMode( Bitmap::MODE_TRANS );
	area.rectangleFill( 0, 0, area.getWidth(), area.getHeight(), Bitmap::makeColor( 0, 0, 0 ) );
	area.drawingMode( Bitmap::MODE_SOLID );
	int color = Bitmap::makeColor( 255, 255, 255 );
	if ( hasFocus ){
		color = Bitmap::makeColor( 255, 255, 0 );
	}
	area.rectangle( 0, 0, area.getWidth() - 1, area.getHeight() - 1, color );
	font.printf( 1, 0, Bitmap::makeColor( 255, 255, 255 ), area, str, 0 );
}

static char lowerCase( const char * x ){
	if ( x[0] >= 'A' && x[0] <= 'Z' ){
		return x[0] - 'A' + 'a';
	}
	return x[0];
}

static void handleHostInput( string & str, const vector< int > & keys ){
	for ( vector< int >::const_iterator it = keys.begin(); it != keys.end(); it++ ){
		const int & key = *it;
		if ( Keyboard::isAlpha( key ) || key == Keyboard::Key_STOP ){
			str += lowerCase( Keyboard::keyToName( key ) );
		} else if ( key == Keyboard::Key_BACKSPACE ){
			if ( str != "" ){
				str = str.substr( 0, str.length() - 1 );
			}
		}
	}
}

static void handlePortInput( string & str, const vector< int > & keys ){
	for ( vector< int >::const_iterator it = keys.begin(); it != keys.end(); it++ ){
		const int & key = *it;
		if ( Keyboard::isNumber( key ) || key == Keyboard::Key_STOP ){
			str += Keyboard::keyToName( key );
		} else if ( key == Keyboard::Key_BACKSPACE ){
			if ( str != "" ){
				str = str.substr( 0, str.length() - 1 );
			}
		}
	}
}

void networkClient(){
	Global::showTitleScreen();
	Global::speed_counter = 0;
	Keyboard keyboard;
	keyboard.setAllDelay( 200 );

	string host = "localhost";
	string port = "7887";

	enum Focus{
		HOST, PORT, CONNECT, BACK
	};

	const Font & font = Font::getFont( Util::getDataPath() + Global::DEFAULT_FONT, 20, 20 );
	const int inputBoxLength = font.textLength( "a" ) * 30;

	font.printf( 20, 100 - font.getHeight() - 1, Bitmap::makeColor( 255, 255, 255 ), *Bitmap::Screen, "Host", 0 );
	Bitmap hostBox( *Bitmap::Screen, 20, 100, inputBoxLength, font.getHeight() );
	Bitmap copyHostBox( hostBox.getWidth(), hostBox.getHeight() );
	hostBox.Blit( copyHostBox );

	font.printf( 20, 100 + font.getHeight() * 2 - font.getHeight() - 1, Bitmap::makeColor( 255, 255, 255 ), *Bitmap::Screen, "Port", 0 );
	Bitmap portBox( *Bitmap::Screen, 20, 100 + font.getHeight() * 2, inputBoxLength, font.getHeight() );
	Bitmap copyPortBox( portBox.getWidth(), portBox.getHeight() );
	portBox.Blit( copyPortBox );

	font.printf( 20, 20, Bitmap::makeColor( 255, 255, 255 ), *Bitmap::Screen, "Press TAB to cycle the next input", 0 );

	Focus focus = HOST;

	bool done = false;
	bool draw = true;
	while ( ! done ){
		int think = Global::speed_counter;
		while ( think > 0 ){
			think -= 1;
			Global::speed_counter = 0;
			keyboard.poll();

			if ( keyboard[ Keyboard::Key_TAB ] ){
				draw = true;
				switch ( focus ){
					case HOST : focus = PORT; break;
					case PORT : focus = CONNECT; break;
					case CONNECT : focus = BACK; break;
					case BACK : focus = HOST; break;
					default : focus = HOST;
				}
			}

			if ( keyboard[ Keyboard::Key_ESC ] ){
				done = true;
			}

			if ( keyboard[ Keyboard::Key_ENTER ] ){
				if ( focus == BACK ){
					done = true;
				}
			}

			vector< int > keys;
			keyboard.readKeys( keys );
			switch ( focus ){
				case HOST : {
					draw = true;
					handleHostInput( host, keys );
					break;
				}
				case PORT : {
					draw = true;
					handlePortInput( port, keys );
					break;
				}
				default : {
					break;
				}
			}
		}

		if ( draw ){
			draw = false;
			int focusColor = Bitmap::makeColor( 255, 255, 0 );
			int unFocusColor = Bitmap::makeColor( 255, 255, 255 );

			drawBox( hostBox, copyHostBox, host, font, focus == HOST );
			drawBox( portBox, copyPortBox, port, font, focus == PORT );
			font.printf( 20, 100 + font.getHeight() * 5, focus == CONNECT ? focusColor : unFocusColor, *Bitmap::Screen, "Connect", 0 );
			font.printf( 20, 100 + font.getHeight() * 6 + 5, focus == BACK ? focusColor : unFocusColor, *Bitmap::Screen, "Back", 0 );
		}

		while ( Global::speed_counter == 0 ){
			Util::rest( 1 );
			keyboard.poll();
		}
	}
}

}
<|endoftext|>


<commit_before>#ifndef _GUARD_TEST_BASE_PYTHON_HPP_
#define _GUARD_TEST_BASE_PYTHON_HPP_

#include "bpmodule/modulebase/Test_Base.hpp"

#include <boost/python.hpp>

namespace bpmodule {
namespace modulebase {
namespace export_python {

class Test_Base_Wrap : public Test_Base, public boost::python::wrapper<Test_Base>
{
    public:
        Test_Base_Wrap(unsigned long id,
                       modulestore::ModuleStore & mstore,
                       const modulestore::ModuleInfo & minfo)
            : Test_Base(id, mstore, minfo)
        {}

        // expose protected member functions
        void ThrowException(const std::string & exwhat,
                            const boost::python::list & exinfo = boost::python::list())
        {
            ModuleBase::ThrowException(exwhat, PythonListToPairVec(exinfo));
        }

        modulestore::ModuleStore & MStore(void)
        {
            return ModuleBase::MStore();
        }

        // Provide overrides for protected member functions
        virtual void RunTest(void)
        {
            this->get_override("RunTest")();
        }

        virtual void CallRunTest(const std::string & other)
        {
            this->get_override("RunCallTest")(other);
        }

        virtual void Throw(void)
        {
            this->get_override("Throw")();
        }

        virtual void CallThrow(const std::string & other)
        {
            this->get_override("CallThrow")(other);
        }

        virtual datastore::CalcData CalcTest(datastore::CalcData inputs)
        {
            return this->get_override("CalcData")(inputs);
        }

    private:
        static exception::GeneralException::ExceptionInfo
        PythonListToPairVec(const boost::python::list & exinfo)
        {
            int length = boost::python::extract<int>(exinfo.attr("__len__")());
            exception::GeneralException::ExceptionInfo inf;
            inf.reserve(length);

            for (int i = 0; i < length; i++)
                inf.push_back({
                                boost::python::extract<std::string>(exinfo[i][0]),
                                boost::python::extract<std::string>(exinfo[i][1]),
                              });

            return inf;
        }

};

} // close namespace export_python
} // close namespace modulebase
} // close namespace bpmodule

#endif
<commit_msg>Fix function name in CalcTest<commit_after>#ifndef _GUARD_TEST_BASE_PYTHON_HPP_
#define _GUARD_TEST_BASE_PYTHON_HPP_

#include "bpmodule/modulebase/Test_Base.hpp"

#include <boost/python.hpp>

namespace bpmodule {
namespace modulebase {
namespace export_python {

class Test_Base_Wrap : public Test_Base, public boost::python::wrapper<Test_Base>
{
    public:
        Test_Base_Wrap(unsigned long id,
                       modulestore::ModuleStore & mstore,
                       const modulestore::ModuleInfo & minfo)
            : Test_Base(id, mstore, minfo)
        {}

        // expose protected member functions
        void ThrowException(const std::string & exwhat,
                            const boost::python::list & exinfo = boost::python::list())
        {
            ModuleBase::ThrowException(exwhat, PythonListToPairVec(exinfo));
        }

        modulestore::ModuleStore & MStore(void)
        {
            return ModuleBase::MStore();
        }

        // Provide overrides for protected member functions
        virtual void RunTest(void)
        {
            this->get_override("RunTest")();
        }

        virtual void CallRunTest(const std::string & other)
        {
            this->get_override("RunCallTest")(other);
        }

        virtual void Throw(void)
        {
            this->get_override("Throw")();
        }

        virtual void CallThrow(const std::string & other)
        {
            this->get_override("CallThrow")(other);
        }

        virtual datastore::CalcData CalcTest(datastore::CalcData inputs)
        {
            return this->get_override("CalcTest")(inputs);
        }

    private:
        static exception::GeneralException::ExceptionInfo
        PythonListToPairVec(const boost::python::list & exinfo)
        {
            int length = boost::python::extract<int>(exinfo.attr("__len__")());
            exception::GeneralException::ExceptionInfo inf;
            inf.reserve(length);

            for (int i = 0; i < length; i++)
                inf.push_back({
                                boost::python::extract<std::string>(exinfo[i][0]),
                                boost::python::extract<std::string>(exinfo[i][1]),
                              });

            return inf;
        }

};

} // close namespace export_python
} // close namespace modulebase
} // close namespace bpmodule

#endif
<|endoftext|>


<commit_before>/*! \file
 *
 * \brief Main module database class (source)
 * \author Benjamin Pritchard (ben@bennyp.org)
 */

#include "bpmodule/modulemanager/ModuleManager.hpp"
#include "bpmodule/output/Output.hpp"
#include "bpmodule/modulebase/ModuleBase.hpp"
#include "bpmodule/exception/Exceptions.hpp"
#include "bpmodule/datastore/Wavefunction.hpp"
#include "bpmodule/output/GlobalOutput.hpp"

////////////////////////
// Supermodule Handlers
////////////////////////
#include "bpmodule/modulemanager/CppSupermoduleLoader.hpp"
#include "bpmodule/modulemanager/PySupermoduleLoader.hpp"

using bpmodule::datastore::Wavefunction;
using bpmodule::modulebase::ModuleBase;
using bpmodule::exception::ModuleLoadException;
using bpmodule::exception::ModuleManagerException;
using bpmodule::exception::GeneralException;

namespace bpmodule {
namespace modulemanager {

ModuleManager::ModuleManager()
    : debugall_(false),
      curid_(100)
{
    // add the handlers
    loadhandlers_.emplace("c_module", std::unique_ptr<SupermoduleLoaderBase>(new CppSupermoduleLoader()));
    loadhandlers_.emplace("python_module", std::unique_ptr<SupermoduleLoaderBase>(new PySupermoduleLoader()));
}

ModuleManager::~ModuleManager()
{
    /*
     * Delete any in-use modules
     */
    auto ninuse = modules_inuse_.size();
    if(ninuse)
        output::GlobalWarning("ModuleManager is destructing with %? modules in use\n", ninuse);
    else
        output::GlobalSuccess("ModuleManager has no modules in use\n");

    /*
       WARNING WARNING WARNING WARNING WARNING
       Clearing the cache and store MUST be done BEFORE unloading
       the modules or else deleting elements will cause a segfault.
       Reason: The GenericHolder is a template, so the code for
               the destructors exists in the modules
    */
    cachemap_.clear();
    store_.clear();

    /*
     * The tree contains System, so that must be cleared before unloading
     *  as well
     */
    mtree_.Clear();

    // NOW we can close all the handlers
    loadhandlers_.clear();
}

size_t ModuleManager::Size(void) const noexcept
{
    return store_.size();
}

bool ModuleManager::HasKey(const std::string & modulekey) const
{
    return store_.count(modulekey);
}

ModuleInfo ModuleManager::ModuleKeyInfo(const std::string & modulekey) const
{
    return GetOrThrow_(modulekey).mi;
}

void ModuleManager::DuplicateKey(const std::string & modulekey, const std::string newkey)
{
    store_.emplace(newkey, GetOrThrow_(modulekey));
}

void ModuleManager::Print(std::ostream & os) const
{
    for(const auto & it : store_)
        it.second.mi.Print(os);
}

void ModuleManager::TestAll(void)
{
    //! \todo needs rewriting and cleanup
    output::GlobalDebug("Testing all modules\n");
    for(const auto & it : store_)
    {
        output::GlobalDebug("Testing %? (%?)...\n", it.first, it.second.mi.name);

        if(!it.second.mi.options.AllReqSet())
        {
            output::GlobalError("Error - module %? [key %?]\" failed options test - required options are missing", it.second.mi.name, it.first);

            auto missingreq = it.second.mi.options.AllMissingReq();
            for(const auto & optit : missingreq)
                output::GlobalError("    Missing \"%?\"\n", optit);
        }

        output::GlobalDebug("Test of %? OK\n", it.first);
    }

    output::GlobalDebug("Testing getting of modules\n");
    for(const auto & it : store_)
    {
        try {
            GetModule<ModuleBase>(it.first, 0);
        }
        catch(std::exception & ex)
        {
            output::GlobalError("Error - module %? [key %?]\" failed test loading!\n", it.second.mi.name, it.first);
            throw GeneralException(ex, "location", "TestAll");
        }
    }

    output::GlobalDebug("Testing done!\n");
}

ModuleManager::StoreEntry & ModuleManager::GetOrThrow_(const std::string & modulekey)
{
    if(HasKey(modulekey))
        return store_.at(modulekey);
    else
        throw ModuleManagerException("Missing module key in ModuleManager", "modulekey", modulekey);
}

const ModuleManager::StoreEntry & ModuleManager::GetOrThrow_(const std::string & modulekey) const
{
    if(HasKey(modulekey))
        return store_.at(modulekey);
    else
        throw ModuleManagerException("Missing module key in ModuleManager", "modulekey", modulekey);
}

void ModuleManager::EnableDebug(const std::string & modulekey, bool debug)
{
    if(debug)
        keydebug_.insert(modulekey);
    else
        keydebug_.erase(modulekey); // ok if it doesn't exist
}

void ModuleManager::EnableDebugAll(bool debug) noexcept
{
    debugall_ = debug;
}

ModuleTree::const_iterator ModuleManager::TreeBegin(ID_t startid) const
{
    return mtree_.Begin(startid);
}

ModuleTree::const_iterator ModuleManager::TreeEnd(void) const
{
    return mtree_.End();
}

ModuleTree::const_flat_iterator ModuleManager::FlatTreeBegin(void) const
{
    return mtree_.FlatBegin();
}

ModuleTree::const_flat_iterator ModuleManager::FlatTreeEnd(void) const
{
    return mtree_.FlatEnd();
}

/////////////////////////////////////////
// Module Loading
/////////////////////////////////////////
void ModuleManager::LoadModuleFromModuleInfo(const ModuleInfo & minfo, const std::string & modulekey)
{
    // path set in the module info?
    if(minfo.path.size() == 0)
        throw ModuleLoadException("Cannot load module: Empty path",
                                  "modulepath", minfo.path, "modulename", minfo.name);

    // check for duplicates
    if(store_.count(minfo.name))
        throw ModuleLoadException("Cannot load module: duplicate module name",
                                  "modulepath", minfo.path, "modulename", minfo.name);

    // Using the handler, load the module
    if(!loadhandlers_.count(minfo.type))
        throw ModuleLoadException("Cannot load module: unknown module type",
                                  "modulepath", minfo.path, "modulename", minfo.name, "type", minfo.type);

    // may throw an exception. Exception should be a ModuleLoadException
    const ModuleCreationFuncs & mcf = loadhandlers_.at(minfo.type)->LoadSupermodule(minfo.path);

    // See if this supermodule actually create a module with this name
    if(!mcf.HasCreator(minfo.name))
        throw ModuleLoadException("Creators from this supermodule cannot create a module with this name",
                                  "path", minfo.path, "modulename", minfo.name);

    // add to store with the given module name
    store_.emplace(modulekey, StoreEntry{minfo, mcf.GetCreator(minfo.name)});
}

bool ModuleManager::ModuleInUse(ID_t id) const
{
    return modules_inuse_.count(id);
}

void ModuleManager::DestructionNotify(ID_t id) noexcept
{
   // comparison object doesn't throw, therefore this shouldn't throw
   modules_inuse_.erase(id);
}

/////////////////////////////////////////
// Module Creation
/////////////////////////////////////////
std::unique_ptr<detail::ModuleIMPLHolder>
ModuleManager::CreateModule_(const std::string & modulekey, ID_t parentid)
{
    // obtain the information for this key
    const StoreEntry & se = GetOrThrow_(modulekey);

    // actually create the module
    std::unique_ptr<detail::ModuleIMPLHolder> umbptr;

    try {
      // calls the creation function within the loaded supermodule
      umbptr = std::unique_ptr<detail::ModuleIMPLHolder>(se.mc(curid_));
    }
    catch(const std::exception & ex)
    {
        throw exception::ModuleCreateException(ex,
                                               "path", se.mi.path,
                                               "modulekey", modulekey,
                                               "modulename", se.mi.name);
    }

    if(!umbptr)
        throw exception::ModuleCreateException("Module function returned a null pointer",
                                               "path", se.mi.path,
                                               "modulekey", modulekey,
                                               "modulename", se.mi.name);

    // add the moduleinfo to the tree
    ModuleTreeNode me{modulekey,      // key
                      se.mi,          // module info
                      std::string(),  // output
                      curid_,         // module id
                      Wavefunction(), // initial wfn
                      Wavefunction()  // final wfn
                     };

    // If there is a parent, get its wavefunction and use that
    if(parentid != 0)
    {
        if(!mtree_.HasID(parentid))
            throw exception::ModuleCreateException("Parent does not exit on map", "parentid", parentid);

        const ModuleTreeNode & parent = mtree_.GetByID(parentid);
        me.initial_wfn = parent.initial_wfn;
        me.final_wfn = parent.initial_wfn;
    }

    // move the data to the tree
    // "me" should not be accessed after this
    mtree_.Insert(std::move(me), parentid);

    // set the info for the module
    // (set via C++ functions)
    ModuleBase * p = umbptr->CppPtr();
    p->SetMManager_(this);
    p->SetTreeNode_(&(mtree_.GetByID(curid_))); // also sets up output tee

    // Debugging enabled for this module?
    if(debugall_ || keydebug_.count(modulekey))
        p->EnableDebug(true);

    // get this module's cache
    // don't use .at() -- we need it created if it doesn't exist already
    std::string mbstr = p->Name() + "_v" + p->Version();
    p->SetCache_(&(cachemap_[mbstr]));

    // mark the module as inuse
    modules_inuse_.insert(curid_);

    // next id
    curid_++;

    return std::move(umbptr);
}

////////////////////
// Python
////////////////////
pybind11::object ModuleManager::GetModulePy(const std::string & modulekey,
                                            ID_t parentid)
{
    std::unique_ptr<detail::ModuleIMPLHolder> umbptr = CreateModule_(modulekey, parentid);

    // we use a pointer so that the python object
    // can take ownership and we can avoid having
    // a copy constructor for PyModulePtr

    return python::ConvertToPy(new PyModulePtr(std::move(umbptr)), pybind11::return_value_policy::take_ownership);
}

void ModuleManager::ChangeOptionPy(const std::string & modulekey, const std::string & optkey, const pybind11::object & value)
{
    GetOrThrow_(modulekey).mi.options.ChangePy(optkey, value);
}

} // close namespace modulemanager
} // close namespace bpmodule
<commit_msg>Check for existing key when duplicating keys<commit_after>/*! \file
 *
 * \brief Main module database class (source)
 * \author Benjamin Pritchard (ben@bennyp.org)
 */

#include "bpmodule/modulemanager/ModuleManager.hpp"
#include "bpmodule/output/Output.hpp"
#include "bpmodule/modulebase/ModuleBase.hpp"
#include "bpmodule/exception/Exceptions.hpp"
#include "bpmodule/datastore/Wavefunction.hpp"
#include "bpmodule/output/GlobalOutput.hpp"

////////////////////////
// Supermodule Handlers
////////////////////////
#include "bpmodule/modulemanager/CppSupermoduleLoader.hpp"
#include "bpmodule/modulemanager/PySupermoduleLoader.hpp"

using bpmodule::datastore::Wavefunction;
using bpmodule::modulebase::ModuleBase;
using bpmodule::exception::ModuleLoadException;
using bpmodule::exception::ModuleManagerException;
using bpmodule::exception::GeneralException;

namespace bpmodule {
namespace modulemanager {

ModuleManager::ModuleManager()
    : debugall_(false),
      curid_(100)
{
    // add the handlers
    loadhandlers_.emplace("c_module", std::unique_ptr<SupermoduleLoaderBase>(new CppSupermoduleLoader()));
    loadhandlers_.emplace("python_module", std::unique_ptr<SupermoduleLoaderBase>(new PySupermoduleLoader()));
}

ModuleManager::~ModuleManager()
{
    /*
     * Delete any in-use modules
     */
    auto ninuse = modules_inuse_.size();
    if(ninuse)
        output::GlobalWarning("ModuleManager is destructing with %? modules in use\n", ninuse);
    else
        output::GlobalSuccess("ModuleManager has no modules in use\n");

    /*
       WARNING WARNING WARNING WARNING WARNING
       Clearing the cache and store MUST be done BEFORE unloading
       the modules or else deleting elements will cause a segfault.
       Reason: The GenericHolder is a template, so the code for
               the destructors exists in the modules
    */
    cachemap_.clear();
    store_.clear();

    /*
     * The tree contains System, so that must be cleared before unloading
     *  as well
     */
    mtree_.Clear();

    // NOW we can close all the handlers
    loadhandlers_.clear();
}

size_t ModuleManager::Size(void) const noexcept
{
    return store_.size();
}

bool ModuleManager::HasKey(const std::string & modulekey) const
{
    return store_.count(modulekey);
}

ModuleInfo ModuleManager::ModuleKeyInfo(const std::string & modulekey) const
{
    return GetOrThrow_(modulekey).mi;
}

void ModuleManager::DuplicateKey(const std::string & modulekey, const std::string newkey)
{
    if(HasKey(newkey))
        throw ModuleLoadException("Cannot duplicate key: new key already exists",
                                  "modulekey", modulekey, "newkey", newkey);

    store_.emplace(newkey, GetOrThrow_(modulekey));
}

void ModuleManager::Print(std::ostream & os) const
{
    for(const auto & it : store_)
        it.second.mi.Print(os);
}

void ModuleManager::TestAll(void)
{
    //! \todo needs rewriting and cleanup
    output::GlobalDebug("Testing all modules\n");
    for(const auto & it : store_)
    {
        output::GlobalDebug("Testing %? (%?)...\n", it.first, it.second.mi.name);

        if(!it.second.mi.options.AllReqSet())
        {
            output::GlobalError("Error - module %? [key %?]\" failed options test - required options are missing", it.second.mi.name, it.first);

            auto missingreq = it.second.mi.options.AllMissingReq();
            for(const auto & optit : missingreq)
                output::GlobalError("    Missing \"%?\"\n", optit);
        }

        output::GlobalDebug("Test of %? OK\n", it.first);
    }

    output::GlobalDebug("Testing getting of modules\n");
    for(const auto & it : store_)
    {
        try {
            GetModule<ModuleBase>(it.first, 0);
        }
        catch(std::exception & ex)
        {
            output::GlobalError("Error - module %? [key %?]\" failed test loading!\n", it.second.mi.name, it.first);
            throw GeneralException(ex, "location", "TestAll");
        }
    }

    output::GlobalDebug("Testing done!\n");
}

ModuleManager::StoreEntry & ModuleManager::GetOrThrow_(const std::string & modulekey)
{
    if(HasKey(modulekey))
        return store_.at(modulekey);
    else
        throw ModuleManagerException("Missing module key in ModuleManager", "modulekey", modulekey);
}

const ModuleManager::StoreEntry & ModuleManager::GetOrThrow_(const std::string & modulekey) const
{
    if(HasKey(modulekey))
        return store_.at(modulekey);
    else
        throw ModuleManagerException("Missing module key in ModuleManager", "modulekey", modulekey);
}

void ModuleManager::EnableDebug(const std::string & modulekey, bool debug)
{
    if(debug)
        keydebug_.insert(modulekey);
    else
        keydebug_.erase(modulekey); // ok if it doesn't exist
}

void ModuleManager::EnableDebugAll(bool debug) noexcept
{
    debugall_ = debug;
}

ModuleTree::const_iterator ModuleManager::TreeBegin(ID_t startid) const
{
    return mtree_.Begin(startid);
}

ModuleTree::const_iterator ModuleManager::TreeEnd(void) const
{
    return mtree_.End();
}

ModuleTree::const_flat_iterator ModuleManager::FlatTreeBegin(void) const
{
    return mtree_.FlatBegin();
}

ModuleTree::const_flat_iterator ModuleManager::FlatTreeEnd(void) const
{
    return mtree_.FlatEnd();
}

/////////////////////////////////////////
// Module Loading
/////////////////////////////////////////
void ModuleManager::LoadModuleFromModuleInfo(const ModuleInfo & minfo, const std::string & modulekey)
{
    // path set in the module info?
    if(minfo.path.size() == 0)
        throw ModuleLoadException("Cannot load module: Empty path",
                                  "modulepath", minfo.path, "modulename", minfo.name);

    // check for duplicates
    if(store_.count(minfo.name))
        throw ModuleLoadException("Cannot load module: duplicate module name",
                                  "modulepath", minfo.path, "modulename", minfo.name);

    // Using the handler, load the module
    if(!loadhandlers_.count(minfo.type))
        throw ModuleLoadException("Cannot load module: unknown module type",
                                  "modulepath", minfo.path, "modulename", minfo.name, "type", minfo.type);

    // may throw an exception. Exception should be a ModuleLoadException
    const ModuleCreationFuncs & mcf = loadhandlers_.at(minfo.type)->LoadSupermodule(minfo.path);

    // See if this supermodule actually create a module with this name
    if(!mcf.HasCreator(minfo.name))
        throw ModuleLoadException("Creators from this supermodule cannot create a module with this name",
                                  "path", minfo.path, "modulename", minfo.name);

    // add to store with the given module name
    store_.emplace(modulekey, StoreEntry{minfo, mcf.GetCreator(minfo.name)});
}

bool ModuleManager::ModuleInUse(ID_t id) const
{
    return modules_inuse_.count(id);
}

void ModuleManager::DestructionNotify(ID_t id) noexcept
{
   // comparison object doesn't throw, therefore this shouldn't throw
   modules_inuse_.erase(id);
}

/////////////////////////////////////////
// Module Creation
/////////////////////////////////////////
std::unique_ptr<detail::ModuleIMPLHolder>
ModuleManager::CreateModule_(const std::string & modulekey, ID_t parentid)
{
    // obtain the information for this key
    const StoreEntry & se = GetOrThrow_(modulekey);

    // actually create the module
    std::unique_ptr<detail::ModuleIMPLHolder> umbptr;

    try {
      // calls the creation function within the loaded supermodule
      umbptr = std::unique_ptr<detail::ModuleIMPLHolder>(se.mc(curid_));
    }
    catch(const std::exception & ex)
    {
        throw exception::ModuleCreateException(ex,
                                               "path", se.mi.path,
                                               "modulekey", modulekey,
                                               "modulename", se.mi.name);
    }

    if(!umbptr)
        throw exception::ModuleCreateException("Module function returned a null pointer",
                                               "path", se.mi.path,
                                               "modulekey", modulekey,
                                               "modulename", se.mi.name);

    // add the moduleinfo to the tree
    ModuleTreeNode me{modulekey,      // key
                      se.mi,          // module info
                      std::string(),  // output
                      curid_,         // module id
                      Wavefunction(), // initial wfn
                      Wavefunction()  // final wfn
                     };

    // If there is a parent, get its wavefunction and use that
    if(parentid != 0)
    {
        if(!mtree_.HasID(parentid))
            throw exception::ModuleCreateException("Parent does not exit on map", "parentid", parentid);

        const ModuleTreeNode & parent = mtree_.GetByID(parentid);
        me.initial_wfn = parent.initial_wfn;
        me.final_wfn = parent.initial_wfn;
    }

    // move the data to the tree
    // "me" should not be accessed after this
    mtree_.Insert(std::move(me), parentid);

    // set the info for the module
    // (set via C++ functions)
    ModuleBase * p = umbptr->CppPtr();
    p->SetMManager_(this);
    p->SetTreeNode_(&(mtree_.GetByID(curid_))); // also sets up output tee

    // Debugging enabled for this module?
    if(debugall_ || keydebug_.count(modulekey))
        p->EnableDebug(true);

    // get this module's cache
    // don't use .at() -- we need it created if it doesn't exist already
    std::string mbstr = p->Name() + "_v" + p->Version();
    p->SetCache_(&(cachemap_[mbstr]));

    // mark the module as inuse
    modules_inuse_.insert(curid_);

    // next id
    curid_++;

    return std::move(umbptr);
}

////////////////////
// Python
////////////////////
pybind11::object ModuleManager::GetModulePy(const std::string & modulekey,
                                            ID_t parentid)
{
    std::unique_ptr<detail::ModuleIMPLHolder> umbptr = CreateModule_(modulekey, parentid);

    // we use a pointer so that the python object
    // can take ownership and we can avoid having
    // a copy constructor for PyModulePtr

    return python::ConvertToPy(new PyModulePtr(std::move(umbptr)), pybind11::return_value_policy::take_ownership);
}

void ModuleManager::ChangeOptionPy(const std::string & modulekey, const std::string & optkey, const pybind11::object & value)
{
    GetOrThrow_(modulekey).mi.options.ChangePy(optkey, value);
}

} // close namespace modulemanager
} // close namespace bpmodule
<|endoftext|>


<commit_before>/* Copyright (c) 2013 Quanta Research Cambridge, Inc
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <semaphore.h>
#include <ctime>
#include <monkit.h>
#include <mp.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "SerialconfigIndicationWrapper.h"
#include "SerialconfigRequestProxy.h"
#include "GeneratedTypes.h"

sem_t test_sem;

uint32_t lasta;
uint32_t lastd;

class SerialconfigIndication : public SerialconfigIndicationWrapper
{
public:
  SerialconfigIndication(unsigned int id) : SerialconfigIndicationWrapper(id){};

  virtual void ack(uint32_t a, uint32_t d) {
    fprintf(stderr, "writeack a %x d %x\n", a, d);
    lasta = a;
    lastd = d;
    sem_post(&test_sem);
  }
};

void dotest(SerialconfigRequestProxy *dev)
{
  dev->send(0x0, 0xf00f00);
  sem_wait(&test_sem);
  dev->send(0x11110001, 0x00000000);
  sem_wait(&test_sem);
  dev->send(0x22220001, 0x00000000);
  sem_wait(&test_sem);
  dev->send(0x33330001, 0x00000000);
  sem_wait(&test_sem);
  dev->send(0x44440001, 0x00000000);
  sem_wait(&test_sem);
  dev->send(0x11110000, 0x00000000);
  sem_wait(&test_sem);
  dev->send(0x22220000, 0x00000000);
  sem_wait(&test_sem);
  dev->send(0x33330000, 0x00000000);
  sem_wait(&test_sem);
  dev->send(0x44440000, 0x00000000);
  sem_wait(&test_sem);
  dev->send(0x11110001, 0x00001111);
  sem_wait(&test_sem);
  dev->send(0x22220001, 0x00002222);
  sem_wait(&test_sem);
  dev->send(0x33330001, 0x00003333);
  sem_wait(&test_sem);
  dev->send(0x44440001, 0x00004444);
  sem_wait(&test_sem);
  dev->send(0x11110000, 0x00000000);
  sem_wait(&test_sem);
  dev->send(0x22220000, 0x00000000);
  sem_wait(&test_sem);
  dev->send(0x33330000, 0x00000000);
  sem_wait(&test_sem);
  dev->send(0x44440000, 0x00000000);
  sem_wait(&test_sem);

  dev->send(0x0, 0xdeadbeef);
  sem_wait(&test_sem);
  dev->send(0x1, 0xdeadbeef);
  sem_wait(&test_sem);
}

int main(int argc, const char **argv)
{
  SerialconfigRequestProxy *device = 0;

  SerialconfigIndication *deviceIndication = 0;

  fprintf(stderr, "%s %s\n", __DATE__, __TIME__);
  device = new SerialconfigRequestProxy(IfcNames_SerialconfigRequest);

  deviceIndication = new SerialconfigIndication(IfcNames_SerialconfigIndication);

  if(sem_init(&test_sem, 1, 0)){
    fprintf(stderr, "failed to init test_sem\n");
    return -1;
  }

  pthread_t tid;
  fprintf(stderr, "creating exec thread\n");
  if(pthread_create(&tid, NULL,  portalExec, NULL)){
   fprintf(stderr, "error creating exec thread\n");
   exit(1);
  }

    fprintf(stderr, "simple tests\n");

    dotest(device);

  }

<commit_msg>test different size registers<commit_after>/* Copyright (c) 2013 Quanta Research Cambridge, Inc
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#include <stdio.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <semaphore.h>
#include <ctime>
#include <monkit.h>
#include <mp.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "SerialconfigIndicationWrapper.h"
#include "SerialconfigRequestProxy.h"
#include "GeneratedTypes.h"

sem_t test_sem;

uint32_t lasta;
uint32_t lastd;

class SerialconfigIndication : public SerialconfigIndicationWrapper
{
public:
  SerialconfigIndication(unsigned int id) : SerialconfigIndicationWrapper(id){};

  virtual void ack(uint32_t a, uint32_t d) {
    fprintf(stderr, "writeack a %x d %x\n", a, d);
    lasta = a;
    lastd = d;
    sem_post(&test_sem);
  }
};

void dotest(SerialconfigRequestProxy *dev)
{
  dev->send(0x0, 0xf00f00);
  sem_wait(&test_sem);
  dev->send(0x11110001, 0x00000000);
  sem_wait(&test_sem);
  dev->send(0x22220001, 0x00000000);
  sem_wait(&test_sem);
  dev->send(0x33330001, 0x00000000);
  sem_wait(&test_sem);
  dev->send(0x44440001, 0x00000000);
  sem_wait(&test_sem);
  dev->send(0x11110000, 0x00000000);
  sem_wait(&test_sem);
  dev->send(0x22220000, 0x00000000);
  sem_wait(&test_sem);
  dev->send(0x33330000, 0x00000000);
  sem_wait(&test_sem);
  dev->send(0x44440000, 0x00000000);
  sem_wait(&test_sem);
  dev->send(0x11110001, 0x11111111);
  sem_wait(&test_sem);
  dev->send(0x22220001, 0x22222222);
  sem_wait(&test_sem);
  dev->send(0x33330001, 0x33333333);
  sem_wait(&test_sem);
  dev->send(0x44440001, 0x44444444);
  sem_wait(&test_sem);
  dev->send(0x11110000, 0x00000000);
  sem_wait(&test_sem);
  dev->send(0x22220000, 0x00000000);
  sem_wait(&test_sem);
  dev->send(0x33330000, 0x00000000);
  sem_wait(&test_sem);
  dev->send(0x44440000, 0x00000000);
  sem_wait(&test_sem);

  dev->send(0x0, 0xdeadbeef);
  sem_wait(&test_sem);
  dev->send(0x1, 0xdeadbeef);
  sem_wait(&test_sem);
}

int main(int argc, const char **argv)
{
  SerialconfigRequestProxy *device = 0;

  SerialconfigIndication *deviceIndication = 0;

  fprintf(stderr, "%s %s\n", __DATE__, __TIME__);
  device = new SerialconfigRequestProxy(IfcNames_SerialconfigRequest);

  deviceIndication = new SerialconfigIndication(IfcNames_SerialconfigIndication);

  if(sem_init(&test_sem, 1, 0)){
    fprintf(stderr, "failed to init test_sem\n");
    return -1;
  }

  pthread_t tid;
  fprintf(stderr, "creating exec thread\n");
  if(pthread_create(&tid, NULL,  portalExec, NULL)){
   fprintf(stderr, "error creating exec thread\n");
   exit(1);
  }

    fprintf(stderr, "simple tests\n");

    dotest(device);

  }

<|endoftext|>