<commit_before>#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QSqlRecord>
#include <functional>
#include "kernel.h"
#include "ilwiscontext.h"
#include "errorobject.h"
#include "publicdatabase.h"
#include "proj4parameters.h"

using namespace Ilwis;

PublicDatabase::PublicDatabase() {
}

PublicDatabase::PublicDatabase(const QSqlDatabase &db) : QSqlDatabase(db)
{
}

void PublicDatabase::prepare() {
    QSqlQuery sql(*this);

    QString stmt = "create table operationMetadata (operationId TEXT, name TEXT, description TEXT,icon TEXT, grouping TEXT)";
    sql.exec(stmt);

    stmt = "create table parameterMetadata (operationId TEXT,parameterName TEXT,parmorder INTEGER, isinput INTEGER,type INTEGER, \
           cardinalty INTEGER,flagged INTEGER,description TEXT,icon TEXT)";
    sql.exec(stmt);

    stmt = "create table aliasses (alias TEXT, code TEXT, type TEXT, source TEXT)";
    sql.exec(stmt);

    stmt = "create table workspaces (workspaceid INTEGER, description TEXT)";
    sql.exec(stmt);

    stmt = "create table workspace (workspaceid INTEGER, itemid INTEGER)";
    sql.exec(stmt);

    stmt = "create table datum \
            (\
                code TEXT,\
                name TEXT,\
                area TEXT, \
                wkt TEXT, \
                authority TEXT, \
                ellipsoid TEXT, \
                dx REAL, \
                sx REAL, \
                dy REAL, \
                sy REAL, \
                dz REAL, \
                sz REAL, \
                north REAL, \
                south REAL, \
                west REAL, \
                east REAL, \
                rx REAL, \
                ry REAL, \
                rz REAL, \
                scale REAL, \
                source TEXT, \
                description TEXT \
                )";

    doQuery(stmt, sql);

    stmt = "create table ellipsoid (  code TEXT, name TEXT, wkt TEXT, authority TEXT, majoraxis REAL, invflattening REAL, source TEXT, description TEXT)";
    doQuery(stmt, sql);

    stmt = "create table projection (  code TEXT, name TEXT, wkt TEXT, authority TEXT, description TEXT)";
    doQuery(stmt, sql);

    stmt = "create table filters (  code TEXT, type TEXT, rows INTEGER, columns INTEGER,definition TEXT, gain REAL, description TEXT)";
    doQuery(stmt, sql);

    stmt = "create table codes (  code TEXT, linkedtable TEXT)";
    doQuery(stmt, sql);

    stmt = "create table dataformats (  code TEXT, name TEXT, description TEXT, extension TEXT,type TEXT,datatype INTEGER, connector TEXT, readwrite TEXT, extendedtype TEXT)";
    doQuery(stmt, sql);

    stmt = "create table numericdomain (  code TEXT, minv REAL, maxv REAL, resolution REAL,resolution_strict INTEGER, range_strict INTEGER,unit TEXT, parent TEXT,description TEXT)";
    doQuery(stmt, sql);

    stmt = "create table representation (  code TEXT, relateddomain TEXT, representationtype TEXT, definition TEXT, description TEXT)";
    doQuery(stmt, sql);

    stmt = "create table mastercatalog \
            (\
                itemid INTEGER,\
                name TEXT collate nocase,\
                code TEXT ,\
                container TEXT collate nocase,\
                resource TEXT collate nocase, \
                rawresource TEXT collate nocase, \
                urlquery TEXT collate nocase, \
                type INTEGER, \
                extendedtype INTEGER, \
                size INTEGER, \
                dimensions TEXT \
               )";
    doQuery(stmt, sql);

    doQuery("CREATE INDEX mastercat_id ON mastercatalog(itemid)", sql);
    doQuery("CREATE INDEX mastercay_urltp ON mastercatalog(rawresource,type)", sql);
    doQuery("CREATE INDEX mastercay_rurltp ON mastercatalog(resource,type)", sql);

    stmt = "create table catalogitemproperties \
            (\
                propertyvalue TEXT, \
                propertyname TEXT, \
                itemid INTEGER \
            )";
    doQuery(stmt, sql) ;

    stmt = "CREATE TABLE projectedcsy ( \
        code TEXT NOT NULL PRIMARY KEY, \
        name TEXT NOT NULL, \
        proj_params TEXT NOT NULL)";
    doQuery(stmt, sql);

    stmt = "create table epsgcodeswithlatlonaxesorder \
            (\
                code TEXT \
            )";
    doQuery(stmt, sql);

    loadPublicTables();

    if ( kernel()->issues()->maxIssueLevel() == IssueObject::itCritical) {
        throw ErrorObject(TR("Critical errors found when initialzing Public database"));
    }

}

bool PublicDatabase::code2Record(const QString &code, const QString &table, QSqlRecord& rec)
{
    auto query = QString("Select * from %1 where code='%2'").arg(table, code);
    QSqlQuery db(*this);
    if (doQuery(query, db)) {
        if ( db.next()) {
            rec = db.record();
            return true;
        }
    }
    return false;
}

QString PublicDatabase::findAlias(const QString &name, const QString &type, const QString &nspace)
{
    QSqlQuery db(kernel()->database());
    QString query = QString("Select code from aliasses where alias='%1' and type='%2' and source='%3'").arg(name).arg(type).arg(nspace);
    if ( db.exec(query)) {
        if ( db.next())
            return db.value(0).toString();
    }
    return sUNDEF;
}

void PublicDatabase::loadPublicTables() {
    QSqlQuery sqlPublic(*this);
    insertFile("datums.csv", sqlPublic);
    insertFile("ellipsoids.csv",sqlPublic);
    insertFile("projections.csv",sqlPublic);
    insertFile("numericdomains.csv",sqlPublic);
    insertFile("filters.csv",sqlPublic);
    insertFile("codes_with_latlon_order.csv",sqlPublic);
    insertFile("representations.csv", sqlPublic);
    insertProj4Epsg(sqlPublic);
}
void PublicDatabase::insertProj4Epsg(QSqlQuery& sqlPublic) {
    auto basePath = context()->ilwisFolder().absoluteFilePath() + "/resources";
    QFileInfo info(basePath + "/epsg.pcs");
    if ( !info.exists())
        return;

    QFile inifile(info.canonicalFilePath());
    if (!inifile.open(QIODevice::ReadOnly | QIODevice::Text))
        return;
    QTextStream textfile(&inifile);
    QString text = textfile.readAll();

    QStringList lines = text.split("\n");
    bool ok = sqlPublic.prepare("INSERT INTO projectedcsy VALUES(\
                  :code,:name,:proj_params )" );
    QString line, name;
    int i = 0;
    while( i < lines.size()) {
        line = lines[i];
        if ( line[0] == '#' && name == "")
            name = line.right(line.size() - 2);
        else if ( line[0] == '<') {
            int index = line.indexOf('>');
            QString epgsTxt = "epsg:" + line.mid(1,index - 1);
            QString projTxt = line.mid(index + 2, line.size() - 4 - index);
            projTxt = projTxt.trimmed();
            sqlPublic.bindValue(":code", epgsTxt);
            sqlPublic.bindValue(":name", name);
            sqlPublic.bindValue(":proj_params", projTxt);
            ok = sqlPublic.exec();
            if (!ok) {
                kernel()->issues()->logSql(sqlPublic.lastError());
                return;
            }
            Proj4Parameters::add2lookup(name,projTxt,epgsTxt);
            name = "";
        } else if ( line[0] == '#') { // comment line, skip it, next line will be empty
            ++i;
            name = "";
        }
        ++i;

    }
}

void PublicDatabase::insertFile(const QString& filename, QSqlQuery& sqlPublic) {
    auto basePath = context()->ilwisFolder().absoluteFilePath() + "/resources";
    QFileInfo fileInfo(basePath + "/" + filename);
    if ( !fileInfo.exists()) {
        kernel()->issues()->log(TR(ERR_MISSING_SYSTEM_FILE_1).arg(filename), IssueObject::itCritical);
        return ;
    }

    QFile file(fileInfo.absoluteFilePath());
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        kernel()->issues()->log(TR(ERR_MISSING_SYSTEM_FILE_1).arg(filename), IssueObject::itCritical);
        return ;
    }

    QTextStream txtFile(&file);
    bool skip = true;
    while(!txtFile.atEnd()) {
        QString line = txtFile.readLine();
        if ( skip) { // first line is header
            skip = false;
            continue;
        }
        auto firstset = line.split(',');
        QStringList parts;
        foreach(auto s, firstset) {
            QString strimmed = s.trimmed();
            parts.push_back(strimmed);
        }

        bool ok = true;
        if ( parts.size() <= 1) {
            // skipping empty lines
            if (parts.size() == 0) {
                continue;
            }
            if (parts.size() == 1 && parts[0].isEmpty()) {
                continue;
            }
        }
        if ( filename == "datums.csv")
            ok = fillDatumRecord(parts, sqlPublic);
        else if ( filename == "ellipsoids.csv")
            ok = fillEllipsoidRecord(parts, sqlPublic);
        else if (filename == "projections.csv")
            ok = fillProjectionRecord(parts,sqlPublic);
        else if ( filename == "numericdomains.csv")
            ok = fillValueDomainRecord(parts, sqlPublic);
        else if ( filename == "filters.csv")
            ok = fillFiltersRecord(parts, sqlPublic);
        else if ( filename == "codes_with_latlon_order.csv")
            ok = fillEpsgWithLatLonAxesOrderRecord(parts, sqlPublic);
        else if ( filename == "representations.csv"){
            ok = fillRepresentationRecord(parts, sqlPublic);
        }
        if (!ok)
            return ;
    }

}

bool PublicDatabase::fillRepresentationRecord(const QStringList& parts, QSqlQuery &sqlPublic) {
    if ( parts.size() == 5) {
        QString parms = QString("'%1','%2','%3','%4','%5'").arg(parts[0],parts[1],parts[2], parts[3],parts[4]);
        QString stmt = QString("INSERT INTO representation VALUES(%1)").arg(parms);
        if(!doQuery(stmt, sqlPublic))
            return false;
        stmt = QString("INSERT INTO codes VALUES('%1', 'representation')").arg(parts[0]);
        return doQuery(stmt, sqlPublic);
    }
    kernel()->issues()->log(TR(ERR_INVALID_RECORD_SIZE_IN).arg("representations.csv"),IssueObject::itCritical);
    return false;
}

bool PublicDatabase::fillValueDomainRecord(const QStringList& parts, QSqlQuery &sqlPublic) {
    if ( parts.size() == 9) {
        QString parms = QString("'%1',%2,%3,%4,%5,%6,'%7','%8','%9'").arg(parts[0],parts[1],parts[2], parts[3],parts[4],parts[5],parts[6],parts[7],parts[8]);
        QString stmt = QString("INSERT INTO numericdomain VALUES(%1)").arg(parms);
        if(!doQuery(stmt, sqlPublic))
            return false;
        stmt = QString("INSERT INTO codes VALUES('%1', 'numericdomain')").arg(parts[0]);
        return doQuery(stmt, sqlPublic);
    }
    kernel()->issues()->log(TR(ERR_INVALID_RECORD_SIZE_IN).arg("numericdomains.csv"),IssueObject::itCritical);
    return false;

}

bool PublicDatabase::fillEllipsoidRecord(const QStringList& parts, QSqlQuery &sqlPublic) {
    if ( parts.size() == 8) {
        QString parms = QString("'%1','%2','%3','%4',%5,%6,'%7','%8'").arg(parts[0],parts[1],parts[2], parts[3],parts[4],parts[5],parts[6],parts[7]);
        QString stmt = QString("INSERT INTO ellipsoid VALUES(%1)").arg(parms);
        if(!doQuery(stmt, sqlPublic))
            return false;
        stmt = QString("INSERT INTO codes VALUES('ellipsoid_%1', 'ellipsoid')").arg(parts[0]);
        return doQuery(stmt, sqlPublic);
    }
    kernel()->issues()->log(TR(ERR_INVALID_RECORD_SIZE_IN).arg("ellipsoids.csv"),IssueObject::itCritical);
    return false;

}

bool PublicDatabase::fillFiltersRecord(const QStringList& parts, QSqlQuery &sqlPublic) {
    if ( parts.size() == 7) {
        auto parms = QString("'%1','%2',%3,%4,'%5',%6,'%7'").arg(parts[0],parts[1],parts[2], parts[3], parts[4],parts[5], parts[6]);
        auto stmt = QString("INSERT INTO filters VALUES(%1)").arg(parms);
        return doQuery(stmt, sqlPublic);
    }
    kernel()->issues()->log(TR(ERR_INVALID_RECORD_SIZE_IN).arg("filters.csv"),IssueObject::itCritical);
    return false;
}

bool PublicDatabase::fillEpsgWithLatLonAxesOrderRecord(const QStringList &parts, QSqlQuery &sqlPublic) {
    if (parts.size() == 1) {
        auto parms = QString("'%1'").arg(parts[0].toLower());
        auto stmt = QString ("INSERT INTO epsgcodeswithlatlonaxesorder VALUES(%1)").arg(parms);
        return doQuery(stmt, sqlPublic);
    }
    kernel()->issues()->log(TR(ERR_INVALID_RECORD_SIZE_IN).arg("codes_with_latlon_order.csv"), IssueObject::itCritical);
    return false;
}

bool PublicDatabase::fillProjectionRecord(const QStringList& parts, QSqlQuery &sqlPublic) {
    if ( parts.size() == 5) {
        auto parms = QString("'%1','%2','%3','%4','%5'").arg(parts[0],parts[1],parts[2], parts[3], parts[4]);
        auto stmt = QString("INSERT INTO projection VALUES(%1)").arg(parms);
        if(!doQuery(stmt, sqlPublic))
            return false;

        stmt = QString("INSERT INTO codes VALUES('%1', 'projection')").arg(parts[0]);
        return doQuery(stmt, sqlPublic);
    }
    kernel()->issues()->log(TR(ERR_INVALID_RECORD_SIZE_IN).arg("projections.csv"),IssueObject::itCritical);
    return false;

}

bool PublicDatabase::fillDatumRecord(const QStringList& parts, QSqlQuery &sqlPublic) {
    if ( parts.size() == 22) {
        QString parms = QString("'%1','%2','%3','%4','%5','%6',").arg(parts[0],parts[1],parts[2],parts[3],parts[4],parts[5]); //text parts
        parms += QString("%1,%2,%3,%4,%5,%6,").arg(parts[6],parts[7],parts[8],parts[9],parts[10],parts[11]); // shifts
        parms += QString("%1,%2,%3,%4,").arg(parts[12],parts[13],parts[14],parts[15]); //rotation
        parms += QString("%1,%2,%3,").arg(parts[16], parts[17], parts[18]); // nsew
        parms += QString("%1,'%2','%3'").arg(parts[19],parts[20], parts[21]); // scale, source,description
        QString stmt = QString("INSERT INTO datum VALUES(%1)").arg(parms);
        if(!doQuery(stmt, sqlPublic))
            return false;
        stmt = QString("INSERT INTO codes VALUES('%1', 'datum')").arg(parts[0]);
        return doQuery(stmt, sqlPublic);
    }
    kernel()->issues()->log(TR(ERR_INVALID_RECORD_SIZE_IN).arg("datums.csv"),IssueObject::itCritical);
    return false;
}

bool PublicDatabase::doQuery(const QString& query, QSqlQuery &sqlPublic)
{
    bool ok = sqlPublic.exec(query);
    if (!ok) {
        kernel()->issues()->logSql(sqlPublic.lastError());
        return false;
    }
    return true;
}

<commit_msg>add rawcontainer to the mastercatalog table<commit_after>#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QSqlRecord>
#include <functional>
#include "kernel.h"
#include "ilwiscontext.h"
#include "errorobject.h"
#include "publicdatabase.h"
#include "proj4parameters.h"

using namespace Ilwis;

PublicDatabase::PublicDatabase() {
}

PublicDatabase::PublicDatabase(const QSqlDatabase &db) : QSqlDatabase(db)
{
}

void PublicDatabase::prepare() {
    QSqlQuery sql(*this);

    QString stmt = "create table operationMetadata (operationId TEXT, name TEXT, description TEXT,icon TEXT, grouping TEXT)";
    sql.exec(stmt);

    stmt = "create table parameterMetadata (operationId TEXT,parameterName TEXT,parmorder INTEGER, isinput INTEGER,type INTEGER, \
           cardinalty INTEGER,flagged INTEGER,description TEXT,icon TEXT)";
    sql.exec(stmt);

    stmt = "create table aliasses (alias TEXT, code TEXT, type TEXT, source TEXT)";
    sql.exec(stmt);

    stmt = "create table workspaces (workspaceid INTEGER, description TEXT)";
    sql.exec(stmt);

    stmt = "create table workspace (workspaceid INTEGER, itemid INTEGER)";
    sql.exec(stmt);

    stmt = "create table datum \
            (\
                code TEXT,\
                name TEXT,\
                area TEXT, \
                wkt TEXT, \
                authority TEXT, \
                ellipsoid TEXT, \
                dx REAL, \
                sx REAL, \
                dy REAL, \
                sy REAL, \
                dz REAL, \
                sz REAL, \
                north REAL, \
                south REAL, \
                west REAL, \
                east REAL, \
                rx REAL, \
                ry REAL, \
                rz REAL, \
                scale REAL, \
                source TEXT, \
                description TEXT \
                )";

    doQuery(stmt, sql);

    stmt = "create table ellipsoid (  code TEXT, name TEXT, wkt TEXT, authority TEXT, majoraxis REAL, invflattening REAL, source TEXT, description TEXT)";
    doQuery(stmt, sql);

    stmt = "create table projection (  code TEXT, name TEXT, wkt TEXT, authority TEXT, description TEXT)";
    doQuery(stmt, sql);

    stmt = "create table filters (  code TEXT, type TEXT, rows INTEGER, columns INTEGER,definition TEXT, gain REAL, description TEXT)";
    doQuery(stmt, sql);

    stmt = "create table codes (  code TEXT, linkedtable TEXT)";
    doQuery(stmt, sql);

    stmt = "create table dataformats (  code TEXT, name TEXT, description TEXT, extension TEXT,type TEXT,datatype INTEGER, connector TEXT, readwrite TEXT, extendedtype TEXT)";
    doQuery(stmt, sql);

    stmt = "create table numericdomain (  code TEXT, minv REAL, maxv REAL, resolution REAL,resolution_strict INTEGER, range_strict INTEGER,unit TEXT, parent TEXT,description TEXT)";
    doQuery(stmt, sql);

    stmt = "create table representation (  code TEXT, relateddomain TEXT, representationtype TEXT, definition TEXT, description TEXT)";
    doQuery(stmt, sql);

    stmt = "create table mastercatalog \
            (\
                itemid INTEGER,\
                name TEXT collate nocase,\
                code TEXT ,\
                container TEXT collate nocase,\
                rawcontainer TEXT collate nocase,\
                resource TEXT collate nocase, \
                rawresource TEXT collate nocase, \
                urlquery TEXT collate nocase, \
                type INTEGER, \
                extendedtype INTEGER, \
                size INTEGER, \
                dimensions TEXT \
               )";
    doQuery(stmt, sql);

    doQuery("CREATE INDEX mastercat_id ON mastercatalog(itemid)", sql);
    doQuery("CREATE INDEX mastercay_urltp ON mastercatalog(rawresource,type)", sql);
    doQuery("CREATE INDEX mastercay_rurltp ON mastercatalog(resource,type)", sql);

    stmt = "create table catalogitemproperties \
            (\
                propertyvalue TEXT, \
                propertyname TEXT, \
                itemid INTEGER \
            )";
    doQuery(stmt, sql) ;

    stmt = "CREATE TABLE projectedcsy ( \
        code TEXT NOT NULL PRIMARY KEY, \
        name TEXT NOT NULL, \
        proj_params TEXT NOT NULL)";
    doQuery(stmt, sql);

    stmt = "create table epsgcodeswithlatlonaxesorder \
            (\
                code TEXT \
            )";
    doQuery(stmt, sql);

    loadPublicTables();

    if ( kernel()->issues()->maxIssueLevel() == IssueObject::itCritical) {
        throw ErrorObject(TR("Critical errors found when initialzing Public database"));
    }

}

bool PublicDatabase::code2Record(const QString &code, const QString &table, QSqlRecord& rec)
{
    auto query = QString("Select * from %1 where code='%2'").arg(table, code);
    QSqlQuery db(*this);
    if (doQuery(query, db)) {
        if ( db.next()) {
            rec = db.record();
            return true;
        }
    }
    return false;
}

QString PublicDatabase::findAlias(const QString &name, const QString &type, const QString &nspace)
{
    QSqlQuery db(kernel()->database());
    QString query = QString("Select code from aliasses where alias='%1' and type='%2' and source='%3'").arg(name).arg(type).arg(nspace);
    if ( db.exec(query)) {
        if ( db.next())
            return db.value(0).toString();
    }
    return sUNDEF;
}

void PublicDatabase::loadPublicTables() {
    QSqlQuery sqlPublic(*this);
    insertFile("datums.csv", sqlPublic);
    insertFile("ellipsoids.csv",sqlPublic);
    insertFile("projections.csv",sqlPublic);
    insertFile("numericdomains.csv",sqlPublic);
    insertFile("filters.csv",sqlPublic);
    insertFile("codes_with_latlon_order.csv",sqlPublic);
    insertFile("representations.csv", sqlPublic);
    insertProj4Epsg(sqlPublic);
}
void PublicDatabase::insertProj4Epsg(QSqlQuery& sqlPublic) {
    auto basePath = context()->ilwisFolder().absoluteFilePath() + "/resources";
    QFileInfo info(basePath + "/epsg.pcs");
    if ( !info.exists())
        return;

    QFile inifile(info.canonicalFilePath());
    if (!inifile.open(QIODevice::ReadOnly | QIODevice::Text))
        return;
    QTextStream textfile(&inifile);
    QString text = textfile.readAll();

    QStringList lines = text.split("\n");
    bool ok = sqlPublic.prepare("INSERT INTO projectedcsy VALUES(\
                  :code,:name,:proj_params )" );
    QString line, name;
    int i = 0;
    while( i < lines.size()) {
        line = lines[i];
        if ( line[0] == '#' && name == "")
            name = line.right(line.size() - 2);
        else if ( line[0] == '<') {
            int index = line.indexOf('>');
            QString epgsTxt = "epsg:" + line.mid(1,index - 1);
            QString projTxt = line.mid(index + 2, line.size() - 4 - index);
            projTxt = projTxt.trimmed();
            sqlPublic.bindValue(":code", epgsTxt);
            sqlPublic.bindValue(":name", name);
            sqlPublic.bindValue(":proj_params", projTxt);
            ok = sqlPublic.exec();
            if (!ok) {
                kernel()->issues()->logSql(sqlPublic.lastError());
                return;
            }
            Proj4Parameters::add2lookup(name,projTxt,epgsTxt);
            name = "";
        } else if ( line[0] == '#') { // comment line, skip it, next line will be empty
            ++i;
            name = "";
        }
        ++i;

    }
}

void PublicDatabase::insertFile(const QString& filename, QSqlQuery& sqlPublic) {
    auto basePath = context()->ilwisFolder().absoluteFilePath() + "/resources";
    QFileInfo fileInfo(basePath + "/" + filename);
    if ( !fileInfo.exists()) {
        kernel()->issues()->log(TR(ERR_MISSING_SYSTEM_FILE_1).arg(filename), IssueObject::itCritical);
        return ;
    }

    QFile file(fileInfo.absoluteFilePath());
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        kernel()->issues()->log(TR(ERR_MISSING_SYSTEM_FILE_1).arg(filename), IssueObject::itCritical);
        return ;
    }

    QTextStream txtFile(&file);
    bool skip = true;
    while(!txtFile.atEnd()) {
        QString line = txtFile.readLine();
        if ( skip) { // first line is header
            skip = false;
            continue;
        }
        auto firstset = line.split(',');
        QStringList parts;
        foreach(auto s, firstset) {
            QString strimmed = s.trimmed();
            parts.push_back(strimmed);
        }

        bool ok = true;
        if ( parts.size() <= 1) {
            // skipping empty lines
            if (parts.size() == 0) {
                continue;
            }
            if (parts.size() == 1 && parts[0].isEmpty()) {
                continue;
            }
        }
        if ( filename == "datums.csv")
            ok = fillDatumRecord(parts, sqlPublic);
        else if ( filename == "ellipsoids.csv")
            ok = fillEllipsoidRecord(parts, sqlPublic);
        else if (filename == "projections.csv")
            ok = fillProjectionRecord(parts,sqlPublic);
        else if ( filename == "numericdomains.csv")
            ok = fillValueDomainRecord(parts, sqlPublic);
        else if ( filename == "filters.csv")
            ok = fillFiltersRecord(parts, sqlPublic);
        else if ( filename == "codes_with_latlon_order.csv")
            ok = fillEpsgWithLatLonAxesOrderRecord(parts, sqlPublic);
        else if ( filename == "representations.csv"){
            ok = fillRepresentationRecord(parts, sqlPublic);
        }
        if (!ok)
            return ;
    }

}

bool PublicDatabase::fillRepresentationRecord(const QStringList& parts, QSqlQuery &sqlPublic) {
    if ( parts.size() == 5) {
        QString parms = QString("'%1','%2','%3','%4','%5'").arg(parts[0],parts[1],parts[2], parts[3],parts[4]);
        QString stmt = QString("INSERT INTO representation VALUES(%1)").arg(parms);
        if(!doQuery(stmt, sqlPublic))
            return false;
        stmt = QString("INSERT INTO codes VALUES('%1', 'representation')").arg(parts[0]);
        return doQuery(stmt, sqlPublic);
    }
    kernel()->issues()->log(TR(ERR_INVALID_RECORD_SIZE_IN).arg("representations.csv"),IssueObject::itCritical);
    return false;
}

bool PublicDatabase::fillValueDomainRecord(const QStringList& parts, QSqlQuery &sqlPublic) {
    if ( parts.size() == 9) {
        QString parms = QString("'%1',%2,%3,%4,%5,%6,'%7','%8','%9'").arg(parts[0],parts[1],parts[2], parts[3],parts[4],parts[5],parts[6],parts[7],parts[8]);
        QString stmt = QString("INSERT INTO numericdomain VALUES(%1)").arg(parms);
        if(!doQuery(stmt, sqlPublic))
            return false;
        stmt = QString("INSERT INTO codes VALUES('%1', 'numericdomain')").arg(parts[0]);
        return doQuery(stmt, sqlPublic);
    }
    kernel()->issues()->log(TR(ERR_INVALID_RECORD_SIZE_IN).arg("numericdomains.csv"),IssueObject::itCritical);
    return false;

}

bool PublicDatabase::fillEllipsoidRecord(const QStringList& parts, QSqlQuery &sqlPublic) {
    if ( parts.size() == 8) {
        QString parms = QString("'%1','%2','%3','%4',%5,%6,'%7','%8'").arg(parts[0],parts[1],parts[2], parts[3],parts[4],parts[5],parts[6],parts[7]);
        QString stmt = QString("INSERT INTO ellipsoid VALUES(%1)").arg(parms);
        if(!doQuery(stmt, sqlPublic))
            return false;
        stmt = QString("INSERT INTO codes VALUES('ellipsoid_%1', 'ellipsoid')").arg(parts[0]);
        return doQuery(stmt, sqlPublic);
    }
    kernel()->issues()->log(TR(ERR_INVALID_RECORD_SIZE_IN).arg("ellipsoids.csv"),IssueObject::itCritical);
    return false;

}

bool PublicDatabase::fillFiltersRecord(const QStringList& parts, QSqlQuery &sqlPublic) {
    if ( parts.size() == 7) {
        auto parms = QString("'%1','%2',%3,%4,'%5',%6,'%7'").arg(parts[0],parts[1],parts[2], parts[3], parts[4],parts[5], parts[6]);
        auto stmt = QString("INSERT INTO filters VALUES(%1)").arg(parms);
        return doQuery(stmt, sqlPublic);
    }
    kernel()->issues()->log(TR(ERR_INVALID_RECORD_SIZE_IN).arg("filters.csv"),IssueObject::itCritical);
    return false;
}

bool PublicDatabase::fillEpsgWithLatLonAxesOrderRecord(const QStringList &parts, QSqlQuery &sqlPublic) {
    if (parts.size() == 1) {
        auto parms = QString("'%1'").arg(parts[0].toLower());
        auto stmt = QString ("INSERT INTO epsgcodeswithlatlonaxesorder VALUES(%1)").arg(parms);
        return doQuery(stmt, sqlPublic);
    }
    kernel()->issues()->log(TR(ERR_INVALID_RECORD_SIZE_IN).arg("codes_with_latlon_order.csv"), IssueObject::itCritical);
    return false;
}

bool PublicDatabase::fillProjectionRecord(const QStringList& parts, QSqlQuery &sqlPublic) {
    if ( parts.size() == 5) {
        auto parms = QString("'%1','%2','%3','%4','%5'").arg(parts[0],parts[1],parts[2], parts[3], parts[4]);
        auto stmt = QString("INSERT INTO projection VALUES(%1)").arg(parms);
        if(!doQuery(stmt, sqlPublic))
            return false;

        stmt = QString("INSERT INTO codes VALUES('%1', 'projection')").arg(parts[0]);
        return doQuery(stmt, sqlPublic);
    }
    kernel()->issues()->log(TR(ERR_INVALID_RECORD_SIZE_IN).arg("projections.csv"),IssueObject::itCritical);
    return false;

}

bool PublicDatabase::fillDatumRecord(const QStringList& parts, QSqlQuery &sqlPublic) {
    if ( parts.size() == 22) {
        QString parms = QString("'%1','%2','%3','%4','%5','%6',").arg(parts[0],parts[1],parts[2],parts[3],parts[4],parts[5]); //text parts
        parms += QString("%1,%2,%3,%4,%5,%6,").arg(parts[6],parts[7],parts[8],parts[9],parts[10],parts[11]); // shifts
        parms += QString("%1,%2,%3,%4,").arg(parts[12],parts[13],parts[14],parts[15]); //rotation
        parms += QString("%1,%2,%3,").arg(parts[16], parts[17], parts[18]); // nsew
        parms += QString("%1,'%2','%3'").arg(parts[19],parts[20], parts[21]); // scale, source,description
        QString stmt = QString("INSERT INTO datum VALUES(%1)").arg(parms);
        if(!doQuery(stmt, sqlPublic))
            return false;
        stmt = QString("INSERT INTO codes VALUES('%1', 'datum')").arg(parts[0]);
        return doQuery(stmt, sqlPublic);
    }
    kernel()->issues()->log(TR(ERR_INVALID_RECORD_SIZE_IN).arg("datums.csv"),IssueObject::itCritical);
    return false;
}

bool PublicDatabase::doQuery(const QString& query, QSqlQuery &sqlPublic)
{
    bool ok = sqlPublic.exec(query);
    if (!ok) {
        kernel()->issues()->logSql(sqlPublic.lastError());
        return false;
    }
    return true;
}

<|endoftext|>


<commit_before>/***

Copyright 2013-2016 Dave Cridland
Copyright 2014-2016 Surevine Ltd

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

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

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

***/

#include "stanza.h"
#include "xmlstream.h"
#include "rapidxml_print.hpp"
#include "log.h"

using namespace Metre;

Stanza::Stanza(const char *name, rapidxml::xml_node<> const *node) : m_name(name), m_node(node) {
    auto to = node->first_attribute("to");
    if (to) m_to = Jid(to->value());
    auto from = node->first_attribute("from");
    if (from) m_from = Jid(from->value());
    auto typestr = node->first_attribute("type");
    if (typestr) m_type_str = typestr->value();
    auto id = node->first_attribute("id");
    if (id) m_id = id->value();
    m_payload = node->contents();
    m_payload_l = node->contents_size();
}

Stanza::Stanza(const char *name) : m_name(name) {
}

Stanza::Stanza(const char *name, Jid const &from, Jid const &to, std::string const &type_str, std::string const &id)
        : m_name(name), m_from(from), m_to(to), m_type_str(type_str),
          m_id(id) {
}

void Stanza::freeze() {
    if (!m_payload_str.empty()) return;
    if (!m_payload) {
        m_node = nullptr;
        return;
    }
    m_payload_str.assign(m_payload, m_payload_l);
    METRE_LOG(Metre::Log::DEBUG, "Frozen stanza: " + m_payload_str);
    m_payload = m_payload_str.data();
    m_node = nullptr;
}

void Stanza::render(rapidxml::xml_document<> &d) {
    auto hdr = d.allocate_node(rapidxml::node_element, m_name);
    if (m_to) {
        auto att = d.allocate_attribute("to", m_to->full().c_str());
        hdr->append_attribute(att);
    }
    if (m_from) {
        auto att = d.allocate_attribute("from", m_from->full().c_str());
        hdr->append_attribute(att);
    }
    if (m_type_str) {
        auto att = d.allocate_attribute("type", m_type_str->c_str());
        hdr->append_attribute(att);
    }
    if (!m_id.empty()) {
        auto att = d.allocate_attribute("id", m_id.c_str());
        hdr->append_attribute(att);
    }
    if (m_node) {
        for (auto child = m_node->first_node(); child; child = child->next_sibling()) {
            hdr->append_node(child);
        }
    } else if (m_payload && m_payload_l) {
        auto lit = d.allocate_node(rapidxml::node_literal);
        lit->value(m_payload, m_payload_l);
        hdr->append_node(lit);
    }
    d.append_node(hdr);
}

std::unique_ptr<Stanza> Stanza::create_bounce(base::stanza_exception const &ex) {
    std::unique_ptr<Stanza> stanza{new Stanza(m_name)};
    stanza->m_from = m_to;
    stanza->m_to = m_from;
    stanza->m_id = m_id;
    stanza->m_type_str = "error";
    stanza->render_error(ex);
    if (m_payload && m_payload_l) {
        stanza->m_payload_str.append(m_payload, m_payload_l);
        stanza->m_payload = stanza->m_payload_str.c_str();
        stanza->m_payload_l = stanza->m_payload_str.length();
    }
    return stanza;
}

void Stanza::render_error(Metre::base::stanza_exception const &ex) {
    // Render the error
    rapidxml::xml_document<> d;
    auto error = d.allocate_node(rapidxml::node_element, "error");
    error->append_attribute(d.allocate_attribute("type", ex.error_type()));
    d.append_node(error);
    auto condition = d.allocate_node(rapidxml::node_element, ex.element_name());
    condition->append_attribute(d.allocate_attribute("xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas"));
    error->append_node(condition);
    auto text = d.allocate_node(rapidxml::node_element, "text");
    text->append_attribute(d.allocate_attribute("xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas"));
    text->value(ex.what());
    error->append_node(text);
    rapidxml::print(std::back_inserter(m_payload_str), d, rapidxml::print_no_indenting);
}

void Stanza::render_error(Stanza::Error e) {
    switch (e) {
        case remote_server_timeout:
            render_error(stanza_remote_server_timeout());
            return;
        case remote_server_not_found:
            render_error(stanza_remote_server_not_found());
            return;
        case service_unavailable:
            render_error(stanza_service_unavailable());
            return;
        case undefined_condition:
            render_error(stanza_undefined_condition());
            return;
        case policy_violation:
            render_error(stanza_policy_violation());
            return;
        default:
        METRE_LOG(Log::CRIT, "Unhandled stanza error type");
            render_error(stanza_undefined_condition());
    }
}

std::unique_ptr<Stanza> Stanza::create_bounce(Stanza::Error e) {
    switch (e) {
        case remote_server_timeout:
            return create_bounce(stanza_remote_server_timeout());
        case remote_server_not_found:
            return create_bounce(stanza_remote_server_not_found());
        case service_unavailable:
            return create_bounce(stanza_service_unavailable());
        case undefined_condition:
            return create_bounce(stanza_undefined_condition());
        default:
        METRE_LOG(Log::CRIT, "Unhandled stanza error type");
            return create_bounce(stanza_undefined_condition());
    }
}

std::unique_ptr<Stanza> Stanza::create_forward() {
    std::unique_ptr<Stanza> stanza{new Stanza(m_name)};
    stanza->m_from = m_from;
    stanza->m_to = m_to;
    stanza->m_id = m_id;
    stanza->m_type_str = m_type_str;
    if (m_payload && m_payload_l) {
        stanza->m_payload_str.append(m_payload, m_payload_l);
        stanza->m_payload = stanza->m_payload_str.c_str();
        stanza->m_payload_l = stanza->m_payload_str.length();
    }
    return stanza;
}

Message::Message(rapidxml::xml_node<> const *node) : Stanza(name, node) {
    m_type = set_type();
}

Message::Type Message::set_type() const {
    if (!type_str()) return NORMAL;
    std::string const &t = *type_str();
    switch (t[0]) {
        case 'n':
            if (t == "normal") return NORMAL;
            break;
        case 'c':
            if (t == "chat") return CHAT;
            break;
        case 'h':
            if (t == "headline") return HEADLINE;
            break;
        case 'g':
            if (t == "groupchat") return GROUPCHAT;
            break;
        case 'e':
            if (t == "error") return ERROR;
            break;
    }
    throw std::runtime_error("Unknown Message type");
}

Iq::Iq(Jid const &from, Jid const &to, Type t, std::string const &id) : Stanza("iq", from, to,
                                                                               Iq::type_toString(t), id), m_type(t) {}

Iq::Iq(rapidxml::xml_node<> const *node) : Stanza(name, node) {
    m_type = set_type();
}

const char *Iq::type_toString(Type t) {
    switch (t) {
        case GET:
            return "get";
        case SET:
            return "set";
        case RESULT:
            return "result";
        case ERROR:
            return "error";
    }
    return "error";
}

Iq::Type Iq::set_type() const {
    if (!type_str()) throw std::runtime_error("Missing type for Iq");
    std::string const &t = *type_str();
    switch (t[0]) {
        case 'g':
            if (t == "get") return GET;
            break;
        case 's':
            if (t == "set") return SET;
            break;
        case 'r':
            if (t == "result") return RESULT;
            break;
        case 'e':
            if (t == "error") return ERROR;
            break;
    }
    throw std::runtime_error("Unknown IQ type");
}

const char *Iq::name = "iq";
const char *Message::name = "message";
const char *Presence::name = "presence";
const char *DB::Verify::name = "db:verify";
const char *DB::Result::name = "db:result";

/*
 * Dialback
 */

DB::DB(const char *name, Jid const &to, Jid const &from, std::string const &stream_id,
       std::optional<std::string> const &key)
        : Stanza(name) {
    m_to = to;
    m_from = from;
    m_id = stream_id;
    m_payload_str = *key;
    m_payload = m_payload_str.data();
    m_payload_l = m_payload_str.length();
}

DB::DB(const char *name, Jid const &to, Jid const &from, std::string const &stream_id, Type t) : Stanza(name) {
    m_to = to;
    m_from = from;
    m_id = stream_id;
    switch (t) {
        case VALID:
            m_type_str = "valid";
            break;
        case INVALID:
            m_type_str = "invalid";
            break;
        case ERROR:
            m_type_str = "error";
            break;
    }
}

DB::DB(const char *name, Jid const &to, Jid const &from, std::string const &stream_id, Stanza::Error e) : Stanza(name) {
    m_to = to;
    m_from = from;
    m_id = stream_id;
    m_type_str = "error";
    render_error(e);
    m_payload = m_payload_str.data();
    m_payload_l = m_payload_str.size();
}<commit_msg>Fix fourth batch of production issues<commit_after>/***

Copyright 2013-2016 Dave Cridland
Copyright 2014-2016 Surevine Ltd

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

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

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

***/

#include "stanza.h"
#include "xmlstream.h"
#include "rapidxml_print.hpp"
#include "log.h"

using namespace Metre;

Stanza::Stanza(const char *name, rapidxml::xml_node<> const *node) : m_name(name), m_node(node) {
    auto to = node->first_attribute("to");
    if (to) m_to = Jid(to->value());
    auto from = node->first_attribute("from");
    if (from) m_from = Jid(from->value());
    auto typestr = node->first_attribute("type");
    if (typestr) m_type_str = typestr->value();
    auto id = node->first_attribute("id");
    if (id) m_id = id->value();
    m_payload = node->contents();
    m_payload_l = node->contents_size();
}

Stanza::Stanza(const char *name) : m_name(name) {
}

Stanza::Stanza(const char *name, Jid const &from, Jid const &to, std::string const &type_str, std::string const &id)
        : m_name(name), m_from(from), m_to(to), m_type_str(type_str),
          m_id(id) {
}

void Stanza::freeze() {
    if (!m_payload_str.empty()) return;
    if (!m_payload) {
        m_node = nullptr;
        return;
    }
    m_payload_str.assign(m_payload, m_payload_l);
    METRE_LOG(Metre::Log::DEBUG, "Frozen stanza: " + m_payload_str);
    m_payload = m_payload_str.data();
    m_node = nullptr;
}

void Stanza::render(rapidxml::xml_document<> &d) {
    auto hdr = d.allocate_node(rapidxml::node_element, m_name);
    if (m_to) {
        auto att = d.allocate_attribute("to", m_to->full().c_str());
        hdr->append_attribute(att);
    }
    if (m_from) {
        auto att = d.allocate_attribute("from", m_from->full().c_str());
        hdr->append_attribute(att);
    }
    if (m_type_str) {
        auto att = d.allocate_attribute("type", m_type_str->c_str());
        hdr->append_attribute(att);
    }
    if (!m_id.empty()) {
        auto att = d.allocate_attribute("id", m_id.c_str());
        hdr->append_attribute(att);
    }
    if (m_payload && m_payload_l) {
        auto lit = d.allocate_node(rapidxml::node_literal);
        lit->value(m_payload, m_payload_l);
        hdr->append_node(lit);
    }
    d.append_node(hdr);
}

std::unique_ptr<Stanza> Stanza::create_bounce(base::stanza_exception const &ex) {
    std::unique_ptr<Stanza> stanza{new Stanza(m_name)};
    stanza->m_from = m_to;
    stanza->m_to = m_from;
    stanza->m_id = m_id;
    stanza->m_type_str = "error";
    stanza->render_error(ex);
    if (m_payload && m_payload_l) {
        stanza->m_payload_str.append(m_payload, m_payload_l);
        stanza->m_payload = stanza->m_payload_str.c_str();
        stanza->m_payload_l = stanza->m_payload_str.length();
    }
    return stanza;
}

void Stanza::render_error(Metre::base::stanza_exception const &ex) {
    // Render the error
    rapidxml::xml_document<> d;
    auto error = d.allocate_node(rapidxml::node_element, "error");
    error->append_attribute(d.allocate_attribute("type", ex.error_type()));
    d.append_node(error);
    auto condition = d.allocate_node(rapidxml::node_element, ex.element_name());
    condition->append_attribute(d.allocate_attribute("xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas"));
    error->append_node(condition);
    auto text = d.allocate_node(rapidxml::node_element, "text");
    text->append_attribute(d.allocate_attribute("xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas"));
    text->value(ex.what());
    error->append_node(text);
    rapidxml::print(std::back_inserter(m_payload_str), d, rapidxml::print_no_indenting);
}

void Stanza::render_error(Stanza::Error e) {
    switch (e) {
        case remote_server_timeout:
            render_error(stanza_remote_server_timeout());
            return;
        case remote_server_not_found:
            render_error(stanza_remote_server_not_found());
            return;
        case service_unavailable:
            render_error(stanza_service_unavailable());
            return;
        case undefined_condition:
            render_error(stanza_undefined_condition());
            return;
        case policy_violation:
            render_error(stanza_policy_violation());
            return;
        default:
        METRE_LOG(Log::CRIT, "Unhandled stanza error type");
            render_error(stanza_undefined_condition());
    }
}

std::unique_ptr<Stanza> Stanza::create_bounce(Stanza::Error e) {
    switch (e) {
        case remote_server_timeout:
            return create_bounce(stanza_remote_server_timeout());
        case remote_server_not_found:
            return create_bounce(stanza_remote_server_not_found());
        case service_unavailable:
            return create_bounce(stanza_service_unavailable());
        case undefined_condition:
            return create_bounce(stanza_undefined_condition());
        default:
        METRE_LOG(Log::CRIT, "Unhandled stanza error type");
            return create_bounce(stanza_undefined_condition());
    }
}

std::unique_ptr<Stanza> Stanza::create_forward() {
    std::unique_ptr<Stanza> stanza{new Stanza(m_name)};
    stanza->m_from = m_from;
    stanza->m_to = m_to;
    stanza->m_id = m_id;
    stanza->m_type_str = m_type_str;
    if (m_payload && m_payload_l) {
        stanza->m_payload_str.append(m_payload, m_payload_l);
        stanza->m_payload = stanza->m_payload_str.c_str();
        stanza->m_payload_l = stanza->m_payload_str.length();
    }
    return stanza;
}

Message::Message(rapidxml::xml_node<> const *node) : Stanza(name, node) {
    m_type = set_type();
}

Message::Type Message::set_type() const {
    if (!type_str()) return NORMAL;
    std::string const &t = *type_str();
    switch (t[0]) {
        case 'n':
            if (t == "normal") return NORMAL;
            break;
        case 'c':
            if (t == "chat") return CHAT;
            break;
        case 'h':
            if (t == "headline") return HEADLINE;
            break;
        case 'g':
            if (t == "groupchat") return GROUPCHAT;
            break;
        case 'e':
            if (t == "error") return ERROR;
            break;
    }
    throw std::runtime_error("Unknown Message type");
}

Iq::Iq(Jid const &from, Jid const &to, Type t, std::string const &id) : Stanza("iq", from, to,
                                                                               Iq::type_toString(t), id), m_type(t) {}

Iq::Iq(rapidxml::xml_node<> const *node) : Stanza(name, node) {
    m_type = set_type();
}

const char *Iq::type_toString(Type t) {
    switch (t) {
        case GET:
            return "get";
        case SET:
            return "set";
        case RESULT:
            return "result";
        case ERROR:
            return "error";
    }
    return "error";
}

Iq::Type Iq::set_type() const {
    if (!type_str()) throw std::runtime_error("Missing type for Iq");
    std::string const &t = *type_str();
    switch (t[0]) {
        case 'g':
            if (t == "get") return GET;
            break;
        case 's':
            if (t == "set") return SET;
            break;
        case 'r':
            if (t == "result") return RESULT;
            break;
        case 'e':
            if (t == "error") return ERROR;
            break;
    }
    throw std::runtime_error("Unknown IQ type");
}

const char *Iq::name = "iq";
const char *Message::name = "message";
const char *Presence::name = "presence";
const char *DB::Verify::name = "db:verify";
const char *DB::Result::name = "db:result";

/*
 * Dialback
 */

DB::DB(const char *name, Jid const &to, Jid const &from, std::string const &stream_id,
       std::optional<std::string> const &key)
        : Stanza(name) {
    m_to = to;
    m_from = from;
    m_id = stream_id;
    m_payload_str = *key;
    m_payload = m_payload_str.data();
    m_payload_l = m_payload_str.length();
}

DB::DB(const char *name, Jid const &to, Jid const &from, std::string const &stream_id, Type t) : Stanza(name) {
    m_to = to;
    m_from = from;
    m_id = stream_id;
    switch (t) {
        case VALID:
            m_type_str = "valid";
            break;
        case INVALID:
            m_type_str = "invalid";
            break;
        case ERROR:
            m_type_str = "error";
            break;
    }
}

DB::DB(const char *name, Jid const &to, Jid const &from, std::string const &stream_id, Stanza::Error e) : Stanza(name) {
    m_to = to;
    m_from = from;
    m_id = stream_id;
    m_type_str = "error";
    render_error(e);
    m_payload = m_payload_str.data();
    m_payload_l = m_payload_str.size();
}<|endoftext|>


<commit_before>// $Id$

/*
Copyright (c) 2007-2009, Trustees of The Leland Stanford Junior University
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
Neither the name of the Stanford University nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*stats.cpp
 *
 *class stores statistics gnerated by the trafficmanager such as the latency
 *hope count of the the flits
 *
 *reset option resets the min and max alues of this statistiscs
 */

#include "booksim.hpp"
#include <iostream>
#include <sstream>
#include <limits>
#include <cmath>
#include <cstdio>

#include "stats.hpp"

Stats::Stats( Module *parent, const string &name,
	      double bin_size, int num_bins ) :
  Module( parent, name ),
   _num_bins( num_bins ), _bin_size( bin_size ), _hist(_num_bins, 0), _num_samples(0), _sample_sum(0.0)
{

}

void Stats::Clear( )
{
  _num_samples = 0;
  _sample_sum  = 0.0;

  for ( int b = 0; b < _num_bins; ++b ) {
    _hist[b] = 0;
  }
  //this could be trouble
  _min = numeric_limits<double>::max();
  _max = numeric_limits<double>::min();

  //  _reset = true;
}

double Stats::Average( ) const
{
  return _sample_sum / (double)_num_samples;
}

double Stats::Min( ) const
{
  return _min;
}

double Stats::Max( ) const
{
  return _max;
}

double Stats::Sum( ) const
{
  return _sample_sum;
}

int Stats::NumSamples( ) const
{
  return _num_samples;
}

void Stats::AddSample( double val )
{
  int b;

  _num_samples++;
  _sample_sum += val;

  _max= (val > _max )?val:_max;
  _min= (val < _min )?val:_min;

  b = (int)floor( val / _bin_size );

  //double clamp between 0 and num_bins
  b = (b < 0 )?0:((b>=_num_bins)?_num_bins - 1:b);

  _hist[b]++;
}

void Stats::AddSample( int val )
{
  AddSample( (double)val );
}

void Stats::Display( ) const
{
  cout << *this << endl;
}

ostream & operator<<(ostream & os, const Stats & s) {
  os << s._hist;
  return os;
}
<commit_msg>add missing initializers for min/max value to stats constructor<commit_after>// $Id$

/*
Copyright (c) 2007-2009, Trustees of The Leland Stanford Junior University
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
Neither the name of the Stanford University nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/*stats.cpp
 *
 *class stores statistics gnerated by the trafficmanager such as the latency
 *hope count of the the flits
 *
 *reset option resets the min and max alues of this statistiscs
 */

#include "booksim.hpp"
#include <iostream>
#include <sstream>
#include <limits>
#include <cmath>
#include <cstdio>

#include "stats.hpp"

Stats::Stats( Module *parent, const string &name,
	      double bin_size, int num_bins ) :
  Module( parent, name ),
   _num_bins( num_bins ), _bin_size( bin_size ), _hist(_num_bins, 0), _num_samples(0), _sample_sum(0.0), _min(numeric_limits<double>::max()), _max(numeric_limits<double>::min())
{

}

void Stats::Clear( )
{
  _num_samples = 0;
  _sample_sum  = 0.0;

  for ( int b = 0; b < _num_bins; ++b ) {
    _hist[b] = 0;
  }
  //this could be trouble
  _min = numeric_limits<double>::max();
  _max = numeric_limits<double>::min();

  //  _reset = true;
}

double Stats::Average( ) const
{
  return _sample_sum / (double)_num_samples;
}

double Stats::Min( ) const
{
  return _min;
}

double Stats::Max( ) const
{
  return _max;
}

double Stats::Sum( ) const
{
  return _sample_sum;
}

int Stats::NumSamples( ) const
{
  return _num_samples;
}

void Stats::AddSample( double val )
{
  int b;

  _num_samples++;
  _sample_sum += val;

  _max= (val > _max )?val:_max;
  _min= (val < _min )?val:_min;

  b = (int)floor( val / _bin_size );

  //double clamp between 0 and num_bins
  b = (b < 0 )?0:((b>=_num_bins)?_num_bins - 1:b);

  _hist[b]++;
}

void Stats::AddSample( int val )
{
  AddSample( (double)val );
}

void Stats::Display( ) const
{
  cout << *this << endl;
}

ostream & operator<<(ostream & os, const Stats & s) {
  os << s._hist;
  return os;
}
<|endoftext|>


<commit_before>/**
 * @file Cosa/RTC.cpp
 * @version 1.0
 *
 * @section License
 * Copyright (C) 2012-2014, Mikael Patel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * This file is part of the Arduino Che Cosa project.
 */

#include "Cosa/RTC.hh"
#include "Cosa/Power.hh"

// Real-Time Clock configuration
#define COUNT 255
#define PRESCALE 64
#define US_PER_TIMER_CYCLE (PRESCALE / I_CPU)
#define US_PER_TICK ((COUNT + 1) * US_PER_TIMER_CYCLE)
#define TICKS_PER_SEC (1000000L / US_PER_TICK)
#define US_PER_SEC_ERROR (1000000L - (TICKS_PER_SEC * US_PER_TICK))

// Initiated state
bool RTC::s_initiated = false;

// Timer ticks counter
volatile uint32_t RTC::s_uticks = 0UL;
volatile uint16_t RTC::s_ticks = 0;
volatile clock_t RTC::s_sec = 0L;
volatile int16_t RTC::s_uerror = 0;

// Timer interrupt extension
RTC::InterruptHandler RTC::s_handler = NULL;
void* RTC::s_env = NULL;

bool
RTC::begin()
{
  if (s_initiated) return (false);
  synchronized {
    // Set prescaling to 64
    TCCR0B = (_BV(CS01) | _BV(CS00));

    // And enable interrupt on overflow
    TIMSK0 = _BV(TOIE0);

    // Reset the counter and clear interrupts
    TCNT0 = 0;
    TIFR0 = 0;
  }
  s_initiated = true;
  ::delay = RTC::delay;
  return (true);
}

bool
RTC::end()
{
  // Disable the timer interrupts
  synchronized {
    TIMSK0 = 0;
  }
  return (true);
}

uint16_t
RTC::us_per_tick()
{
  return (US_PER_TICK);
}

uint16_t
RTC::us_per_timer_cycle()
{
  return (US_PER_TIMER_CYCLE);
}

uint32_t
RTC::micros()
{
  uint32_t res;
  uint8_t cnt;

  // Read tick count and hardware counter. Adjust if pending interrupt
  synchronized {
    res = s_uticks;
    cnt = TCNT0;
    if ((TIFR0 & _BV(TOV0)) && cnt < COUNT) res += US_PER_TICK;
  }

  // Convert ticks to micro-seconds
  res += ((uint32_t) cnt) * US_PER_TIMER_CYCLE;
  return (res);
}

void
RTC::delay(uint32_t ms)
{
  uint32_t start = RTC::millis();
  while (RTC::since(start) < ms) yield();
}

ISR(TIMER0_OVF_vect)
{
  // Increment ticks and check for second count update
  uint16_t ticks = RTC::s_ticks + 1;
  if (RTC::s_uerror >= US_PER_TICK) {
      ticks--;
      RTC::s_uerror -= US_PER_TICK;
  }
  if (ticks == TICKS_PER_SEC) {
    ticks = 0;
    RTC::s_sec += 1;
    RTC::s_uerror += US_PER_SEC_ERROR;
  }
  RTC::s_ticks = ticks;

  // Increment most significant part of micro second counter
  RTC::s_uticks += US_PER_TICK;

  // Check for extension of the interrupt handler
  RTC::InterruptHandler fn = RTC::s_handler;
  if (fn == NULL) return;
  void* env = RTC::s_env;
  fn(env);
}
<commit_msg>Refined<commit_after>/**
 * @file Cosa/RTC.cpp
 * @version 1.0
 *
 * @section License
 * Copyright (C) 2012-2014, Mikael Patel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * This file is part of the Arduino Che Cosa project.
 */

#include "Cosa/RTC.hh"
#include "Cosa/Power.hh"

// Real-Time Clock configuration
#define COUNT 255
#define PRESCALE 64
#define US_PER_TIMER_CYCLE (PRESCALE / I_CPU)
#define US_PER_TICK ((COUNT + 1) * US_PER_TIMER_CYCLE)
#define TICKS_PER_SEC (1000000L / US_PER_TICK)
#define US_PER_SEC_ERROR (1000000L - (TICKS_PER_SEC * US_PER_TICK))

// Initiated state
bool RTC::s_initiated = false;

// Timer ticks counter
volatile uint32_t RTC::s_uticks = 0UL;
volatile uint16_t RTC::s_ticks = 0;
volatile clock_t RTC::s_sec = 0L;
volatile int16_t RTC::s_uerror = 0;

// Timer interrupt extension
RTC::InterruptHandler RTC::s_handler = NULL;
void* RTC::s_env = NULL;

bool
RTC::begin()
{
  if (s_initiated) return (false);
  synchronized {
    // Set prescaling to 64
    TCCR0B = (_BV(CS01) | _BV(CS00));

    // And enable interrupt on overflow
    TIMSK0 = _BV(TOIE0);

    // Reset the counter and clear interrupts
    TCNT0 = 0;
    TIFR0 = 0;
  }
  s_initiated = true;
  ::delay = RTC::delay;
  return (true);
}

bool
RTC::end()
{
  // Disable the timer interrupts
  synchronized {
    TIMSK0 = 0;
  }
  return (true);
}

uint16_t
RTC::us_per_tick()
{
  return (US_PER_TICK);
}

uint16_t
RTC::us_per_timer_cycle()
{
  return (US_PER_TIMER_CYCLE);
}

uint32_t
RTC::micros()
{
  uint32_t res;
  uint8_t cnt;

  // Read tick count and hardware counter. Adjust if pending interrupt
  synchronized {
    res = s_uticks;
    cnt = TCNT0;
    if ((TIFR0 & _BV(TOV0)) && cnt < COUNT) res += US_PER_TICK;
  }

  // Convert ticks to micro-seconds
  res += ((uint32_t) cnt) * US_PER_TIMER_CYCLE;
  return (res);
}

void
RTC::delay(uint32_t ms)
{
  uint32_t start = RTC::millis();
  while (RTC::since(start) < ms) yield();
}

ISR(TIMER0_OVF_vect)
{
  // Increment most significant part of micro second counter
  RTC::s_uticks += US_PER_TICK;

  // Skip tick if accumulated error is greater than tick time
  if (RTC::s_uerror >= US_PER_TICK)
    RTC::s_uerror -= US_PER_TICK;
  else {
    RTC::s_ticks++;
    if (RTC::s_ticks == TICKS_PER_SEC) {
      RTC::s_ticks = 0;
      RTC::s_sec += 1;
      RTC::s_uerror += US_PER_SEC_ERROR;
    }
  }

  // Check for extension of the interrupt handler
  RTC::InterruptHandler fn = RTC::s_handler;
  if (fn == NULL) return;
  void* env = RTC::s_env;
  fn(env);
}
<|endoftext|>


<commit_before>/*************************************************************************/
/*  compression.cpp                                                      */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */
/*                                                                       */
/* 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 "compression.h"

#include "core/io/zip_io.h"
#include "core/os/copymem.h"
#include "core/project_settings.h"

#include "thirdparty/misc/fastlz.h"

#include <zlib.h>
#include <zstd.h>

int Compression::compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size, Mode p_mode) {

	switch (p_mode) {
		case MODE_FASTLZ: {

			if (p_src_size < 16) {
				uint8_t src[16];
				zeromem(&src[p_src_size], 16 - p_src_size);
				copymem(src, p_src, p_src_size);
				return fastlz_compress(src, 16, p_dst);
			} else {
				return fastlz_compress(p_src, p_src_size, p_dst);
			}

		} break;
		case MODE_DEFLATE:
		case MODE_GZIP: {

			int window_bits = p_mode == MODE_DEFLATE ? 15 : 15 + 16;

			z_stream strm;
			strm.zalloc = zipio_alloc;
			strm.zfree = zipio_free;
			strm.opaque = Z_NULL;
			int level = p_mode == MODE_DEFLATE ? zlib_level : gzip_level;
			int err = deflateInit2(&strm, level, Z_DEFLATED, window_bits, 8, Z_DEFAULT_STRATEGY);
			if (err != Z_OK)
				return -1;

			strm.avail_in = p_src_size;
			int aout = deflateBound(&strm, p_src_size);
			strm.avail_out = aout;
			strm.next_in = (Bytef *)p_src;
			strm.next_out = p_dst;
			deflate(&strm, Z_FINISH);
			aout = aout - strm.avail_out;
			deflateEnd(&strm);
			return aout;

		} break;
		case MODE_ZSTD: {
			ZSTD_CCtx *cctx = ZSTD_createCCtx();
			ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, zstd_level);
			if (zstd_long_distance_matching) {
				ZSTD_CCtx_setParameter(cctx, ZSTD_c_enableLongDistanceMatching, 1);
				ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, zstd_window_log_size);
			}
			int max_dst_size = get_max_compressed_buffer_size(p_src_size, MODE_ZSTD);
			int ret = ZSTD_compressCCtx(cctx, p_dst, max_dst_size, p_src, p_src_size, zstd_level);
			ZSTD_freeCCtx(cctx);
			return ret;
		} break;
	}

	ERR_FAIL_V(-1);
}

int Compression::get_max_compressed_buffer_size(int p_src_size, Mode p_mode) {

	switch (p_mode) {
		case MODE_FASTLZ: {

			int ss = p_src_size + p_src_size * 6 / 100;
			if (ss < 66)
				ss = 66;
			return ss;

		} break;
		case MODE_DEFLATE:
		case MODE_GZIP: {

			int window_bits = p_mode == MODE_DEFLATE ? 15 : 15 + 16;

			z_stream strm;
			strm.zalloc = zipio_alloc;
			strm.zfree = zipio_free;
			strm.opaque = Z_NULL;
			int err = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, window_bits, 8, Z_DEFAULT_STRATEGY);
			if (err != Z_OK)
				return -1;
			int aout = deflateBound(&strm, p_src_size);
			deflateEnd(&strm);
			return aout;
		} break;
		case MODE_ZSTD: {

			return ZSTD_compressBound(p_src_size);
		} break;
	}

	ERR_FAIL_V(-1);
}

int Compression::decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p_src, int p_src_size, Mode p_mode) {

	switch (p_mode) {
		case MODE_FASTLZ: {

			int ret_size = 0;

			if (p_dst_max_size < 16) {
				uint8_t dst[16];
				ret_size = fastlz_decompress(p_src, p_src_size, dst, 16);
				copymem(p_dst, dst, p_dst_max_size);
			} else {
				ret_size = fastlz_decompress(p_src, p_src_size, p_dst, p_dst_max_size);
			}
			return ret_size;
		} break;
		case MODE_DEFLATE:
		case MODE_GZIP: {

			int window_bits = p_mode == MODE_DEFLATE ? 15 : 15 + 16;

			z_stream strm;
			strm.zalloc = zipio_alloc;
			strm.zfree = zipio_free;
			strm.opaque = Z_NULL;
			strm.avail_in = 0;
			strm.next_in = Z_NULL;
			int err = inflateInit2(&strm, window_bits);
			ERR_FAIL_COND_V(err != Z_OK, -1);

			strm.avail_in = p_src_size;
			strm.avail_out = p_dst_max_size;
			strm.next_in = (Bytef *)p_src;
			strm.next_out = p_dst;

			err = inflate(&strm, Z_FINISH);
			int total = strm.total_out;
			inflateEnd(&strm);
			ERR_FAIL_COND_V(err != Z_STREAM_END, -1);
			return total;
		} break;
		case MODE_ZSTD: {
			ZSTD_DCtx *dctx = ZSTD_createDCtx();
			if (zstd_long_distance_matching) ZSTD_DCtx_setMaxWindowSize(dctx, (size_t)1 << zstd_window_log_size);
			int ret = ZSTD_decompressDCtx(dctx, p_dst, p_dst_max_size, p_src, p_src_size);
			ZSTD_freeDCtx(dctx);
			return ret;
		} break;
	}

	ERR_FAIL_V(-1);
}

int Compression::zlib_level = Z_DEFAULT_COMPRESSION;
int Compression::gzip_level = Z_DEFAULT_COMPRESSION;
int Compression::zstd_level = 3;
bool Compression::zstd_long_distance_matching = false;
int Compression::zstd_window_log_size = 27;
<commit_msg>Compression: Set Zstd max window size via public parameter<commit_after>/*************************************************************************/
/*  compression.cpp                                                      */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */
/*                                                                       */
/* 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 "compression.h"

#include "core/io/zip_io.h"
#include "core/os/copymem.h"
#include "core/project_settings.h"

#include "thirdparty/misc/fastlz.h"

#include <zlib.h>
#include <zstd.h>

int Compression::compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size, Mode p_mode) {

	switch (p_mode) {
		case MODE_FASTLZ: {

			if (p_src_size < 16) {
				uint8_t src[16];
				zeromem(&src[p_src_size], 16 - p_src_size);
				copymem(src, p_src, p_src_size);
				return fastlz_compress(src, 16, p_dst);
			} else {
				return fastlz_compress(p_src, p_src_size, p_dst);
			}

		} break;
		case MODE_DEFLATE:
		case MODE_GZIP: {

			int window_bits = p_mode == MODE_DEFLATE ? 15 : 15 + 16;

			z_stream strm;
			strm.zalloc = zipio_alloc;
			strm.zfree = zipio_free;
			strm.opaque = Z_NULL;
			int level = p_mode == MODE_DEFLATE ? zlib_level : gzip_level;
			int err = deflateInit2(&strm, level, Z_DEFLATED, window_bits, 8, Z_DEFAULT_STRATEGY);
			if (err != Z_OK)
				return -1;

			strm.avail_in = p_src_size;
			int aout = deflateBound(&strm, p_src_size);
			strm.avail_out = aout;
			strm.next_in = (Bytef *)p_src;
			strm.next_out = p_dst;
			deflate(&strm, Z_FINISH);
			aout = aout - strm.avail_out;
			deflateEnd(&strm);
			return aout;

		} break;
		case MODE_ZSTD: {
			ZSTD_CCtx *cctx = ZSTD_createCCtx();
			ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, zstd_level);
			if (zstd_long_distance_matching) {
				ZSTD_CCtx_setParameter(cctx, ZSTD_c_enableLongDistanceMatching, 1);
				ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, zstd_window_log_size);
			}
			int max_dst_size = get_max_compressed_buffer_size(p_src_size, MODE_ZSTD);
			int ret = ZSTD_compressCCtx(cctx, p_dst, max_dst_size, p_src, p_src_size, zstd_level);
			ZSTD_freeCCtx(cctx);
			return ret;
		} break;
	}

	ERR_FAIL_V(-1);
}

int Compression::get_max_compressed_buffer_size(int p_src_size, Mode p_mode) {

	switch (p_mode) {
		case MODE_FASTLZ: {

			int ss = p_src_size + p_src_size * 6 / 100;
			if (ss < 66)
				ss = 66;
			return ss;

		} break;
		case MODE_DEFLATE:
		case MODE_GZIP: {

			int window_bits = p_mode == MODE_DEFLATE ? 15 : 15 + 16;

			z_stream strm;
			strm.zalloc = zipio_alloc;
			strm.zfree = zipio_free;
			strm.opaque = Z_NULL;
			int err = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, window_bits, 8, Z_DEFAULT_STRATEGY);
			if (err != Z_OK)
				return -1;
			int aout = deflateBound(&strm, p_src_size);
			deflateEnd(&strm);
			return aout;
		} break;
		case MODE_ZSTD: {

			return ZSTD_compressBound(p_src_size);
		} break;
	}

	ERR_FAIL_V(-1);
}

int Compression::decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p_src, int p_src_size, Mode p_mode) {

	switch (p_mode) {
		case MODE_FASTLZ: {

			int ret_size = 0;

			if (p_dst_max_size < 16) {
				uint8_t dst[16];
				ret_size = fastlz_decompress(p_src, p_src_size, dst, 16);
				copymem(p_dst, dst, p_dst_max_size);
			} else {
				ret_size = fastlz_decompress(p_src, p_src_size, p_dst, p_dst_max_size);
			}
			return ret_size;
		} break;
		case MODE_DEFLATE:
		case MODE_GZIP: {

			int window_bits = p_mode == MODE_DEFLATE ? 15 : 15 + 16;

			z_stream strm;
			strm.zalloc = zipio_alloc;
			strm.zfree = zipio_free;
			strm.opaque = Z_NULL;
			strm.avail_in = 0;
			strm.next_in = Z_NULL;
			int err = inflateInit2(&strm, window_bits);
			ERR_FAIL_COND_V(err != Z_OK, -1);

			strm.avail_in = p_src_size;
			strm.avail_out = p_dst_max_size;
			strm.next_in = (Bytef *)p_src;
			strm.next_out = p_dst;

			err = inflate(&strm, Z_FINISH);
			int total = strm.total_out;
			inflateEnd(&strm);
			ERR_FAIL_COND_V(err != Z_STREAM_END, -1);
			return total;
		} break;
		case MODE_ZSTD: {
			ZSTD_DCtx *dctx = ZSTD_createDCtx();
			if (zstd_long_distance_matching) {
				ZSTD_DCtx_setParameter(dctx, ZSTD_d_windowLogMax, zstd_window_log_size);
			}
			int ret = ZSTD_decompressDCtx(dctx, p_dst, p_dst_max_size, p_src, p_src_size);
			ZSTD_freeDCtx(dctx);
			return ret;
		} break;
	}

	ERR_FAIL_V(-1);
}

int Compression::zlib_level = Z_DEFAULT_COMPRESSION;
int Compression::gzip_level = Z_DEFAULT_COMPRESSION;
int Compression::zstd_level = 3;
bool Compression::zstd_long_distance_matching = false;
int Compression::zstd_window_log_size = 27; // ZSTD_WINDOWLOG_LIMIT_DEFAULT
<|endoftext|>


<commit_before>/*************************************************************************/
/*  input_event.cpp                                                      */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                    http://www.godotengine.org                         */
/*************************************************************************/
/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur.                 */
/*                                                                       */
/* 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 "input_event.h"
#include "input_map.h"
#include "os/keyboard.h"
/**
 *
 */

bool InputEvent::operator==(const InputEvent &p_event) const {
	if (type != p_event.type){
		return false;
	}

	switch(type) {
		case KEY:
			return key.unicode == p_event.key.unicode
				&& key.scancode == p_event.key.scancode
				&& key.echo == p_event.key.echo
				&& key.pressed == p_event.key.pressed
				&& key.mod == p_event.key.mod;
		case MOUSE_MOTION:
			return mouse_motion.x == p_event.mouse_motion.x
				&& mouse_motion.y == p_event.mouse_motion.y
				&& mouse_motion.relative_x == p_event.mouse_motion.relative_y
				&& mouse_motion.button_mask == p_event.mouse_motion.button_mask
				&& key.mod == p_event.key.mod;
		case MOUSE_BUTTON:
			return mouse_button.pressed == p_event.mouse_button.pressed
				&& mouse_button.x == p_event.mouse_button.x
				&& mouse_button.y == p_event.mouse_button.y
				&& mouse_button.button_index == p_event.mouse_button.button_index
				&& mouse_button.button_mask == p_event.mouse_button.button_mask
				&& key.mod == p_event.key.mod;
		case JOYSTICK_MOTION:
			return joy_motion.axis == p_event.joy_motion.axis
				&& joy_motion.axis_value == p_event.joy_motion.axis_value;
		case JOYSTICK_BUTTON:
			return joy_button.pressed == p_event.joy_button.pressed
				&& joy_button.button_index == p_event.joy_button.button_index
				&& joy_button.pressure == p_event.joy_button.pressure;
		case SCREEN_TOUCH:
			return screen_touch.pressed == p_event.screen_touch.pressed
				&& screen_touch.index == p_event.screen_touch.index
				&& screen_touch.x == p_event.screen_touch.x
				&& screen_touch.y == p_event.screen_touch.y;
		case SCREEN_DRAG:
			return screen_drag.index == p_event.screen_drag.index
				&& screen_drag.x == p_event.screen_drag.x
				&& screen_drag.y == p_event.screen_drag.y;
		case ACTION:
			return action.action == p_event.action.action
				&& action.pressed == p_event.action.pressed;
	}

	return false;
}
InputEvent::operator String() const {

	String str="Device "+itos(device)+" ID "+itos(ID)+" ";

	switch(type) {

		case NONE: {

			return "Event: None";
		} break;
		case KEY: {

			str+= "Event: Key ";
			str=str+"Unicode: "+String::chr(key.unicode)+" Scan: "+itos( key.scancode )+" Echo: "+String(key.echo?"True":"False")+" Pressed"+String(key.pressed?"True":"False")+" Mod: ";
			if (key.mod.shift)
				str+="S";
			if (key.mod.control)
				str+="C";
			if (key.mod.alt)
				str+="A";
			if (key.mod.meta)
				str+="M";

			return str;
		} break;
		case MOUSE_MOTION: {

			str+= "Event: Motion ";
			str=str+" Pos: " +itos(mouse_motion.x)+","+itos(mouse_motion.y)+" Rel: "+itos(mouse_motion.relative_x)+","+itos(mouse_motion.relative_y)+" Mask: ";
			for (int i=0;i<8;i++) {

				if ((1<<i)&mouse_motion.button_mask)
					str+=itos(i+1);
			}
			str+=" Mod: ";
			if (key.mod.shift)
				str+="S";
			if (key.mod.control)
				str+="C";
			if (key.mod.alt)
				str+="A";
			if (key.mod.meta)
				str+="M";

			return str;
		} break;
		case MOUSE_BUTTON: {
			str+= "Event: Button ";
			str=str+"Pressed: "+itos(mouse_button.pressed)+" Pos: " +itos(mouse_button.x)+","+itos(mouse_button.y)+" Button: "+itos(mouse_button.button_index)+" Mask: ";
			for (int i=0;i<8;i++) {

				if ((1<<i)&mouse_button.button_mask)
					str+=itos(i+1);
			}
			str+=" Mod: ";
			if (key.mod.shift)
				str+="S";
			if (key.mod.control)
				str+="C";
			if (key.mod.alt)
				str+="A";
			if (key.mod.meta)
				str+="M";

			str+=String(" DoubleClick: ")+(mouse_button.doubleclick?"Yes":"No");

			return str;

		} break;
		case JOYSTICK_MOTION: {
			str+= "Event: JoystickMotion ";
			str=str+"Axis: "+itos(joy_motion.axis)+" Value: " +rtos(joy_motion.axis_value);
			return str;

		} break;
		case JOYSTICK_BUTTON: {
			str+= "Event: JoystickButton ";
			str=str+"Pressed: "+itos(joy_button.pressed)+" Index: " +itos(joy_button.button_index)+" pressure "+rtos(joy_button.pressure);
			return str;

		} break;
		case SCREEN_TOUCH: {
			str+= "Event: ScreenTouch ";
			str=str+"Pressed: "+itos(screen_touch.pressed)+" Index: " +itos(screen_touch.index)+" pos "+rtos(screen_touch.x)+","+rtos(screen_touch.y);
			return str;

		} break;
		case SCREEN_DRAG: {
			str+= "Event: ScreenDrag ";
			str=str+" Index: " +itos(screen_drag.index)+" pos "+rtos(screen_drag.x)+","+rtos(screen_drag.y);
			return str;

		} break;
		case ACTION: {
			str+= "Event: Action: "+InputMap::get_singleton()->get_action_from_id(action.action)+" Pressed: "+itos(action.pressed);
			return str;

		} break;

	}

	return "";
}

void InputEvent::set_as_action(const String& p_action, bool p_pressed) {

	type=ACTION;
	action.action=InputMap::get_singleton()->get_action_id(p_action);
	action.pressed=p_pressed;
}

bool InputEvent::is_pressed() const {

	switch(type) {

		case KEY: return key.pressed;
		case MOUSE_BUTTON: return mouse_button.pressed;
		case JOYSTICK_BUTTON: return joy_button.pressed;
		case SCREEN_TOUCH: return screen_touch.pressed;
		case JOYSTICK_MOTION: return InputMap::get_singleton()->event_is_joy_motion_action_pressed(*this);
		case ACTION: return action.pressed;
		default: {}
	}

	return false;
}

bool InputEvent::is_echo() const {

	return (type==KEY && key.echo);
}

bool InputEvent::is_action(const String& p_action) const {

	return InputMap::get_singleton()->event_is_action(*this,p_action);
}

bool InputEvent::is_action_pressed(const String& p_action) const {

	return is_action(p_action) && is_pressed() && !is_echo();
}

bool InputEvent::is_action_released(const String& p_action) const {

	return is_action(p_action) && !is_pressed();
}

uint32_t InputEventKey::get_scancode_with_modifiers() const {

	uint32_t sc=scancode;
	if (mod.control)
		sc|=KEY_MASK_CTRL;
	if (mod.alt)
		sc|=KEY_MASK_ALT;
	if (mod.shift)
		sc|=KEY_MASK_SHIFT;
	if (mod.meta)
		sc|=KEY_MASK_META;

	return sc;

}

InputEvent InputEvent::xform_by(const Matrix32& p_xform) const {

	InputEvent ev=*this;

	switch(ev.type) {

		case InputEvent::MOUSE_BUTTON: {

			Vector2 g = p_xform.xform(Vector2(ev.mouse_button.global_x,ev.mouse_button.global_y));
			Vector2 l = p_xform.xform(Vector2(ev.mouse_button.x,ev.mouse_button.y));
			ev.mouse_button.x=l.x;
			ev.mouse_button.y=l.y;
			ev.mouse_button.global_x=g.x;
			ev.mouse_button.global_y=g.y;

		} break;
		case InputEvent::MOUSE_MOTION: {

			Vector2 g = p_xform.xform(Vector2(ev.mouse_motion.global_x,ev.mouse_motion.global_y));
			Vector2 l = p_xform.xform(Vector2(ev.mouse_motion.x,ev.mouse_motion.y));
			Vector2 r = p_xform.basis_xform(Vector2(ev.mouse_motion.relative_x,ev.mouse_motion.relative_y));
			Vector2 s = p_xform.basis_xform(Vector2(ev.mouse_motion.speed_x,ev.mouse_motion.speed_y));
			ev.mouse_motion.x=l.x;
			ev.mouse_motion.y=l.y;
			ev.mouse_motion.global_x=g.x;
			ev.mouse_motion.global_y=g.y;
			ev.mouse_motion.relative_x=r.x;
			ev.mouse_motion.relative_y=r.y;
			ev.mouse_motion.speed_x=s.x;
			ev.mouse_motion.speed_y=s.y;

		} break;
		case InputEvent::SCREEN_TOUCH: {

			Vector2 t = p_xform.xform(Vector2(ev.screen_touch.x,ev.screen_touch.y));
			ev.screen_touch.x=t.x;
			ev.screen_touch.y=t.y;

		} break;
		case InputEvent::SCREEN_DRAG: {

			Vector2 t = p_xform.xform(Vector2(ev.screen_drag.x,ev.screen_drag.y));
			Vector2 r = p_xform.basis_xform(Vector2(ev.screen_drag.relative_x,ev.screen_drag.relative_y));
			Vector2 s = p_xform.basis_xform(Vector2(ev.screen_drag.speed_x,ev.screen_drag.speed_y));
			ev.screen_drag.x=t.x;
			ev.screen_drag.y=t.y;
			ev.screen_drag.relative_x=r.x;
			ev.screen_drag.relative_y=r.y;
			ev.screen_drag.speed_x=s.x;
			ev.screen_drag.speed_y=s.y;
		} break;
	}

	return ev;
}
<commit_msg>InputEvent: Fix event comparisons when type is NONE<commit_after>/*************************************************************************/
/*  input_event.cpp                                                      */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                    http://www.godotengine.org                         */
/*************************************************************************/
/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur.                 */
/*                                                                       */
/* 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 "input_event.h"
#include "input_map.h"
#include "os/keyboard.h"
/**
 *
 */

bool InputEvent::operator==(const InputEvent &p_event) const {
	if (type != p_event.type){
		return false;
	}

	switch(type) {
		case NONE:
			return true;
		case KEY:
			return key.unicode == p_event.key.unicode
				&& key.scancode == p_event.key.scancode
				&& key.echo == p_event.key.echo
				&& key.pressed == p_event.key.pressed
				&& key.mod == p_event.key.mod;
		case MOUSE_MOTION:
			return mouse_motion.x == p_event.mouse_motion.x
				&& mouse_motion.y == p_event.mouse_motion.y
				&& mouse_motion.relative_x == p_event.mouse_motion.relative_y
				&& mouse_motion.button_mask == p_event.mouse_motion.button_mask
				&& key.mod == p_event.key.mod;
		case MOUSE_BUTTON:
			return mouse_button.pressed == p_event.mouse_button.pressed
				&& mouse_button.x == p_event.mouse_button.x
				&& mouse_button.y == p_event.mouse_button.y
				&& mouse_button.button_index == p_event.mouse_button.button_index
				&& mouse_button.button_mask == p_event.mouse_button.button_mask
				&& key.mod == p_event.key.mod;
		case JOYSTICK_MOTION:
			return joy_motion.axis == p_event.joy_motion.axis
				&& joy_motion.axis_value == p_event.joy_motion.axis_value;
		case JOYSTICK_BUTTON:
			return joy_button.pressed == p_event.joy_button.pressed
				&& joy_button.button_index == p_event.joy_button.button_index
				&& joy_button.pressure == p_event.joy_button.pressure;
		case SCREEN_TOUCH:
			return screen_touch.pressed == p_event.screen_touch.pressed
				&& screen_touch.index == p_event.screen_touch.index
				&& screen_touch.x == p_event.screen_touch.x
				&& screen_touch.y == p_event.screen_touch.y;
		case SCREEN_DRAG:
			return screen_drag.index == p_event.screen_drag.index
				&& screen_drag.x == p_event.screen_drag.x
				&& screen_drag.y == p_event.screen_drag.y;
		case ACTION:
			return action.action == p_event.action.action
				&& action.pressed == p_event.action.pressed;
		default:
			ERR_PRINT("No logic to compare InputEvents of this type, this shouldn't happen.");
	}

	return false;
}
InputEvent::operator String() const {

	String str="Device "+itos(device)+" ID "+itos(ID)+" ";

	switch(type) {

		case NONE: {

			return "Event: None";
		} break;
		case KEY: {

			str+= "Event: Key ";
			str=str+"Unicode: "+String::chr(key.unicode)+" Scan: "+itos( key.scancode )+" Echo: "+String(key.echo?"True":"False")+" Pressed"+String(key.pressed?"True":"False")+" Mod: ";
			if (key.mod.shift)
				str+="S";
			if (key.mod.control)
				str+="C";
			if (key.mod.alt)
				str+="A";
			if (key.mod.meta)
				str+="M";

			return str;
		} break;
		case MOUSE_MOTION: {

			str+= "Event: Motion ";
			str=str+" Pos: " +itos(mouse_motion.x)+","+itos(mouse_motion.y)+" Rel: "+itos(mouse_motion.relative_x)+","+itos(mouse_motion.relative_y)+" Mask: ";
			for (int i=0;i<8;i++) {

				if ((1<<i)&mouse_motion.button_mask)
					str+=itos(i+1);
			}
			str+=" Mod: ";
			if (key.mod.shift)
				str+="S";
			if (key.mod.control)
				str+="C";
			if (key.mod.alt)
				str+="A";
			if (key.mod.meta)
				str+="M";

			return str;
		} break;
		case MOUSE_BUTTON: {
			str+= "Event: Button ";
			str=str+"Pressed: "+itos(mouse_button.pressed)+" Pos: " +itos(mouse_button.x)+","+itos(mouse_button.y)+" Button: "+itos(mouse_button.button_index)+" Mask: ";
			for (int i=0;i<8;i++) {

				if ((1<<i)&mouse_button.button_mask)
					str+=itos(i+1);
			}
			str+=" Mod: ";
			if (key.mod.shift)
				str+="S";
			if (key.mod.control)
				str+="C";
			if (key.mod.alt)
				str+="A";
			if (key.mod.meta)
				str+="M";

			str+=String(" DoubleClick: ")+(mouse_button.doubleclick?"Yes":"No");

			return str;

		} break;
		case JOYSTICK_MOTION: {
			str+= "Event: JoystickMotion ";
			str=str+"Axis: "+itos(joy_motion.axis)+" Value: " +rtos(joy_motion.axis_value);
			return str;

		} break;
		case JOYSTICK_BUTTON: {
			str+= "Event: JoystickButton ";
			str=str+"Pressed: "+itos(joy_button.pressed)+" Index: " +itos(joy_button.button_index)+" pressure "+rtos(joy_button.pressure);
			return str;

		} break;
		case SCREEN_TOUCH: {
			str+= "Event: ScreenTouch ";
			str=str+"Pressed: "+itos(screen_touch.pressed)+" Index: " +itos(screen_touch.index)+" pos "+rtos(screen_touch.x)+","+rtos(screen_touch.y);
			return str;

		} break;
		case SCREEN_DRAG: {
			str+= "Event: ScreenDrag ";
			str=str+" Index: " +itos(screen_drag.index)+" pos "+rtos(screen_drag.x)+","+rtos(screen_drag.y);
			return str;

		} break;
		case ACTION: {
			str+= "Event: Action: "+InputMap::get_singleton()->get_action_from_id(action.action)+" Pressed: "+itos(action.pressed);
			return str;

		} break;

	}

	return "";
}

void InputEvent::set_as_action(const String& p_action, bool p_pressed) {

	type=ACTION;
	action.action=InputMap::get_singleton()->get_action_id(p_action);
	action.pressed=p_pressed;
}

bool InputEvent::is_pressed() const {

	switch(type) {

		case KEY: return key.pressed;
		case MOUSE_BUTTON: return mouse_button.pressed;
		case JOYSTICK_BUTTON: return joy_button.pressed;
		case SCREEN_TOUCH: return screen_touch.pressed;
		case JOYSTICK_MOTION: return InputMap::get_singleton()->event_is_joy_motion_action_pressed(*this);
		case ACTION: return action.pressed;
		default: {}
	}

	return false;
}

bool InputEvent::is_echo() const {

	return (type==KEY && key.echo);
}

bool InputEvent::is_action(const String& p_action) const {

	return InputMap::get_singleton()->event_is_action(*this,p_action);
}

bool InputEvent::is_action_pressed(const String& p_action) const {

	return is_action(p_action) && is_pressed() && !is_echo();
}

bool InputEvent::is_action_released(const String& p_action) const {

	return is_action(p_action) && !is_pressed();
}

uint32_t InputEventKey::get_scancode_with_modifiers() const {

	uint32_t sc=scancode;
	if (mod.control)
		sc|=KEY_MASK_CTRL;
	if (mod.alt)
		sc|=KEY_MASK_ALT;
	if (mod.shift)
		sc|=KEY_MASK_SHIFT;
	if (mod.meta)
		sc|=KEY_MASK_META;

	return sc;

}

InputEvent InputEvent::xform_by(const Matrix32& p_xform) const {

	InputEvent ev=*this;

	switch(ev.type) {

		case InputEvent::MOUSE_BUTTON: {

			Vector2 g = p_xform.xform(Vector2(ev.mouse_button.global_x,ev.mouse_button.global_y));
			Vector2 l = p_xform.xform(Vector2(ev.mouse_button.x,ev.mouse_button.y));
			ev.mouse_button.x=l.x;
			ev.mouse_button.y=l.y;
			ev.mouse_button.global_x=g.x;
			ev.mouse_button.global_y=g.y;

		} break;
		case InputEvent::MOUSE_MOTION: {

			Vector2 g = p_xform.xform(Vector2(ev.mouse_motion.global_x,ev.mouse_motion.global_y));
			Vector2 l = p_xform.xform(Vector2(ev.mouse_motion.x,ev.mouse_motion.y));
			Vector2 r = p_xform.basis_xform(Vector2(ev.mouse_motion.relative_x,ev.mouse_motion.relative_y));
			Vector2 s = p_xform.basis_xform(Vector2(ev.mouse_motion.speed_x,ev.mouse_motion.speed_y));
			ev.mouse_motion.x=l.x;
			ev.mouse_motion.y=l.y;
			ev.mouse_motion.global_x=g.x;
			ev.mouse_motion.global_y=g.y;
			ev.mouse_motion.relative_x=r.x;
			ev.mouse_motion.relative_y=r.y;
			ev.mouse_motion.speed_x=s.x;
			ev.mouse_motion.speed_y=s.y;

		} break;
		case InputEvent::SCREEN_TOUCH: {

			Vector2 t = p_xform.xform(Vector2(ev.screen_touch.x,ev.screen_touch.y));
			ev.screen_touch.x=t.x;
			ev.screen_touch.y=t.y;

		} break;
		case InputEvent::SCREEN_DRAG: {

			Vector2 t = p_xform.xform(Vector2(ev.screen_drag.x,ev.screen_drag.y));
			Vector2 r = p_xform.basis_xform(Vector2(ev.screen_drag.relative_x,ev.screen_drag.relative_y));
			Vector2 s = p_xform.basis_xform(Vector2(ev.screen_drag.speed_x,ev.screen_drag.speed_y));
			ev.screen_drag.x=t.x;
			ev.screen_drag.y=t.y;
			ev.screen_drag.relative_x=r.x;
			ev.screen_drag.relative_y=r.y;
			ev.screen_drag.speed_x=s.x;
			ev.screen_drag.speed_y=s.y;
		} break;
	}

	return ev;
}
<|endoftext|>