<commit_before>/*
   Copyright (C) 2014-2017 Alexandr Akulich <akulichalexander@gmail.com>

   This file is a part of TelegramQt library.

   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.

 */

#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QCommandLineParser>

#include <QJsonDocument>

#include "GeneratorNG.hpp"

enum StatusCode {
    NoError,
    InvalidAction,
    InvalidArgument,
    SchemaReadError,
    UnableToResolveTypes,
    NetworkError,
    ServerError,
    FileAccessError
};

enum SchemaFormat {
    JsonFormat,
    TextFormat,
};

static bool s_dryRun = false;
static bool s_dump = true;

/* Replacing helper */
QString getSectionContent(const QString &fileName, const QString &startMarker, const QString &endMarker, bool *winEol = nullptr)
{
    QFile fileToProcess(fileName);

    if (!fileToProcess.open(QIODevice::ReadOnly))
        return QString();

    QString fileContent = fileToProcess.readAll();
    fileToProcess.close();

    bool winNewLines = fileContent.indexOf(QLatin1String("\r\n")) > 0;

    if (winNewLines) {
        fileContent.replace(QLatin1String("\r\n"), QLatin1String("\n"));
    }

    if (winEol) {
        *winEol = winNewLines;
    }

    int startPos = fileContent.indexOf(startMarker);
    int endPos   = fileContent.indexOf(endMarker);
    if (startPos >= 0) {
        if (endPos < 0) {
            printf("There is only start marker in the file %s. Error.\n", fileName.toLocal8Bit().constData());
            return QString();
        }

        endPos += endMarker.length();
    } else {
        return QString();
    }

    const QString previousContent = fileContent.mid(startPos, endPos - startPos);

    return previousContent;
}

QString getGeneratedContent(const QString &fileName, int spacing, const QString &marker, bool *winEol = nullptr)
{
    const QString space(spacing, QChar(' '));
    return getSectionContent(fileName,
                             QString("%1// Generated %2\n").arg(space).arg(marker),
                             QString("%1// End of generated %2\n").arg(space).arg(marker), winEol);
}

QString getPartiallyGeneratedContent(const QString &fileName, int spacing, const QString &marker, bool *winEol = nullptr)
{
    const QString space(spacing, QChar(' '));
    return getSectionContent(fileName,
                             QString("%1// Partially generated %2\n").arg(space).arg(marker),
                             QString("%1// End of partially generated %2\n").arg(space).arg(marker), winEol);
}

bool replaceSection(const QString &fileName, const QString &startMarker, const QString &endMarker, const QString &newContent)
{
    QFile fileToProcess(fileName);

    if (!fileToProcess.open(QIODevice::ReadOnly))
        return false;

    QString fileContent = fileToProcess.readAll();
    fileToProcess.close();

    bool winNewLines = fileContent.indexOf(QLatin1String("\r\n")) > 0;

    if (winNewLines) {
        fileContent.replace(QLatin1String("\r\n"), QLatin1String("\n"));
    }

    int startPos = fileContent.indexOf(startMarker);
    int endPos   = fileContent.indexOf(endMarker);

    if (startPos >= 0) {
        if (endPos < 0) {
            printf("There is only start marker in the file %s. Error.\n", fileName.toLocal8Bit().constData());
            return false;
        }

        endPos += endMarker.length();
    } else {
        return false;
    }

    const QString previousContent = fileContent.mid(startPos, endPos - startPos);

    const bool changed = previousContent != startMarker + newContent + endMarker;

    if (s_dump) {
        const char *strChanged = "changed";
        const char *strNotChanged = "not changed";

        printf("File: \"%s\", Startmarker: \"%s\", Code (%s):\n%s\n", fileName.toLocal8Bit().constData(), startMarker.trimmed().toLocal8Bit().constData(),
               changed ? strChanged : strNotChanged,
               newContent.toLocal8Bit().constData());
    }

    if (!changed) {
        printf("Nothing to do: new and previous contents are exactly same.\n");
        return true;
    }

    fileContent.remove(startPos, endPos - startPos);
    fileContent.insert(startPos, startMarker + newContent + endMarker);

    if (!s_dryRun) {
        if (!fileToProcess.open(QIODevice::WriteOnly))
            return false;

        if (winNewLines) {
            fileContent.replace(QLatin1String("\n"), QLatin1String("\r\n"));
        }

        fileToProcess.write(fileContent.toLatin1());

        fileToProcess.close();
        printf("Replacing is done.\n");
    } else {
        printf("Replacing is done (dry run).\n");
    }

    return true;
}

bool partialReplacingHelper(const QString &fileName, int spacing, const QString &marker, const QString &newContent)
{
    const QString space(spacing, QChar(' '));

    if (!replaceSection(fileName,
                        QString("%1// Partially generated %2\n").arg(space).arg(marker),
                        QString("%1// End of partially generated %2\n").arg(space).arg(marker), newContent)) {
        printf("Can not update file %s with marker %s.\n", fileName.toLatin1().constData(), marker.toLatin1().constData());
        return false;
    } else {
        return true;
    }
}

bool replacingHelper(const QString &fileName, int spacing, const QString &marker, const QString &newContent)
{
    const QString space(spacing, QChar(' '));

    if (!replaceSection(fileName,
                        QString("%1// Generated %2\n").arg(space).arg(marker),
                        QString("%1// End of generated %2\n").arg(space).arg(marker), newContent)) {
        printf("Can not update file %s with marker %s.\n", fileName.toLatin1().constData(), marker.toLatin1().constData());
        return false;
    } else {
        return true;
    }
}

/* End of replacing helper */

void debugType(const TLType &type)
{
    qDebug() << type.name;
    foreach (const TLSubType &subType, type.subTypes) {
        qDebug() << "    " << subType.name;
        foreach (const TLParam &member, subType.members) {
            qDebug() << "        " << member.type << member.name;
        }
    }
}

StatusCode fetchJson(const QString &specFileName)
{
    QEventLoop eventLoop;
    QNetworkAccessManager mgr;
    QObject::connect(&mgr, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit);

    QNetworkRequest req(QUrl(QLatin1String("https://core.telegram.org/schema/json")));
    QNetworkReply *reply = mgr.get(req);

    eventLoop.exec();

    if (reply->error() != QNetworkReply::NoError) {
        delete reply;
        return NetworkError;
    }

    QByteArray data = reply->readAll();
    delete reply;

    if (data.isEmpty()) {
        return ServerError;
    }

    QFile specsOutFile(specFileName);
    if (!specsOutFile.open(QIODevice::WriteOnly)) {
        return FileAccessError;
    }

    QJsonDocument document = QJsonDocument::fromJson(data);
    specsOutFile.write(document.toJson());
    specsOutFile.close();

    printf("Spec file successfully downloaded (and formatted).\n");
    return NoError;
}

StatusCode format(const QString &specFileName)
{
    QFile specsFile(specFileName);
    if (!specsFile.open(QIODevice::ReadOnly)) {
        return FileAccessError;
    }

    QByteArray data = specsFile.readAll();

    specsFile.close();

    if (!specsFile.open(QIODevice::WriteOnly)) {
        return FileAccessError;
    }

    QJsonDocument document = QJsonDocument::fromJson(data);
    specsFile.write(document.toJson());
    specsFile.close();

    printf("Spec file successfully formatted.\n");
    return NoError;
}

StatusCode generate(SchemaFormat format, const QString &specFileName)
{
    QFile specsFile(specFileName);
    if (!specsFile.open(QIODevice::ReadOnly)) {
        qWarning() << "Unable to open spec file" << specFileName << "in" << QDir().absolutePath();
        return InvalidArgument;
    }

    const QByteArray data = specsFile.readAll();

    if (data.isEmpty()) {
        qWarning() << "Unable to read spec file" << specFileName;
        return InvalidArgument;
    }

    specsFile.close();

    GeneratorNG generator;

    bool success = true;

    switch (format) {
    case JsonFormat:
        success = generator.loadFromJson(data);
        break;
    case TextFormat:
        success = generator.loadFromText(data);
        break;
    }

    if (!success) {
        qWarning() << "Unable to parse schema";
        return SchemaReadError;
    }

    if (!generator.resolveTypes()) {
        qWarning() << "Unable to resolve types";
        return UnableToResolveTypes;
    }

    generator.existsStreamReadTemplateInstancing = getGeneratedContent(QStringLiteral("../CTelegramStream.cpp"), 0, QLatin1String("vector read templates instancing"));
    generator.existsStreamWriteTemplateInstancing = getGeneratedContent(QStringLiteral("../CTelegramStream.cpp"), 0, QLatin1String("vector write templates instancing"));
    generator.setExistsRpcProcessDefinitions(getPartiallyGeneratedContent(QStringLiteral("../CTelegramConnection.cpp"),
                                                                          0,
                                                                          QStringLiteral("Telegram API RPC process implementation")));
    generator.generate();

    replacingHelper(QLatin1String("../TLValues.hpp"), 8, QLatin1String("TLValues"), generator.codeOfTLValues);
    replacingHelper(QLatin1String("../TLTypes.hpp"), 0, QLatin1String("TLTypes"), generator.codeOfTLTypes);
    replacingHelper(QLatin1String("../CTelegramStream.hpp"), 4, QLatin1String("read operators"), generator.codeStreamReadDeclarations);
    replacingHelper(QLatin1String("../CTelegramStream.cpp"), 0, QLatin1String("read operators implementation"), generator.codeStreamReadDefinitions);
    replacingHelper(QLatin1String("../CTelegramStream.cpp"), 0, QLatin1String("vector read templates instancing"), generator.codeStreamReadTemplateInstancing);
    replacingHelper(QLatin1String("../CTelegramStream.hpp"), 4, QLatin1String("write operators"), generator.codeStreamWriteDeclarations);
    replacingHelper(QLatin1String("../CTelegramStream.cpp"), 0, QLatin1String("write operators implementation"), generator.codeStreamWriteDefinitions);
    replacingHelper(QLatin1String("../CTelegramStream.cpp"), 0, QLatin1String("vector write templates instancing"), generator.codeStreamWriteTemplateInstancing);
    replacingHelper(QLatin1String("../CTelegramConnection.hpp"), 4, QLatin1String("Telegram API methods declaration"), generator.codeConnectionDeclarations);
    replacingHelper(QLatin1String("../CTelegramConnection.cpp"), 0, QLatin1String("Telegram API methods implementation"), generator.codeConnectionDefinitions);

    replacingHelper(QLatin1String("../CTelegramConnection.hpp"), 4, QLatin1String("Telegram API RPC process declarations"), generator.codeRpcProcessDeclarations);
    partialReplacingHelper(QLatin1String("../CTelegramConnection.cpp"), 0, QLatin1String("Telegram API RPC process implementation"), generator.codeRpcProcessDefinitions);
    replacingHelper(QLatin1String("../CTelegramConnection.cpp"), 8, QLatin1String("RPC processing switch cases"), generator.codeRpcProcessSwitchCases);
    replacingHelper(QLatin1String("../CTelegramConnection.cpp"), 8, QLatin1String("RPC processing switch updates cases"), generator.codeRpcProcessSwitchUpdatesCases);

    replacingHelper(QLatin1String("../TLTypesDebug.hpp"), 0, QLatin1String("TLTypes debug operators"), generator.codeDebugWriteDeclarations);
    replacingHelper(QLatin1String("../TLTypesDebug.cpp"), 0, QLatin1String("TLTypes debug operators"), generator.codeDebugWriteDefinitions);

    replacingHelper(QLatin1String("../TLRpcDebug.cpp"), 4, QLatin1String("RPC debug cases"), generator.codeDebugRpcParse);

    printf("Spec file successfully used for generation.\n");
    return NoError;
}

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QCommandLineParser parser;
    parser.addHelpOption();

    QCommandLineOption dryRunOption(QStringLiteral("dry-run"));
    parser.addOption(dryRunOption);

    QCommandLineOption dumpOption(QStringLiteral("dump"));
    parser.addOption(dumpOption);

    QCommandLineOption fetchJsonOption(QStringLiteral("fetch-json"));
    parser.addOption(fetchJsonOption);

    QCommandLineOption formatJsonOption(QStringLiteral("format-json"));
    parser.addOption(formatJsonOption);

    QCommandLineOption generateFromJsonOption(QStringLiteral("generate-from-json"));
    parser.addOption(generateFromJsonOption);

    QCommandLineOption generateFromTextOption(QStringLiteral("generate-from-text"));
    parser.addOption(generateFromTextOption);

    parser.addPositionalArgument(QStringLiteral("spec"), QStringLiteral("The specification file (text or json)"));

    parser.process(app);

    if (parser.positionalArguments().count() != 1) {
        parser.showHelp(InvalidArgument);
    }

    s_dryRun = parser.isSet(dryRunOption);
    s_dump = parser.isSet(dumpOption);

    const QString fileName = parser.positionalArguments().first();

    StatusCode code;

    if (parser.isSet(fetchJsonOption)) {
        code = fetchJson(fileName);
        if (code != NoError) {
            return code;
        }
    }

    if (parser.isSet(formatJsonOption)) {
        code = format(fileName);
        if (code != NoError) {
            return code;
        }
    }

    if (parser.isSet(generateFromJsonOption)) {
        code = generate(JsonFormat, fileName);
        if (code != NoError) {
            return code;
        }
    }

    if (parser.isSet(generateFromTextOption)) {
        code = generate(TextFormat, fileName);
        if (code != NoError) {
            return code;
        }
    }

    return code;
}
<commit_msg>GeneratorNG: Rename a variable<commit_after>/*
   Copyright (C) 2014-2017 Alexandr Akulich <akulichalexander@gmail.com>

   This file is a part of TelegramQt library.

   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.

 */

#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QCommandLineParser>

#include <QJsonDocument>

#include "GeneratorNG.hpp"

enum StatusCode {
    NoError,
    InvalidAction,
    InvalidArgument,
    SchemaReadError,
    UnableToResolveTypes,
    NetworkError,
    ServerError,
    FileAccessError
};

enum SchemaFormat {
    JsonFormat,
    TextFormat,
};

static bool s_dryRun = false;
static bool s_dump = true;

/* Replacing helper */
QString getSectionContent(const QString &fileName, const QString &startMarker, const QString &endMarker, bool *winEol = nullptr)
{
    QFile fileToProcess(fileName);

    if (!fileToProcess.open(QIODevice::ReadOnly))
        return QString();

    QString fileContent = fileToProcess.readAll();
    fileToProcess.close();

    bool winNewLines = fileContent.indexOf(QLatin1String("\r\n")) > 0;

    if (winNewLines) {
        fileContent.replace(QLatin1String("\r\n"), QLatin1String("\n"));
    }

    if (winEol) {
        *winEol = winNewLines;
    }

    int startPos = fileContent.indexOf(startMarker);
    int endPos   = fileContent.indexOf(endMarker);
    if (startPos >= 0) {
        if (endPos < 0) {
            printf("There is only start marker in the file %s. Error.\n", fileName.toLocal8Bit().constData());
            return QString();
        }

        endPos += endMarker.length();
    } else {
        return QString();
    }

    const QString previousContent = fileContent.mid(startPos, endPos - startPos);

    return previousContent;
}

QString getGeneratedContent(const QString &fileName, int spacing, const QString &marker, bool *winEol = nullptr)
{
    const QString space(spacing, QChar(' '));
    return getSectionContent(fileName,
                             QString("%1// Generated %2\n").arg(space).arg(marker),
                             QString("%1// End of generated %2\n").arg(space).arg(marker), winEol);
}

QString getPartiallyGeneratedContent(const QString &fileName, int spacing, const QString &marker, bool *winEol = nullptr)
{
    const QString space(spacing, QChar(' '));
    return getSectionContent(fileName,
                             QString("%1// Partially generated %2\n").arg(space).arg(marker),
                             QString("%1// End of partially generated %2\n").arg(space).arg(marker), winEol);
}

bool replaceSection(const QString &fileName, const QString &startMarker, const QString &endMarker, const QString &newContent)
{
    QFile fileToProcess(fileName);

    if (!fileToProcess.open(QIODevice::ReadOnly))
        return false;

    QString fileContent = fileToProcess.readAll();
    fileToProcess.close();

    bool winNewLines = fileContent.indexOf(QLatin1String("\r\n")) > 0;

    if (winNewLines) {
        fileContent.replace(QLatin1String("\r\n"), QLatin1String("\n"));
    }

    int startPos = fileContent.indexOf(startMarker);
    int endPos   = fileContent.indexOf(endMarker);

    if (startPos >= 0) {
        if (endPos < 0) {
            printf("There is only start marker in the file %s. Error.\n", fileName.toLocal8Bit().constData());
            return false;
        }

        endPos += endMarker.length();
    } else {
        return false;
    }

    const QString previousContent = fileContent.mid(startPos, endPos - startPos);

    const bool changed = previousContent != startMarker + newContent + endMarker;

    if (s_dump) {
        const char *strChanged = "changed";
        const char *strNotChanged = "not changed";

        printf("File: \"%s\", Startmarker: \"%s\", Code (%s):\n%s\n", fileName.toLocal8Bit().constData(), startMarker.trimmed().toLocal8Bit().constData(),
               changed ? strChanged : strNotChanged,
               newContent.toLocal8Bit().constData());
    }

    if (!changed) {
        printf("Nothing to do: new and previous contents are exactly same.\n");
        return true;
    }

    fileContent.remove(startPos, endPos - startPos);
    fileContent.insert(startPos, startMarker + newContent + endMarker);

    if (!s_dryRun) {
        if (!fileToProcess.open(QIODevice::WriteOnly))
            return false;

        if (winNewLines) {
            fileContent.replace(QLatin1String("\n"), QLatin1String("\r\n"));
        }

        fileToProcess.write(fileContent.toLatin1());

        fileToProcess.close();
        printf("Replacing is done.\n");
    } else {
        printf("Replacing is done (dry run).\n");
    }

    return true;
}

bool partialReplacingHelper(const QString &fileName, int spacing, const QString &marker, const QString &newContent)
{
    const QString space(spacing, QChar(' '));

    if (!replaceSection(fileName,
                        QString("%1// Partially generated %2\n").arg(space).arg(marker),
                        QString("%1// End of partially generated %2\n").arg(space).arg(marker), newContent)) {
        printf("Can not update file %s with marker %s.\n", fileName.toLatin1().constData(), marker.toLatin1().constData());
        return false;
    } else {
        return true;
    }
}

bool replacingHelper(const QString &fileName, int spacing, const QString &marker, const QString &newContent)
{
    const QString space(spacing, QChar(' '));

    if (!replaceSection(fileName,
                        QString("%1// Generated %2\n").arg(space).arg(marker),
                        QString("%1// End of generated %2\n").arg(space).arg(marker), newContent)) {
        printf("Can not update file %s with marker %s.\n", fileName.toLatin1().constData(), marker.toLatin1().constData());
        return false;
    } else {
        return true;
    }
}

/* End of replacing helper */

void debugType(const TLType &type)
{
    qDebug() << type.name;
    foreach (const TLSubType &subType, type.subTypes) {
        qDebug() << "    " << subType.name;
        foreach (const TLParam &member, subType.members) {
            qDebug() << "        " << member.type << member.name;
        }
    }
}

StatusCode fetchJson(const QString &specFileName)
{
    QEventLoop eventLoop;
    QNetworkAccessManager mgr;
    QObject::connect(&mgr, &QNetworkAccessManager::finished, &eventLoop, &QEventLoop::quit);

    QNetworkRequest req(QUrl(QLatin1String("https://core.telegram.org/schema/json")));
    QNetworkReply *reply = mgr.get(req);

    eventLoop.exec();

    if (reply->error() != QNetworkReply::NoError) {
        delete reply;
        return NetworkError;
    }

    QByteArray data = reply->readAll();
    delete reply;

    if (data.isEmpty()) {
        return ServerError;
    }

    QFile specsOutFile(specFileName);
    if (!specsOutFile.open(QIODevice::WriteOnly)) {
        return FileAccessError;
    }

    QJsonDocument document = QJsonDocument::fromJson(data);
    specsOutFile.write(document.toJson());
    specsOutFile.close();

    printf("Spec file successfully downloaded (and formatted).\n");
    return NoError;
}

StatusCode format(const QString &specFileName)
{
    QFile specsFile(specFileName);
    if (!specsFile.open(QIODevice::ReadOnly)) {
        return FileAccessError;
    }

    QByteArray data = specsFile.readAll();

    specsFile.close();

    if (!specsFile.open(QIODevice::WriteOnly)) {
        return FileAccessError;
    }

    QJsonDocument document = QJsonDocument::fromJson(data);
    specsFile.write(document.toJson());
    specsFile.close();

    printf("Spec file successfully formatted.\n");
    return NoError;
}

StatusCode generate(SchemaFormat format, const QString &specFileName)
{
    QFile specsFile(specFileName);
    if (!specsFile.open(QIODevice::ReadOnly)) {
        qWarning() << "Unable to open spec file" << specFileName << "in" << QDir().absolutePath();
        return InvalidArgument;
    }

    const QByteArray data = specsFile.readAll();

    if (data.isEmpty()) {
        qWarning() << "Unable to read spec file" << specFileName;
        return InvalidArgument;
    }

    specsFile.close();

    GeneratorNG generator;

    bool success = true;

    switch (format) {
    case JsonFormat:
        success = generator.loadFromJson(data);
        break;
    case TextFormat:
        success = generator.loadFromText(data);
        break;
    }

    if (!success) {
        qWarning() << "Unable to parse schema";
        return SchemaReadError;
    }

    if (!generator.resolveTypes()) {
        qWarning() << "Unable to resolve types";
        return UnableToResolveTypes;
    }

    generator.existsStreamReadTemplateInstancing = getGeneratedContent(QStringLiteral("../CTelegramStream.cpp"), 0, QLatin1String("vector read templates instancing"));
    generator.existsStreamWriteTemplateInstancing = getGeneratedContent(QStringLiteral("../CTelegramStream.cpp"), 0, QLatin1String("vector write templates instancing"));
    generator.setExistsRpcProcessDefinitions(getPartiallyGeneratedContent(QStringLiteral("../CTelegramConnection.cpp"),
                                                                          0,
                                                                          QStringLiteral("Telegram API RPC process implementation")));
    generator.generate();

    replacingHelper(QLatin1String("../TLValues.hpp"), 8, QLatin1String("TLValues"), generator.codeOfTLValues);
    replacingHelper(QLatin1String("../TLTypes.hpp"), 0, QLatin1String("TLTypes"), generator.codeOfTLTypes);
    replacingHelper(QLatin1String("../CTelegramStream.hpp"), 4, QLatin1String("read operators"), generator.codeStreamReadDeclarations);
    replacingHelper(QLatin1String("../CTelegramStream.cpp"), 0, QLatin1String("read operators implementation"), generator.codeStreamReadDefinitions);
    replacingHelper(QLatin1String("../CTelegramStream.cpp"), 0, QLatin1String("vector read templates instancing"), generator.codeStreamReadTemplateInstancing);
    replacingHelper(QLatin1String("../CTelegramStream.hpp"), 4, QLatin1String("write operators"), generator.codeStreamWriteDeclarations);
    replacingHelper(QLatin1String("../CTelegramStream.cpp"), 0, QLatin1String("write operators implementation"), generator.codeStreamWriteDefinitions);
    replacingHelper(QLatin1String("../CTelegramStream.cpp"), 0, QLatin1String("vector write templates instancing"), generator.codeStreamWriteTemplateInstancing);
    replacingHelper(QLatin1String("../CTelegramConnection.hpp"), 4, QLatin1String("Telegram API methods declaration"), generator.codeConnectionDeclarations);
    replacingHelper(QLatin1String("../CTelegramConnection.cpp"), 0, QLatin1String("Telegram API methods implementation"), generator.codeConnectionDefinitions);

    replacingHelper(QLatin1String("../CTelegramConnection.hpp"), 4, QLatin1String("Telegram API RPC process declarations"), generator.codeRpcProcessDeclarations);
    partialReplacingHelper(QLatin1String("../CTelegramConnection.cpp"), 0, QLatin1String("Telegram API RPC process implementation"), generator.codeRpcProcessDefinitions);
    replacingHelper(QLatin1String("../CTelegramConnection.cpp"), 8, QLatin1String("RPC processing switch cases"), generator.codeRpcProcessSwitchCases);
    replacingHelper(QLatin1String("../CTelegramConnection.cpp"), 8, QLatin1String("RPC processing switch updates cases"), generator.codeRpcProcessSwitchUpdatesCases);

    replacingHelper(QLatin1String("../TLTypesDebug.hpp"), 0, QLatin1String("TLTypes debug operators"), generator.codeDebugWriteDeclarations);
    replacingHelper(QLatin1String("../TLTypesDebug.cpp"), 0, QLatin1String("TLTypes debug operators"), generator.codeDebugWriteDefinitions);

    replacingHelper(QLatin1String("../TLRpcDebug.cpp"), 4, QLatin1String("RPC debug cases"), generator.codeDebugRpcParse);

    printf("Spec file successfully used for generation.\n");
    return NoError;
}

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QCommandLineParser parser;
    parser.addHelpOption();

    QCommandLineOption dryRunOption(QStringLiteral("dry-run"));
    parser.addOption(dryRunOption);

    QCommandLineOption dumpOption(QStringLiteral("dump"));
    parser.addOption(dumpOption);

    QCommandLineOption fetchJsonOption(QStringLiteral("fetch-json"));
    parser.addOption(fetchJsonOption);

    QCommandLineOption formatJsonOption(QStringLiteral("format-json"));
    parser.addOption(formatJsonOption);

    QCommandLineOption generateFromJsonOption(QStringLiteral("generate-from-json"));
    parser.addOption(generateFromJsonOption);

    QCommandLineOption generateFromTextOption(QStringLiteral("generate-from-text"));
    parser.addOption(generateFromTextOption);

    parser.addPositionalArgument(QStringLiteral("spec"), QStringLiteral("The specification file (text or json)"));

    parser.process(app);

    if (parser.positionalArguments().count() != 1) {
        parser.showHelp(InvalidArgument);
    }

    s_dryRun = parser.isSet(dryRunOption);
    s_dump = parser.isSet(dumpOption);

    const QString specFileName = parser.positionalArguments().first();

    StatusCode code;

    if (parser.isSet(fetchJsonOption)) {
        code = fetchJson(specFileName);
        if (code != NoError) {
            return code;
        }
    }

    if (parser.isSet(formatJsonOption)) {
        code = format(specFileName);
        if (code != NoError) {
            return code;
        }
    }

    if (parser.isSet(generateFromJsonOption)) {
        code = generate(JsonFormat, specFileName);
        if (code != NoError) {
            return code;
        }
    }

    if (parser.isSet(generateFromTextOption)) {
        code = generate(TextFormat, specFileName);
        if (code != NoError) {
            return code;
        }
    }

    return code;
}
<|endoftext|>


<commit_before>/*
 * This file is part of TelepathyQt4
 *
 * Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
 * Copyright (C) 2010 Nokia Corporation
 *
 * 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.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt4/AccountFactory>

#include <TelepathyQt4/Account>

namespace Tp
{

/**
 * \class AccountFactory
 * \ingroup clientaccount
 * \headerfile TelepathyQt4/account-factory.h <TelepathyQt4/AccountFactory>
 *
 * \brief Constructs Account objects according to application-defined settings
 *
 * The AccountFactory class is used by AccountManager and other classes which construct Account
 * proxy instances to enable sharing instances of application-defined Account subclasses with
 * certain features always ready.
 */

/**
 * Creates a new AccountFactory.
 *
 * Optionally, the \a features to make ready on all constructed proxies can be specified. The
 * default is to make Account::FeatureCore ready. It should be noted that unlike
 * Account::becomeReady(), FeatureCore isn't assumed. If no features are specified, no
 * Account::becomeReady() call is made at all and the proxy won't be Account::isReady().
 *
 * \param bus The QDBusConnection for proxies constructed using this factory to use.
 * \param features The features to make ready on constructed Accounts.
 * \returns A pointer to the created factory.
 */
AccountFactoryPtr AccountFactory::create(const QDBusConnection &bus, const Features &features)
{
    return AccountFactoryPtr(new AccountFactory(bus, features));
}

/**
 * Class constructor.
 *
 * As in create(), it should be noted that unlike Account::becomeReady(), FeatureCore isn't assumed.
 * If no \a features are specified, no Account::becomeReady() call is made at all and the proxy
 * won't be Account::isReady().
 *
 * \param bus The QDBusConnection for proxies constructed using this factory to use.
 * \param features The features to make ready on constructed Accounts.
 */
AccountFactory::AccountFactory(const QDBusConnection &bus, const Features &features)
    : FixedFeatureFactory(bus)
{
    addFeatures(features);
}

/**
 * Class destructor.
 */
AccountFactory::~AccountFactory()
{
}

/**
 * Constructs an Account proxy and begins making it ready.
 *
 * If a valid proxy already exists in the factory cache for the given combination of \a busName and
 * \a objectPath, it is returned instead. All newly created proxies are automatically cached until
 * they're either DBusProxy::invalidated() or the last reference to them outside the factory has
 * been dropped.
 *
 * The proxy can be accessed immediately after this function returns using PendingReady::proxy().
 * The ready operation only finishes, however, when the features specified by features(), if any,
 * are made ready as much as possible. If the service doesn't support a given feature, they won't
 * obviously be ready even if the operation finished successfully, as is the case for
 * Account::becomeReady().
 *
 * \param busName The bus/service name of the D-Bus account object the proxy is constructed for.
 * (Usually TELEPATHY_ACCOUNT_MANAGER_BUS_NAME).
 * \param objectPath The object path of the account.
 * \param connFactory The connection factory to use for the Account.
 * \param chanFactory The channel factory to use for the Account.
 * \return A PendingReady operation with the proxy in PendingReady::proxy().
 */
PendingReady *AccountFactory::proxy(const QString &busName, const QString &objectPath,
            const ConnectionFactoryConstPtr &connFactory,
            const ChannelFactoryConstPtr &chanFactory) const
{
    SharedPtr<RefCounted> proxy = cachedProxy(busName, objectPath);
    if (!proxy) {
        proxy = construct(busName, objectPath, connFactory, chanFactory);
    }

    return nowHaveProxy(proxy);
}

/**
 * Identity transform, as is appropriate for Account objects.
 */
QString AccountFactory::finalBusNameFrom(const QString &uniqueOrWellKnown) const
{
    return uniqueOrWellKnown;
}

/**
 * Can be used by subclasses to override the Account subclass constructed by the factory.
 *
 * This is automatically called by proxy() to construct proxy instances if no valid cached proxy is
 * found.
 *
 * \param busName The bus/service name of the D-Bus account object the proxy is constructed for.
 * (Usually TELEPATHY_ACCOUNT_MANAGER_BUS_NAME).
 * \param objectPath The object path of the account.
 * \param connFactory The connection factory to use for the Account.
 * \param chanFactory The channel factory to use for the Account.
 * \return A pointer to the constructed proxy.
 */
AccountPtr AccountFactory::construct(const QString &busName, const QString &objectPath,
        const ConnectionFactoryConstPtr &connFactory,
        const ChannelFactoryConstPtr &chanFactory) const
{
    return Account::create(dbusConnection(), busName, objectPath, connFactory, chanFactory);
}

}
<commit_msg>Reorder AccountFactory::{construct,finalBusNameFrom} impls to be consistent with the header<commit_after>/*
 * This file is part of TelepathyQt4
 *
 * Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
 * Copyright (C) 2010 Nokia Corporation
 *
 * 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.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt4/AccountFactory>

#include <TelepathyQt4/Account>

namespace Tp
{

/**
 * \class AccountFactory
 * \ingroup clientaccount
 * \headerfile TelepathyQt4/account-factory.h <TelepathyQt4/AccountFactory>
 *
 * \brief Constructs Account objects according to application-defined settings
 *
 * The AccountFactory class is used by AccountManager and other classes which construct Account
 * proxy instances to enable sharing instances of application-defined Account subclasses with
 * certain features always ready.
 */

/**
 * Creates a new AccountFactory.
 *
 * Optionally, the \a features to make ready on all constructed proxies can be specified. The
 * default is to make Account::FeatureCore ready. It should be noted that unlike
 * Account::becomeReady(), FeatureCore isn't assumed. If no features are specified, no
 * Account::becomeReady() call is made at all and the proxy won't be Account::isReady().
 *
 * \param bus The QDBusConnection for proxies constructed using this factory to use.
 * \param features The features to make ready on constructed Accounts.
 * \returns A pointer to the created factory.
 */
AccountFactoryPtr AccountFactory::create(const QDBusConnection &bus, const Features &features)
{
    return AccountFactoryPtr(new AccountFactory(bus, features));
}

/**
 * Class constructor.
 *
 * As in create(), it should be noted that unlike Account::becomeReady(), FeatureCore isn't assumed.
 * If no \a features are specified, no Account::becomeReady() call is made at all and the proxy
 * won't be Account::isReady().
 *
 * \param bus The QDBusConnection for proxies constructed using this factory to use.
 * \param features The features to make ready on constructed Accounts.
 */
AccountFactory::AccountFactory(const QDBusConnection &bus, const Features &features)
    : FixedFeatureFactory(bus)
{
    addFeatures(features);
}

/**
 * Class destructor.
 */
AccountFactory::~AccountFactory()
{
}

/**
 * Constructs an Account proxy and begins making it ready.
 *
 * If a valid proxy already exists in the factory cache for the given combination of \a busName and
 * \a objectPath, it is returned instead. All newly created proxies are automatically cached until
 * they're either DBusProxy::invalidated() or the last reference to them outside the factory has
 * been dropped.
 *
 * The proxy can be accessed immediately after this function returns using PendingReady::proxy().
 * The ready operation only finishes, however, when the features specified by features(), if any,
 * are made ready as much as possible. If the service doesn't support a given feature, they won't
 * obviously be ready even if the operation finished successfully, as is the case for
 * Account::becomeReady().
 *
 * \param busName The bus/service name of the D-Bus account object the proxy is constructed for.
 * (Usually TELEPATHY_ACCOUNT_MANAGER_BUS_NAME).
 * \param objectPath The object path of the account.
 * \param connFactory The connection factory to use for the Account.
 * \param chanFactory The channel factory to use for the Account.
 * \return A PendingReady operation with the proxy in PendingReady::proxy().
 */
PendingReady *AccountFactory::proxy(const QString &busName, const QString &objectPath,
            const ConnectionFactoryConstPtr &connFactory,
            const ChannelFactoryConstPtr &chanFactory) const
{
    SharedPtr<RefCounted> proxy = cachedProxy(busName, objectPath);
    if (!proxy) {
        proxy = construct(busName, objectPath, connFactory, chanFactory);
    }

    return nowHaveProxy(proxy);
}

/**
 * Can be used by subclasses to override the Account subclass constructed by the factory.
 *
 * This is automatically called by proxy() to construct proxy instances if no valid cached proxy is
 * found.
 *
 * \param busName The bus/service name of the D-Bus account object the proxy is constructed for.
 * (Usually TELEPATHY_ACCOUNT_MANAGER_BUS_NAME).
 * \param objectPath The object path of the account.
 * \param connFactory The connection factory to use for the Account.
 * \param chanFactory The channel factory to use for the Account.
 * \return A pointer to the constructed proxy.
 */
AccountPtr AccountFactory::construct(const QString &busName, const QString &objectPath,
        const ConnectionFactoryConstPtr &connFactory,
        const ChannelFactoryConstPtr &chanFactory) const
{
    return Account::create(dbusConnection(), busName, objectPath, connFactory, chanFactory);
}

/**
 * Identity transform, as is appropriate for Account objects.
 */
QString AccountFactory::finalBusNameFrom(const QString &uniqueOrWellKnown) const
{
    return uniqueOrWellKnown;
}

}
<|endoftext|>


<commit_before>// easyxml.cpp - implementation of EasyXML interfaces.

#pragma warning( disable : 4786 )

#include <string.h>		// strcmp()
#include <fstream>
using namespace std;

#include "easyxml.hpp"
#include "xmlparse.h"
#include "widestring.h"

////////////////////////////////////////////////////////////////////////
// Implementation of XMLAttributes.
////////////////////////////////////////////////////////////////////////

XMLAttributes::XMLAttributes ()
{
}

XMLAttributes::~XMLAttributes ()
{
}

int XMLAttributes::findAttribute (const char * name) const
{
	int s = size();
	for (int i = 0; i < s; i++) {
		if (strcmp(name, getName(i)) == 0)
			return i;
	}
	return -1;
}

bool XMLAttributes::hasAttribute (const char * name) const
{
	return (findAttribute(name) != -1);
}

const char *XMLAttributes::getValue (const char * name) const
{
	int pos = findAttribute(name);
	if (pos >= 0)
		return getValue(pos);
	else
		return 0;
}

////////////////////////////////////////////////////////////////////////
// Implementation of XMLAttributesDefault.
////////////////////////////////////////////////////////////////////////

XMLAttributesDefault::XMLAttributesDefault ()
{
}

XMLAttributesDefault::XMLAttributesDefault (const XMLAttributes &atts)
{
	int s = atts.size();
	for (int i = 0; i < s; i++)
		addAttribute(atts.getName(i), atts.getValue(i));
}

XMLAttributesDefault::~XMLAttributesDefault ()
{
}

int XMLAttributesDefault::size () const
{
	return _atts.size() / 2;
}

const char *XMLAttributesDefault::getName (int i) const
{
	return _atts[i*2].c_str();
}

const char *XMLAttributesDefault::getValue (int i) const
{
	return _atts[i*2+1].c_str();
}

void XMLAttributesDefault::addAttribute (const char * name, const char * value)
{
	_atts.push_back(name);
	_atts.push_back(value);
}

void XMLAttributesDefault::setName (int i, const char * name)
{
	_atts[i*2] = name;
}

void XMLAttributesDefault::setValue (int i, const char * name)
{
	_atts[i*2+1] = name;
}

void XMLAttributesDefault::setValue (const char * name, const char * value)
{
	int pos = findAttribute(name);
	if (pos >= 0) {
		setName(pos, name);
		setValue(pos, value);
	} else {
		addAttribute(name, value);
	}
}

////////////////////////////////////////////////////////////////////////
// Attribute list wrapper for Expat.
////////////////////////////////////////////////////////////////////////

class ExpatAtts : public XMLAttributes
{
public:
	ExpatAtts (const char ** atts) : _atts(atts) {}

	virtual int size () const;
	virtual const char * getName (int i) const;
	virtual const char * getValue (int i) const;

private:
	const char ** _atts;
};

int ExpatAtts::size () const
{
	int s = 0;
	for (int i = 0; _atts[i] != 0; i += 2)
		s++;
	return s;
}

const char *ExpatAtts::getName (int i) const
{
	return _atts[i*2];
}

const char *ExpatAtts::getValue (int i) const
{
	return _atts[i*2+1];
}

////////////////////////////////////////////////////////////////////////
// Static callback functions for Expat.
////////////////////////////////////////////////////////////////////////

#define VISITOR (*((XMLVisitor *)userData))

static void start_element (void * userData, const char * name, const char ** atts)
{
	VISITOR.startElement(name, ExpatAtts(atts));
}

static void end_element (void * userData, const char * name)
{
	VISITOR.endElement(name);
}

static void character_data (void * userData, const char * s, int len)
{
	VISITOR.data(s, len);
}

static void processing_instruction (void * userData,
			const char * target,
			const char * data)
{
	VISITOR.pi(target, data);
}

#undef VISITOR

////////////////////////////////////////////////////////////////////////
// Implementation of XMLReader.
////////////////////////////////////////////////////////////////////////

/**
 * Read and parse the XML from an istream.
 */
void readXML (istream &input, XMLVisitor &visitor, const string &path,
			  bool progress_callback(int))
{
	XML_Parser parser = XML_ParserCreate(0);
	XML_SetUserData(parser, &visitor);
	XML_SetElementHandler(parser, start_element, end_element);
	XML_SetCharacterDataHandler(parser, character_data);
	XML_SetProcessingInstructionHandler(parser, processing_instruction);

	visitor.startXML();

	int progress = 0;
	char buf[16384];
	while (!input.eof())
	{
		// FIXME: get proper error string from system
		if (!input.good())
		{
			int CurrentLineNumber = XML_GetCurrentLineNumber(parser);
			int CurrentColumnNumber = XML_GetCurrentColumnNumber(parser);
			XML_ParserFree(parser);
			throw xh_io_exception("Problem reading file",
					xh_location(path,
					CurrentLineNumber,
					CurrentColumnNumber),
					"XML Parser");
		}

		input.read(buf,16384);
		if (!XML_Parse(parser, buf, input.gcount(), false))
		{
			const XML_LChar *message = XML_ErrorString(XML_GetErrorCode(parser));
			int line = XML_GetCurrentLineNumber(parser);
			int col = XML_GetCurrentColumnNumber(parser);
			XML_ParserFree(parser);
			throw xh_io_exception(message,
					xh_location(path, line, col),
					"XML Parser");
		}
		if (progress_callback != NULL)
		{
			progress++;
			if (progress == 400)
				progress = 0;
			progress_callback(progress/4);
		}
	}

	// Verify end of document.
	if (!XML_Parse(parser, buf, 0, true)) {
		int CurrentLineNumber = XML_GetCurrentLineNumber(parser);
		int CurrentColumnNumber = XML_GetCurrentColumnNumber(parser);
		XML_ParserFree(parser);
		throw xh_io_exception(XML_ErrorString(XML_GetErrorCode(parser)),
				xh_location(path,
							CurrentLineNumber,
							CurrentColumnNumber),
				"XML Parser");
	}

	XML_ParserFree(parser);
}

/**
 * Read and parse the XML from a file.
 */
void readXML (const string &path_utf8, XMLVisitor &visitor,
			  bool progress_callback(int))
{
	FILE *fp;
#if WIN32
	// For Windows we need to convert the utf-8 path to either multi-byte
	//  (which might fail in some cases) or wide characters (wchar_t).
	// The latter is better.
	widestring fn;
	fn.from_utf8(path_utf8.c_str());
	fp = _wfopen(fn.c_str(), L"rb");
#elif __DARWIN_OSX__
	// Mac OS X already likes utf-8.
	fp = fopen(path_utf8.c_str(), "rb");
#else
	// some other Unix flavor
	widestring fn;
	fn.from_utf8(path_utf8.c_str());
	fp = fopen(fn.mb_str(), "rb");
#endif
	if (!fp)
		throw xh_io_exception("Failed to open file", xh_location(path_utf8),
					"XML Parser");

	// If it is not compressed, we can get the length of the file
	int iFileLength = -1;
	if (progress_callback != NULL)
	{
		const char *path_cstr = path_utf8.c_str();

		// Not compressed if: filename does not end with "gz"
		if (strncmp(path_cstr+path_utf8.length()-2, "gz", 2))
		{
			fseek(fp, 0, SEEK_END);
			iFileLength = ftell(fp);
		}
	}

#ifdef _MSC_VER
	int fd = _fileno(fp);
#else
	int fd = fileno(fp);
#endif

	// Ensure that underlying fd isd rewound
	lseek(fd, 0, SEEK_SET);

	gzFile gfp = gzdopen(fd, "rb");

	if (!gfp)
		throw xh_io_exception("Failed to open file", xh_location(path_utf8),
					"XML Parser");
	try
	{
		readCompressedXML(gfp, visitor, path_utf8, iFileLength, progress_callback);
	}
	catch (xh_io_exception &e)
	{
			gzclose(gfp);
			throw e;
	}
	catch (xh_throwable &t)
	{
			gzclose(gfp);
			throw t;
	}
	// If it gets here, it succeeded
	gzclose(gfp);
}

void readCompressedXML (gzFile fp, XMLVisitor &visitor, const string& path,
						int iFileLength, bool progress_callback(int))
{
	XML_Parser parser = XML_ParserCreate(0);
	XML_SetUserData(parser, &visitor);
	XML_SetElementHandler(parser, start_element, end_element);
	XML_SetCharacterDataHandler(parser, character_data);
	XML_SetProcessingInstructionHandler(parser, processing_instruction);

	visitor.startXML();

	const int BUFSIZE = 8192;
	int progress = 0;
	char buf[8192];
	while (!gzeof(fp))
	{
		int iError;
		gzerror(fp, &iError);
		int iCount = gzread(fp, buf, BUFSIZE);
		gzerror(fp, &iError);
		if (iCount > 0)
		{
			if (!XML_Parse(parser, buf, iCount, false))
			{
				const XML_LChar *message = XML_ErrorString(XML_GetErrorCode(parser));
				int line = XML_GetCurrentLineNumber(parser);
				int col = XML_GetCurrentColumnNumber(parser);
				XML_ParserFree(parser);
				throw xh_io_exception(message,
						xh_location(path, line, col),
						"XML Parser");
			}
			if (progress_callback != NULL)
			{
				if (iFileLength != -1)
				{
					// We know the length, so we can estimate total progress
					progress += iCount;
					// beware integer overflow, use doubles
					double prog = (float)progress * 99.0 / iFileLength;
					progress_callback((int) prog);
				}
				else
				{
					// Give a gradually advancing progress that wraps around
					progress++;
					if (progress == 400)
						progress = 0;
					progress_callback(progress/4);
				}
			}
		}
		else if (iCount < 0)
		{
			int CurrentLineNumber = XML_GetCurrentLineNumber(parser);
			int CurrentColumnNumber = XML_GetCurrentColumnNumber(parser);
			XML_ParserFree(parser);
			throw xh_io_exception("Problem reading file",
					xh_location(path,
					CurrentLineNumber,
					CurrentColumnNumber),
					"XML Parser");
		}
	}

	// Verify end of document.
	if (!XML_Parse(parser, buf, 0, true))
	{
		XML_Error errcode = XML_GetErrorCode(parser);
		const XML_LChar *errstr = XML_ErrorString(errcode);
		int line = XML_GetCurrentLineNumber(parser);
		int column = XML_GetCurrentColumnNumber(parser);

		XML_ParserFree(parser);

		throw xh_io_exception(errstr,
				xh_location(path,
							line,
							column),
				"XML Parser");
	}

	XML_ParserFree(parser);
}

<commit_msg>added io.h for windows<commit_after>// easyxml.cpp - implementation of EasyXML interfaces.

#pragma warning( disable : 4786 )

#include <string.h>		// strcmp()
#include <fstream>
using namespace std;

#if WIN32
#include <io.h>
#endif

#include "easyxml.hpp"
#include "xmlparse.h"
#include "widestring.h"

////////////////////////////////////////////////////////////////////////
// Implementation of XMLAttributes.
////////////////////////////////////////////////////////////////////////

XMLAttributes::XMLAttributes ()
{
}

XMLAttributes::~XMLAttributes ()
{
}

int XMLAttributes::findAttribute (const char * name) const
{
	int s = size();
	for (int i = 0; i < s; i++) {
		if (strcmp(name, getName(i)) == 0)
			return i;
	}
	return -1;
}

bool XMLAttributes::hasAttribute (const char * name) const
{
	return (findAttribute(name) != -1);
}

const char *XMLAttributes::getValue (const char * name) const
{
	int pos = findAttribute(name);
	if (pos >= 0)
		return getValue(pos);
	else
		return 0;
}

////////////////////////////////////////////////////////////////////////
// Implementation of XMLAttributesDefault.
////////////////////////////////////////////////////////////////////////

XMLAttributesDefault::XMLAttributesDefault ()
{
}

XMLAttributesDefault::XMLAttributesDefault (const XMLAttributes &atts)
{
	int s = atts.size();
	for (int i = 0; i < s; i++)
		addAttribute(atts.getName(i), atts.getValue(i));
}

XMLAttributesDefault::~XMLAttributesDefault ()
{
}

int XMLAttributesDefault::size () const
{
	return _atts.size() / 2;
}

const char *XMLAttributesDefault::getName (int i) const
{
	return _atts[i*2].c_str();
}

const char *XMLAttributesDefault::getValue (int i) const
{
	return _atts[i*2+1].c_str();
}

void XMLAttributesDefault::addAttribute (const char * name, const char * value)
{
	_atts.push_back(name);
	_atts.push_back(value);
}

void XMLAttributesDefault::setName (int i, const char * name)
{
	_atts[i*2] = name;
}

void XMLAttributesDefault::setValue (int i, const char * name)
{
	_atts[i*2+1] = name;
}

void XMLAttributesDefault::setValue (const char * name, const char * value)
{
	int pos = findAttribute(name);
	if (pos >= 0) {
		setName(pos, name);
		setValue(pos, value);
	} else {
		addAttribute(name, value);
	}
}

////////////////////////////////////////////////////////////////////////
// Attribute list wrapper for Expat.
////////////////////////////////////////////////////////////////////////

class ExpatAtts : public XMLAttributes
{
public:
	ExpatAtts (const char ** atts) : _atts(atts) {}

	virtual int size () const;
	virtual const char * getName (int i) const;
	virtual const char * getValue (int i) const;

private:
	const char ** _atts;
};

int ExpatAtts::size () const
{
	int s = 0;
	for (int i = 0; _atts[i] != 0; i += 2)
		s++;
	return s;
}

const char *ExpatAtts::getName (int i) const
{
	return _atts[i*2];
}

const char *ExpatAtts::getValue (int i) const
{
	return _atts[i*2+1];
}

////////////////////////////////////////////////////////////////////////
// Static callback functions for Expat.
////////////////////////////////////////////////////////////////////////

#define VISITOR (*((XMLVisitor *)userData))

static void start_element (void * userData, const char * name, const char ** atts)
{
	VISITOR.startElement(name, ExpatAtts(atts));
}

static void end_element (void * userData, const char * name)
{
	VISITOR.endElement(name);
}

static void character_data (void * userData, const char * s, int len)
{
	VISITOR.data(s, len);
}

static void processing_instruction (void * userData,
			const char * target,
			const char * data)
{
	VISITOR.pi(target, data);
}

#undef VISITOR

////////////////////////////////////////////////////////////////////////
// Implementation of XMLReader.
////////////////////////////////////////////////////////////////////////

/**
 * Read and parse the XML from an istream.
 */
void readXML (istream &input, XMLVisitor &visitor, const string &path,
			  bool progress_callback(int))
{
	XML_Parser parser = XML_ParserCreate(0);
	XML_SetUserData(parser, &visitor);
	XML_SetElementHandler(parser, start_element, end_element);
	XML_SetCharacterDataHandler(parser, character_data);
	XML_SetProcessingInstructionHandler(parser, processing_instruction);

	visitor.startXML();

	int progress = 0;
	char buf[16384];
	while (!input.eof())
	{
		// FIXME: get proper error string from system
		if (!input.good())
		{
			int CurrentLineNumber = XML_GetCurrentLineNumber(parser);
			int CurrentColumnNumber = XML_GetCurrentColumnNumber(parser);
			XML_ParserFree(parser);
			throw xh_io_exception("Problem reading file",
					xh_location(path,
					CurrentLineNumber,
					CurrentColumnNumber),
					"XML Parser");
		}

		input.read(buf,16384);
		if (!XML_Parse(parser, buf, input.gcount(), false))
		{
			const XML_LChar *message = XML_ErrorString(XML_GetErrorCode(parser));
			int line = XML_GetCurrentLineNumber(parser);
			int col = XML_GetCurrentColumnNumber(parser);
			XML_ParserFree(parser);
			throw xh_io_exception(message,
					xh_location(path, line, col),
					"XML Parser");
		}
		if (progress_callback != NULL)
		{
			progress++;
			if (progress == 400)
				progress = 0;
			progress_callback(progress/4);
		}
	}

	// Verify end of document.
	if (!XML_Parse(parser, buf, 0, true)) {
		int CurrentLineNumber = XML_GetCurrentLineNumber(parser);
		int CurrentColumnNumber = XML_GetCurrentColumnNumber(parser);
		XML_ParserFree(parser);
		throw xh_io_exception(XML_ErrorString(XML_GetErrorCode(parser)),
				xh_location(path,
							CurrentLineNumber,
							CurrentColumnNumber),
				"XML Parser");
	}

	XML_ParserFree(parser);
}

/**
 * Read and parse the XML from a file.
 */
void readXML (const string &path_utf8, XMLVisitor &visitor,
			  bool progress_callback(int))
{
	FILE *fp;
#if WIN32
	// For Windows we need to convert the utf-8 path to either multi-byte
	//  (which might fail in some cases) or wide characters (wchar_t).
	// The latter is better.
	widestring fn;
	fn.from_utf8(path_utf8.c_str());
	fp = _wfopen(fn.c_str(), L"rb");
#elif __DARWIN_OSX__
	// Mac OS X already likes utf-8.
	fp = fopen(path_utf8.c_str(), "rb");
#else
	// some other Unix flavor
	widestring fn;
	fn.from_utf8(path_utf8.c_str());
	fp = fopen(fn.mb_str(), "rb");
#endif
	if (!fp)
		throw xh_io_exception("Failed to open file", xh_location(path_utf8),
					"XML Parser");

	// If it is not compressed, we can get the length of the file
	int iFileLength = -1;
	if (progress_callback != NULL)
	{
		const char *path_cstr = path_utf8.c_str();

		// Not compressed if: filename does not end with "gz"
		if (strncmp(path_cstr+path_utf8.length()-2, "gz", 2))
		{
			fseek(fp, 0, SEEK_END);
			iFileLength = ftell(fp);
		}
	}

#ifdef _MSC_VER
	int fd = _fileno(fp);
#else
	int fd = fileno(fp);
#endif

	// Ensure that underlying fd isd rewound
	lseek(fd, 0, SEEK_SET);

	gzFile gfp = gzdopen(fd, "rb");

	if (!gfp)
		throw xh_io_exception("Failed to open file", xh_location(path_utf8),
					"XML Parser");
	try
	{
		readCompressedXML(gfp, visitor, path_utf8, iFileLength, progress_callback);
	}
	catch (xh_io_exception &e)
	{
			gzclose(gfp);
			throw e;
	}
	catch (xh_throwable &t)
	{
			gzclose(gfp);
			throw t;
	}
	// If it gets here, it succeeded
	gzclose(gfp);
}

void readCompressedXML (gzFile fp, XMLVisitor &visitor, const string& path,
						int iFileLength, bool progress_callback(int))
{
	XML_Parser parser = XML_ParserCreate(0);
	XML_SetUserData(parser, &visitor);
	XML_SetElementHandler(parser, start_element, end_element);
	XML_SetCharacterDataHandler(parser, character_data);
	XML_SetProcessingInstructionHandler(parser, processing_instruction);

	visitor.startXML();

	const int BUFSIZE = 8192;
	int progress = 0;
	char buf[8192];
	while (!gzeof(fp))
	{
		int iError;
		gzerror(fp, &iError);
		int iCount = gzread(fp, buf, BUFSIZE);
		gzerror(fp, &iError);
		if (iCount > 0)
		{
			if (!XML_Parse(parser, buf, iCount, false))
			{
				const XML_LChar *message = XML_ErrorString(XML_GetErrorCode(parser));
				int line = XML_GetCurrentLineNumber(parser);
				int col = XML_GetCurrentColumnNumber(parser);
				XML_ParserFree(parser);
				throw xh_io_exception(message,
						xh_location(path, line, col),
						"XML Parser");
			}
			if (progress_callback != NULL)
			{
				if (iFileLength != -1)
				{
					// We know the length, so we can estimate total progress
					progress += iCount;
					// beware integer overflow, use doubles
					double prog = (float)progress * 99.0 / iFileLength;
					progress_callback((int) prog);
				}
				else
				{
					// Give a gradually advancing progress that wraps around
					progress++;
					if (progress == 400)
						progress = 0;
					progress_callback(progress/4);
				}
			}
		}
		else if (iCount < 0)
		{
			int CurrentLineNumber = XML_GetCurrentLineNumber(parser);
			int CurrentColumnNumber = XML_GetCurrentColumnNumber(parser);
			XML_ParserFree(parser);
			throw xh_io_exception("Problem reading file",
					xh_location(path,
					CurrentLineNumber,
					CurrentColumnNumber),
					"XML Parser");
		}
	}

	// Verify end of document.
	if (!XML_Parse(parser, buf, 0, true))
	{
		XML_Error errcode = XML_GetErrorCode(parser);
		const XML_LChar *errstr = XML_ErrorString(errcode);
		int line = XML_GetCurrentLineNumber(parser);
		int column = XML_GetCurrentColumnNumber(parser);

		XML_ParserFree(parser);

		throw xh_io_exception(errstr,
				xh_location(path,
							line,
							column),
				"XML Parser");
	}

	XML_ParserFree(parser);
}

<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2005 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */
#if defined(_MSC_VER)
// turn off bogus `this used in base member initialization list'
#  pragma warning(disable: 4786)
#endif

#include "global.h"

const struct GlobalDBItem globalDBItems[] = {
  { "_agilityAdVel",		"2.25",				false, StateDatabase::Locked},
  { "_agilityTimeWindow",	"1.0",				false, StateDatabase::Locked},
  { "_agilityVelDelta",		"0.3",				false, StateDatabase::Locked},
  { "_angleTolerance",		"0.05",				false, StateDatabase::Locked},
  { "_angularAd",		"1.5",				false, StateDatabase::Locked},
  { "_avenueSize",		"2.0*_boxBase",			false, StateDatabase::Locked},
  { "_baseSize",		"60.0",				false, StateDatabase::Locked},
  { "_boxBase",			"30.0",				false, StateDatabase::Locked},
  { "_boxHeight",		"6.0*_muzzleHeight",		false, StateDatabase::Locked},
  { "_burrowAngularAd",		"0.55",				false, StateDatabase::Locked},
  { "_burrowDepth",		"-1.32",			false, StateDatabase::Locked},
  { "_burrowSpeedAd",		"0.80",				false, StateDatabase::Locked},
  { "_coldetDepth",		"6",				false, StateDatabase::Locked},
  { "_coldetElements",		"4",				false, StateDatabase::Locked},
  { "_cullDepth",		"6",				false, StateDatabase::Locked},
  { "_cullElements",		"16",				false, StateDatabase::Locked},
  { "_cullOccluders",		"0",				false, StateDatabase::Locked},
  { "_disableBots",		"0",				false, StateDatabase::Locked},
  { "_drawCelestial",		"1",				false, StateDatabase::Locked},
  { "_drawClouds",		"1",				false, StateDatabase::Locked},
  { "_drawGround",		"1",				false, StateDatabase::Locked},
  { "_drawMountains",		"1",				false, StateDatabase::Locked},
  { "_drawSky",			"1",				false, StateDatabase::Locked},
  { "_endShotDetection",	"5",				false, StateDatabase::Locked},
  { "_explodeTime",		"5.0",				false, StateDatabase::Locked},
  { "_flagAltitude",		"11.0",				false, StateDatabase::Locked},
  { "_flagEffectTime",		"0.64",				false, StateDatabase::Locked},
  { "_flagHeight",		"10.0",				false, StateDatabase::Locked},
  { "_flagPoleWidth",		"0.025",			false, StateDatabase::Locked},
  { "_flagPoleSize",		"0.8",				false, StateDatabase::Locked},
  { "_flagRadius",		"2.5",				false, StateDatabase::Locked},
  { "_friction",		"0",				false, StateDatabase::Locked},
  { "_gmActivationTime",	"0.5",				false, StateDatabase::Locked},
  { "_gmAdLife",		"0.95",				false, StateDatabase::Locked},
  { "_gmTurnAngle",		"0.628319",			false, StateDatabase::Locked},
  { "_gravity",			"-9.8",				false, StateDatabase::Locked},
  { "_handicapScoreDiff",	"50.0",				false, StateDatabase::Locked},
  { "_handicapVelAd",		"2.0",				false, StateDatabase::Locked},
  { "_handicapAngAd",		"1.5",				false, StateDatabase::Locked},
  { "_handicapShotAd",		"1.75",				false, StateDatabase::Locked},
  { "_identifyRange",		"50.0",				false, StateDatabase::Locked},
  { "_jumpVelocity",		"19.0",				false, StateDatabase::Locked},
  { "_laserAdLife",		"0.1",				false, StateDatabase::Locked},
  { "_laserAdRate",		"0.5",				false, StateDatabase::Locked},
  { "_laserAdVel",		"1000.0",			false, StateDatabase::Locked},
  { "_latitude",		"37.5",				false, StateDatabase::Locked},
  { "_lockOnAngle",		"0.15",				false, StateDatabase::Locked},
  { "_longitude",		"122",				false, StateDatabase::Locked},
  { "_lRAdRate",		"0.5",				false, StateDatabase::Locked},
  { "_maxBumpHeight",		"0.33",				false, StateDatabase::Locked},
  { "_maxFlagGrabs",		"4.0",				false, StateDatabase::Locked},
  { "_maxLOD",			"32767.0",			false, StateDatabase::Locked},
  { "_mirror",			"none",				false, StateDatabase::Locked},
  { "_momentumAngAcc",		"1.0",				false, StateDatabase::Locked},
  { "_momentumLinAcc",		"1.0",				false, StateDatabase::Locked},
  { "_momentumFriction",	"0",				false, StateDatabase::Locked},
  { "_mGunAdLife",		"1.0 / _mGunAdRate",		false, StateDatabase::Locked},
  { "_mGunAdRate",		"10.0",				false, StateDatabase::Locked},
  { "_mGunAdVel",		"1.5",				false, StateDatabase::Locked},
  { "_muzzleFront",		"_tankRadius + 0.1",		false, StateDatabase::Locked},
  { "_muzzleHeight",		"1.57",				false, StateDatabase::Locked},
  { "_noClimb",			"1",				false, StateDatabase::Locked},
  { "_noShadows",		"0",				false, StateDatabase::Locked},
  { "_noSmallPackets",		"0",				false, StateDatabase::Locked},
  { "_notRespondingTime",	"5.0",				false, StateDatabase::Locked},
  { "_obeseFactor",		"2.5",				false, StateDatabase::Locked},
  { "_pauseDropTime",		"15.0",				false, StateDatabase::Locked},
  { "_positionTolerance",	"0.09",				false, StateDatabase::Locked},
  { "_pyrBase",			"4.0*_tankHeight",		false, StateDatabase::Locked},
  { "_pyrHeight",		"5.0*_tankHeight",		false, StateDatabase::Locked},
  { "_rainBaseColor",		"none",				false, StateDatabase::Locked},
  { "_radarLimit",		"_worldSize",			false, StateDatabase::Locked},
  { "_rainRoofs",		"1",				false, StateDatabase::Locked},
  { "_rainDensity",		"none",				false, StateDatabase::Locked},
  { "_rainEndZ",		"none",				false, StateDatabase::Locked},
  { "_rainMaxPuddleTime",	"none",				false, StateDatabase::Locked},
  { "_rainPuddleSpeed",		"none",				false, StateDatabase::Locked},
  { "_rainPuddleColor",		"none",				false, StateDatabase::Locked},
  { "_rainPuddleTexture",	"none",				false, StateDatabase::Locked},
  { "_rainSpread",		"none",				false, StateDatabase::Locked},
  { "_rainSpeed",		"none",				false, StateDatabase::Locked},
  { "_rainSpeedMod",		"none",				false, StateDatabase::Locked},
  { "_rainSpins",		"none",				false, StateDatabase::Locked},
  { "_rainStartZ",		"none",				false, StateDatabase::Locked},
  { "_rainTexture",		"none",				false, StateDatabase::Locked},
  { "_rainTopColor",		"none",				false, StateDatabase::Locked},
  { "_rainType",		"none",				false, StateDatabase::Locked},
  { "_rejoinTime",		"_explodeTime",			false, StateDatabase::Locked},
  { "_reloadTime",		"_shotRange / _shotSpeed",	false, StateDatabase::Locked},
  { "_rFireAdLife",		"1.0 / _rFireAdRate",		false, StateDatabase::Locked},
  { "_rFireAdRate",		"2.0",				false, StateDatabase::Locked},
  { "_rFireAdVel",		"1.5",				false, StateDatabase::Locked},
  { "_shieldFlight",		"2.7",				false, StateDatabase::Locked},
  { "_shockAdLife",		"0.2",				false, StateDatabase::Locked},
  { "_shockInRadius",		"_tankLength",			false, StateDatabase::Locked},
  { "_shockOutRadius",		"60.0",				false, StateDatabase::Locked},
  { "_shotTailLength",		"4.0",				false, StateDatabase::Locked},
  { "_shotRadius",		"0.5",				false, StateDatabase::Locked},
  { "_shotRange",		"350.0",			false, StateDatabase::Locked},
  { "_shotSpeed",		"100.0",			false, StateDatabase::Locked},
  { "_shotsKeepVerticalVelocity",	"0",			false, StateDatabase::Locked},
  { "_skyColor",		"white",			false, StateDatabase::Locked},
  { "_srRadiusMult",		"2.0",				false, StateDatabase::Locked},
  { "_squishFactor",		"1.0",				false, StateDatabase::Locked},
  { "_squishTime",		"1.0",				false, StateDatabase::Locked},
  { "_syncTime",		"-1.0",				false, StateDatabase::Locked},
  { "_syncLocation",		"0",				false, StateDatabase::Locked},
  { "_tankExplosionSize",	"3.5 * _tankLength",		false, StateDatabase::Locked},
  { "_tankAngVel",		"0.785398",			false, StateDatabase::Locked},
  { "_tankHeight",		"2.05",				false, StateDatabase::Locked},
  { "_tankLength",		"6.0",				false, StateDatabase::Locked},
  { "_tankRadius",		"0.72 * _tankLength",		false, StateDatabase::Locked},
  { "_tankSpeed",		"25.0",				false, StateDatabase::Locked},
  { "_tankWidth",		"2.8",				false, StateDatabase::Locked},
  { "_targetingAngle",		"0.3",				false, StateDatabase::Locked},
  { "_teleportBreadth",		"4.48",				false, StateDatabase::Locked},
  { "_teleportHeight",		"10.08",			false, StateDatabase::Locked},
  { "_teleportTime",		"1.0",				false, StateDatabase::Locked},
  { "_teleportWidth",		"1.12",				false, StateDatabase::Locked},
  { "_thiefAdLife",		"0.05",				false, StateDatabase::Locked},
  { "_thiefAdRate",		"12.0",				false, StateDatabase::Locked},
  { "_thiefAdShotVel",		"8.0",				false, StateDatabase::Locked},
  { "_thiefTinyFactor",		"0.5",				false, StateDatabase::Locked},
  { "_thiefVelAd",		"1.67",				false, StateDatabase::Locked},
  { "_thiefDropTime",		"_reloadTime * 0.5",		false, StateDatabase::Locked},
  { "_tinyFactor",		"0.4",				false, StateDatabase::Locked},
  { "_trackFade",		"3.0",				false, StateDatabase::Locked},
  { "_updateThrottleRate",	"30.0",				false, StateDatabase::Locked},
  { "_useLineRain",		"none",				false, StateDatabase::Locked},
  { "_useRainPuddles",		"none",				false, StateDatabase::Locked},
  { "_useRainBillboards",	"none",				false, StateDatabase::Locked},
  { "_velocityAd",		"1.5",				false, StateDatabase::Locked},
  { "_wallHeight",		"3.0*_tankHeight",		false, StateDatabase::Locked},
  { "_weapons",			"1",				false, StateDatabase::Locked},
  { "_wideAngleAng",		"1.745329",			false, StateDatabase::Locked},
  { "_wingsGravity",		"0.5*_gravity",			false, StateDatabase::Locked},
  { "_wingsJumpCount",		"1",				false, StateDatabase::Locked},
  { "_wingsJumpVelocity",	"0.5*_jumpVelocity",		false, StateDatabase::Locked},
  { "_wingsSlideTime",		"1.0",				false, StateDatabase::Locked},
  { "_worldSize",		"800.0",			false, StateDatabase::Locked}

};
const unsigned int	numGlobalDBItems = countof(globalDBItems);

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>revert _wings var changes<commit_after>/* bzflag
 * Copyright (c) 1993 - 2005 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named LICENSE that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */
#if defined(_MSC_VER)
// turn off bogus `this used in base member initialization list'
#  pragma warning(disable: 4786)
#endif

#include "global.h"

const struct GlobalDBItem globalDBItems[] = {
  { "_agilityAdVel",		"2.25",				false, StateDatabase::Locked},
  { "_agilityTimeWindow",	"1.0",				false, StateDatabase::Locked},
  { "_agilityVelDelta",		"0.3",				false, StateDatabase::Locked},
  { "_angleTolerance",		"0.05",				false, StateDatabase::Locked},
  { "_angularAd",		"1.5",				false, StateDatabase::Locked},
  { "_avenueSize",		"2.0*_boxBase",			false, StateDatabase::Locked},
  { "_baseSize",		"60.0",				false, StateDatabase::Locked},
  { "_boxBase",			"30.0",				false, StateDatabase::Locked},
  { "_boxHeight",		"6.0*_muzzleHeight",		false, StateDatabase::Locked},
  { "_burrowAngularAd",		"0.55",				false, StateDatabase::Locked},
  { "_burrowDepth",		"-1.32",			false, StateDatabase::Locked},
  { "_burrowSpeedAd",		"0.80",				false, StateDatabase::Locked},
  { "_coldetDepth",		"6",				false, StateDatabase::Locked},
  { "_coldetElements",		"4",				false, StateDatabase::Locked},
  { "_cullDepth",		"6",				false, StateDatabase::Locked},
  { "_cullElements",		"16",				false, StateDatabase::Locked},
  { "_cullOccluders",		"0",				false, StateDatabase::Locked},
  { "_disableBots",		"0",				false, StateDatabase::Locked},
  { "_drawCelestial",		"1",				false, StateDatabase::Locked},
  { "_drawClouds",		"1",				false, StateDatabase::Locked},
  { "_drawGround",		"1",				false, StateDatabase::Locked},
  { "_drawMountains",		"1",				false, StateDatabase::Locked},
  { "_drawSky",			"1",				false, StateDatabase::Locked},
  { "_endShotDetection",	"5",				false, StateDatabase::Locked},
  { "_explodeTime",		"5.0",				false, StateDatabase::Locked},
  { "_flagAltitude",		"11.0",				false, StateDatabase::Locked},
  { "_flagEffectTime",		"0.64",				false, StateDatabase::Locked},
  { "_flagHeight",		"10.0",				false, StateDatabase::Locked},
  { "_flagPoleWidth",		"0.025",			false, StateDatabase::Locked},
  { "_flagPoleSize",		"0.8",				false, StateDatabase::Locked},
  { "_flagRadius",		"2.5",				false, StateDatabase::Locked},
  { "_friction",		"0",				false, StateDatabase::Locked},
  { "_gmActivationTime",	"0.5",				false, StateDatabase::Locked},
  { "_gmAdLife",		"0.95",				false, StateDatabase::Locked},
  { "_gmTurnAngle",		"0.628319",			false, StateDatabase::Locked},
  { "_gravity",			"-9.8",				false, StateDatabase::Locked},
  { "_handicapScoreDiff",	"50.0",				false, StateDatabase::Locked},
  { "_handicapVelAd",		"2.0",				false, StateDatabase::Locked},
  { "_handicapAngAd",		"1.5",				false, StateDatabase::Locked},
  { "_handicapShotAd",		"1.75",				false, StateDatabase::Locked},
  { "_identifyRange",		"50.0",				false, StateDatabase::Locked},
  { "_jumpVelocity",		"19.0",				false, StateDatabase::Locked},
  { "_laserAdLife",		"0.1",				false, StateDatabase::Locked},
  { "_laserAdRate",		"0.5",				false, StateDatabase::Locked},
  { "_laserAdVel",		"1000.0",			false, StateDatabase::Locked},
  { "_latitude",		"37.5",				false, StateDatabase::Locked},
  { "_lockOnAngle",		"0.15",				false, StateDatabase::Locked},
  { "_longitude",		"122",				false, StateDatabase::Locked},
  { "_lRAdRate",		"0.5",				false, StateDatabase::Locked},
  { "_maxBumpHeight",		"0.33",				false, StateDatabase::Locked},
  { "_maxFlagGrabs",		"4.0",				false, StateDatabase::Locked},
  { "_maxLOD",			"32767.0",			false, StateDatabase::Locked},
  { "_mirror",			"none",				false, StateDatabase::Locked},
  { "_momentumAngAcc",		"1.0",				false, StateDatabase::Locked},
  { "_momentumLinAcc",		"1.0",				false, StateDatabase::Locked},
  { "_momentumFriction",	"0",				false, StateDatabase::Locked},
  { "_mGunAdLife",		"1.0 / _mGunAdRate",		false, StateDatabase::Locked},
  { "_mGunAdRate",		"10.0",				false, StateDatabase::Locked},
  { "_mGunAdVel",		"1.5",				false, StateDatabase::Locked},
  { "_muzzleFront",		"_tankRadius + 0.1",		false, StateDatabase::Locked},
  { "_muzzleHeight",		"1.57",				false, StateDatabase::Locked},
  { "_noClimb",			"1",				false, StateDatabase::Locked},
  { "_noShadows",		"0",				false, StateDatabase::Locked},
  { "_noSmallPackets",		"0",				false, StateDatabase::Locked},
  { "_notRespondingTime",	"5.0",				false, StateDatabase::Locked},
  { "_obeseFactor",		"2.5",				false, StateDatabase::Locked},
  { "_pauseDropTime",		"15.0",				false, StateDatabase::Locked},
  { "_positionTolerance",	"0.09",				false, StateDatabase::Locked},
  { "_pyrBase",			"4.0*_tankHeight",		false, StateDatabase::Locked},
  { "_pyrHeight",		"5.0*_tankHeight",		false, StateDatabase::Locked},
  { "_rainBaseColor",		"none",				false, StateDatabase::Locked},
  { "_radarLimit",		"_worldSize",			false, StateDatabase::Locked},
  { "_rainRoofs",		"1",				false, StateDatabase::Locked},
  { "_rainDensity",		"none",				false, StateDatabase::Locked},
  { "_rainEndZ",		"none",				false, StateDatabase::Locked},
  { "_rainMaxPuddleTime",	"none",				false, StateDatabase::Locked},
  { "_rainPuddleSpeed",		"none",				false, StateDatabase::Locked},
  { "_rainPuddleColor",		"none",				false, StateDatabase::Locked},
  { "_rainPuddleTexture",	"none",				false, StateDatabase::Locked},
  { "_rainSpread",		"none",				false, StateDatabase::Locked},
  { "_rainSpeed",		"none",				false, StateDatabase::Locked},
  { "_rainSpeedMod",		"none",				false, StateDatabase::Locked},
  { "_rainSpins",		"none",				false, StateDatabase::Locked},
  { "_rainStartZ",		"none",				false, StateDatabase::Locked},
  { "_rainTexture",		"none",				false, StateDatabase::Locked},
  { "_rainTopColor",		"none",				false, StateDatabase::Locked},
  { "_rainType",		"none",				false, StateDatabase::Locked},
  { "_rejoinTime",		"_explodeTime",			false, StateDatabase::Locked},
  { "_reloadTime",		"_shotRange / _shotSpeed",	false, StateDatabase::Locked},
  { "_rFireAdLife",		"1.0 / _rFireAdRate",		false, StateDatabase::Locked},
  { "_rFireAdRate",		"2.0",				false, StateDatabase::Locked},
  { "_rFireAdVel",		"1.5",				false, StateDatabase::Locked},
  { "_shieldFlight",		"2.7",				false, StateDatabase::Locked},
  { "_shockAdLife",		"0.2",				false, StateDatabase::Locked},
  { "_shockInRadius",		"_tankLength",			false, StateDatabase::Locked},
  { "_shockOutRadius",		"60.0",				false, StateDatabase::Locked},
  { "_shotTailLength",		"4.0",				false, StateDatabase::Locked},
  { "_shotRadius",		"0.5",				false, StateDatabase::Locked},
  { "_shotRange",		"350.0",			false, StateDatabase::Locked},
  { "_shotSpeed",		"100.0",			false, StateDatabase::Locked},
  { "_shotsKeepVerticalVelocity",	"0",			false, StateDatabase::Locked},
  { "_skyColor",		"white",			false, StateDatabase::Locked},
  { "_srRadiusMult",		"2.0",				false, StateDatabase::Locked},
  { "_squishFactor",		"1.0",				false, StateDatabase::Locked},
  { "_squishTime",		"1.0",				false, StateDatabase::Locked},
  { "_syncTime",		"-1.0",				false, StateDatabase::Locked},
  { "_syncLocation",		"0",				false, StateDatabase::Locked},
  { "_tankExplosionSize",	"3.5 * _tankLength",		false, StateDatabase::Locked},
  { "_tankAngVel",		"0.785398",			false, StateDatabase::Locked},
  { "_tankHeight",		"2.05",				false, StateDatabase::Locked},
  { "_tankLength",		"6.0",				false, StateDatabase::Locked},
  { "_tankRadius",		"0.72 * _tankLength",		false, StateDatabase::Locked},
  { "_tankSpeed",		"25.0",				false, StateDatabase::Locked},
  { "_tankWidth",		"2.8",				false, StateDatabase::Locked},
  { "_targetingAngle",		"0.3",				false, StateDatabase::Locked},
  { "_teleportBreadth",		"4.48",				false, StateDatabase::Locked},
  { "_teleportHeight",		"10.08",			false, StateDatabase::Locked},
  { "_teleportTime",		"1.0",				false, StateDatabase::Locked},
  { "_teleportWidth",		"1.12",				false, StateDatabase::Locked},
  { "_thiefAdLife",		"0.05",				false, StateDatabase::Locked},
  { "_thiefAdRate",		"12.0",				false, StateDatabase::Locked},
  { "_thiefAdShotVel",		"8.0",				false, StateDatabase::Locked},
  { "_thiefTinyFactor",		"0.5",				false, StateDatabase::Locked},
  { "_thiefVelAd",		"1.67",				false, StateDatabase::Locked},
  { "_thiefDropTime",		"_reloadTime * 0.5",		false, StateDatabase::Locked},
  { "_tinyFactor",		"0.4",				false, StateDatabase::Locked},
  { "_trackFade",		"3.0",				false, StateDatabase::Locked},
  { "_updateThrottleRate",	"30.0",				false, StateDatabase::Locked},
  { "_useLineRain",		"none",				false, StateDatabase::Locked},
  { "_useRainPuddles",		"none",				false, StateDatabase::Locked},
  { "_useRainBillboards",	"none",				false, StateDatabase::Locked},
  { "_velocityAd",		"1.5",				false, StateDatabase::Locked},
  { "_wallHeight",		"3.0*_tankHeight",		false, StateDatabase::Locked},
  { "_weapons",			"1",				false, StateDatabase::Locked},
  { "_wideAngleAng",		"1.745329",			false, StateDatabase::Locked},
  { "_wingsGravity",		"_gravity",			false, StateDatabase::Locked},
  { "_wingsJumpCount",		"1",				false, StateDatabase::Locked},
  { "_wingsJumpVelocity",	"_jumpVelocity",		false, StateDatabase::Locked},
  { "_wingsSlideTime",		"1.0",				false, StateDatabase::Locked},
  { "_worldSize",		"800.0",			false, StateDatabase::Locked}

};
const unsigned int	numGlobalDBItems = countof(globalDBItems);

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>/*BEGIN_LEGAL
Intel Open Source License

Copyright (c) 2002-2013 Intel Corporation. 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 Intel Corporation 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 INTEL OR
ITS 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.
END_LEGAL */

#include "pin.H"
#include <iostream>
#include <cstdio>
#include <set>
#include "memlist.h"
using namespace std;

// Prototypes ; TODO: Move to Seperate Header file?
void HookFree(IMG img);
void HookMalloc(IMG img);

typedef VOID* (*FP_MALLOC)(size_t);
typedef void (*FP_FREE)(void*);

bool inMain = false;
FILE * trace;
MemList ml;
int freeWasCalled = 0;
// Malloc
int mallocNumber = -1;
int freeNumber = -1;

// Print a memory read record
VOID RecordHeapMemRead(VOID * ip, VOID * addr) {
    int rtn = ml.containsAddress(addr);
    if(rtn != ERR_NOT_FOUND) {
        fprintf(trace,"##########BAD WRITE: %p \n", addr);
        cout << "BAD WRITE" << endl;
    }
    //printf("heap read: %p\n", addr);
}

// Print a memory write record
VOID RecordHeapMemWrite(VOID * ip, VOID * addr) {
    int rtn = ml.containsAddress(addr);
    if(rtn != ERR_NOT_FOUND) {
        fprintf(trace,"##########BAD WRITE: %p \n", addr);
        cout << "BAD WRITE" << endl;
    }
    //printf("heap write: %p\n", addr);
}

VOID RecordStackMemRead(VOID * ip, VOID * addr) {
    //printf("stack read: %p\n", addr);
}

// Print a memory write record
VOID RecordStackMemWrite(VOID * ip, VOID * addr) {
    //printf("stack write: %p\n", addr);
}

// Is called for every instruction and instruments reads and writes
VOID Instruction(INS ins, VOID *v) {
    if(!inMain || (mallocNumber <= 0 && freeNumber <=0))
        return;
    // Instruments memory accesses using a predicated call, i.e.
    // the instrumentation is called iff the instruction will actually be executed.
    //
    // On the IA-32 and Intel(R) 64 architectures conditional moves and REP
    // prefixed instructions appear as predicated instructions in Pin.
    UINT32 memOperands = INS_MemoryOperandCount(ins);

    // Iterate over each memory operand of the instruction.
    for (UINT32 memOp = 0; memOp < memOperands; memOp++) {
        //if (INS_MemoryOperandIsRead(ins, memOp)) {
        if (INS_MemoryOperandIsRead(ins, memOp) && !INS_IsStackRead(ins)) {
            INS_InsertPredicatedCall(
                ins, IPOINT_BEFORE, (AFUNPTR)RecordHeapMemRead,
                IARG_INST_PTR,
                IARG_MEMORYOP_EA, memOp,
                IARG_END);
        } else if (INS_MemoryOperandIsRead(ins, memOp)) {
            INS_InsertPredicatedCall(
                ins, IPOINT_BEFORE, (AFUNPTR)RecordStackMemRead,
                IARG_INST_PTR,
                IARG_MEMORYOP_EA, memOp,
                IARG_END);
        }
        // Note that in some architectures a single memory operand can be
        // both read and written (for instance incl (%eax) on IA-32)
        // In that case we instrument it once for read and once for write.
        //if (INS_MemoryOperandIsWritten(ins, memOp)) {
        if (INS_MemoryOperandIsWritten(ins, memOp) && !INS_IsStackWrite(ins)) {
            INS_InsertPredicatedCall(
                ins, IPOINT_BEFORE, (AFUNPTR)RecordHeapMemWrite,
                IARG_INST_PTR,
                IARG_MEMORYOP_EA, memOp,
                IARG_END);
        } else if (INS_MemoryOperandIsWritten(ins, memOp)) {
            INS_InsertPredicatedCall(
                ins, IPOINT_BEFORE, (AFUNPTR)RecordStackMemWrite,
                IARG_INST_PTR,
                IARG_MEMORYOP_EA, memOp,
                IARG_END);
        }
    }
}

VOID Fini(INT32 code, VOID *v) {
    fprintf(trace, "#eof \n");
    fclose(trace);
}

// This is the replacement routine.
VOID* NewMalloc(FP_MALLOC orgFuncptr, UINT32 arg0, ADDRINT returnIp) {
    // Call the relocated entry point of the original (replaced) routine.
    void* v = orgFuncptr(arg0 + 16);
    char *cp = (char*)v;
    ml.add(cp, 8);
    fprintf(trace, "ADDED: %p %d \n", cp, 8);
    cp += (8 + arg0);
    ml.add(cp, 8);
    fprintf(trace, "ADDED: %p %d \n", cp, 8);
    return (void*)(((char*)v)+8);
}

void NewFree(FP_FREE orgFuncptr, void* ptr, ADDRINT returnIp) {
    if(ptr != NULL) {
        // TODO: -8 is the fence size; Make it a constant
        // Set the pointer to the actual start of memory
        void* realPtr = (char*)ptr - 8;
        // Check the WhiteList
        int index  = ml.containsAddress(ptr);
        if(index > 0) {
            // Remove the space
            orgFuncptr(realPtr);
        } else if(index == ERR_NOT_FOUND) {
            // This currently gets hit since a blacklist is being used
            fprintf(trace, "Address = %p not found. Bad address or stack address used.\n", ptr);
        } else if(index == ERR_MID_CHUNK) {
            fprintf(trace, "Mid-chunk memory deallocation @ %p\n", ptr);
        } else {
            fprintf(trace, "Unable to deallocate the memory @ %p\n", ptr);
        }
    } else {
        fprintf(trace, "Attempted to free NULL\n");
    }
}

// Pin calls this function every time a new img is loaded.
// It is best to do probe replacement when the image is loaded,
// because only one thread knows about the image at this time.
VOID ImageLoad(IMG img, VOID *v) {
    if(!inMain) {
        inMain = IMG_IsMainExecutable(img);
        return;
    }
    // Hook Functions
    HookMalloc(img);
    HookFree(img);
}

void HookFree(IMG img) {
    RTN rtn = RTN_FindByName(img, "free");
    // TODO: Hack for skipping hooks to /lib64/ld-linux-x86-64.so.2
    if(RTN_Valid(rtn)) {
        freeNumber++;
    }
    if(RTN_Valid(rtn) && freeNumber > 0) {
        cout << "Replacing free in " << IMG_Name(img) << endl;
        // Return type, cstype, function name, arguments...
        PROTO proto = PROTO_Allocate(PIN_PARG(void), CALLINGSTD_DEFAULT, "free", PIN_PARG(void*), PIN_PARG_END());
        // Replace free
        RTN_ReplaceSignature(rtn, AFUNPTR(NewFree),
            IARG_PROTOTYPE,
            proto,
            IARG_ORIG_FUNCPTR,
            IARG_FUNCARG_ENTRYPOINT_VALUE,
            0,
            IARG_RETURN_IP,
            IARG_END);
        // Free the function prototype
        PROTO_Free(proto);
    }
}

void HookMalloc(IMG img) {
    // See if malloc() is present in the image.  If so, replace it.
    RTN rtnMalloc = RTN_FindByName(img, "malloc");
    if(RTN_Valid(rtnMalloc)) {
        mallocNumber++;
    }
    if(RTN_Valid(rtnMalloc) && mallocNumber > 0) {
        cout << "Replacing malloc in " << IMG_Name(img) << endl;
        PROTO proto_malloc = PROTO_Allocate(PIN_PARG(void *), CALLINGSTD_DEFAULT,
            "malloc", PIN_PARG(int), PIN_PARG_END());
        RTN_ReplaceSignature(rtnMalloc, AFUNPTR(NewMalloc),
            IARG_PROTOTYPE, proto_malloc,
            IARG_ORIG_FUNCPTR,
            IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
            IARG_RETURN_IP,
            IARG_END);
        // Free the function prototype.
        PROTO_Free(proto_malloc);
    }
}

/* ===================================================================== */
/* Print Help Message                                                    */
/* ===================================================================== */

INT32 Usage() {
    cerr << "This tool demonstrates how to replace an original" << endl;
    cerr << " function with a custom function defined in the tool " << endl;
    cerr << " using probes.  The replacement function has a different " << endl;
    cerr << " signature from that of the original replaced function." << endl;
    cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
    return -1;
}

/* ===================================================================== */
/* Main: Initialize and start Pin in Probe mode.                         */
/* ===================================================================== */

int main(INT32 argc, CHAR *argv[]) {
    // Initialize symbol processing
    PIN_InitSymbols();
    // Initialize pin
    if (PIN_Init(argc, argv))
        return Usage();
    // Open up the trace file
    trace = fopen("zzz.out", "w");
    // Register ImageLoad to be called when an image is loaded
    IMG_AddInstrumentFunction(ImageLoad, 0);
    INS_AddInstrumentFunction(Instruction, 0);
    PIN_AddFiniFunction(Fini, 0);
    PIN_StartProgram();
    return 0;
}
<commit_msg>fixed mymalloc<commit_after>/*BEGIN_LEGAL
Intel Open Source License

Copyright (c) 2002-2013 Intel Corporation. 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 Intel Corporation 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 INTEL OR
ITS 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.
END_LEGAL */

#include "pin.H"
#include <iostream>
#include <cstdio>
#include <set>
#include "memlist.h"
#include "memoryalloc.h"
using namespace std;

// Prototypes ; TODO: Move to Seperate Header file?
void HookFree(IMG img);
void HookMalloc(IMG img);

typedef VOID* (*FP_MALLOC)(size_t);
typedef void (*FP_FREE)(void*);

bool inMain = false;
FILE * trace;
MemList ml;
int freeWasCalled = 0;
// Malloc
int mallocNumber = -1;
int freeNumber = -1;

// Print a memory read record
VOID RecordHeapMemRead(VOID * ip, VOID * addr) {
    int rtn = ml.containsAddress(addr);
    if(rtn != ERR_NOT_FOUND) {
        fprintf(trace,"##########BAD WRITE: %p \n", addr);
        cout << "BAD WRITE" << endl;
    }
    //printf("heap read: %p\n", addr);
}

// Print a memory write record
VOID RecordHeapMemWrite(VOID * ip, VOID * addr) {
    int rtn = ml.containsAddress(addr);
    if(rtn != ERR_NOT_FOUND) {
        fprintf(trace,"##########BAD WRITE: %p \n", addr);
        cout << "BAD WRITE" << endl;
    }
    //printf("heap write: %p\n", addr);
}

VOID RecordStackMemRead(VOID * ip, VOID * addr) {
    //printf("stack read: %p\n", addr);
}

// Print a memory write record
VOID RecordStackMemWrite(VOID * ip, VOID * addr) {
    //printf("stack write: %p\n", addr);
}

// Is called for every instruction and instruments reads and writes
VOID Instruction(INS ins, VOID *v) {
    if(!inMain || (mallocNumber <= 0 && freeNumber <=0))
        return;
    // Instruments memory accesses using a predicated call, i.e.
    // the instrumentation is called iff the instruction will actually be executed.
    //
    // On the IA-32 and Intel(R) 64 architectures conditional moves and REP
    // prefixed instructions appear as predicated instructions in Pin.
    UINT32 memOperands = INS_MemoryOperandCount(ins);

    // Iterate over each memory operand of the instruction.
    for (UINT32 memOp = 0; memOp < memOperands; memOp++) {
        //if (INS_MemoryOperandIsRead(ins, memOp)) {
        if (INS_MemoryOperandIsRead(ins, memOp) && !INS_IsStackRead(ins)) {
            INS_InsertPredicatedCall(
                ins, IPOINT_BEFORE, (AFUNPTR)RecordHeapMemRead,
                IARG_INST_PTR,
                IARG_MEMORYOP_EA, memOp,
                IARG_END);
        } else if (INS_MemoryOperandIsRead(ins, memOp)) {
            INS_InsertPredicatedCall(
                ins, IPOINT_BEFORE, (AFUNPTR)RecordStackMemRead,
                IARG_INST_PTR,
                IARG_MEMORYOP_EA, memOp,
                IARG_END);
        }
        // Note that in some architectures a single memory operand can be
        // both read and written (for instance incl (%eax) on IA-32)
        // In that case we instrument it once for read and once for write.
        //if (INS_MemoryOperandIsWritten(ins, memOp)) {
        if (INS_MemoryOperandIsWritten(ins, memOp) && !INS_IsStackWrite(ins)) {
            INS_InsertPredicatedCall(
                ins, IPOINT_BEFORE, (AFUNPTR)RecordHeapMemWrite,
                IARG_INST_PTR,
                IARG_MEMORYOP_EA, memOp,
                IARG_END);
        } else if (INS_MemoryOperandIsWritten(ins, memOp)) {
            INS_InsertPredicatedCall(
                ins, IPOINT_BEFORE, (AFUNPTR)RecordStackMemWrite,
                IARG_INST_PTR,
                IARG_MEMORYOP_EA, memOp,
                IARG_END);
        }
    }
}

VOID Fini(INT32 code, VOID *v) {
    fprintf(trace, "#eof \n");
    fclose(trace);
}

// This is the replacement routine.
VOID* NewMalloc(FP_MALLOC orgFuncptr, UINT32 arg0, ADDRINT returnIp) {
    // Call the relocated entry point of the original (replaced) routine.
    void* v = orgFuncptr(arg0 + (2 * DEFAULT_FENCE_SIZE));

    MemoryAlloc ma = ml.add(v, arg0, DEFAULT_FENCE_SIZE);
    fprintf(trace, "ADDED: %p %d \n", v, DEFAULT_FENCE_SIZE);
    return ma.getAddress();
}

void NewFree(FP_FREE orgFuncptr, void* ptr, ADDRINT returnIp) {
    if(ptr != NULL) {
        // TODO: -8 is the fence size; Make it a constant
        // Set the pointer to the actual start of memory
        void* realPtr = (char*)ptr - 8;
        // Check the WhiteList
        int index  = ml.containsAddress(ptr);
        if(index > 0) {
            // Remove the space
            orgFuncptr(realPtr);
        } else if(index == ERR_NOT_FOUND) {
            // This currently gets hit since a blacklist is being used
            fprintf(trace, "Address = %p not found. Bad address or stack address used.\n", ptr);
        } else if(index == ERR_MID_CHUNK) {
            fprintf(trace, "Mid-chunk memory deallocation @ %p\n", ptr);
        } else {
            fprintf(trace, "Unable to deallocate the memory @ %p\n", ptr);
        }
    } else {
        fprintf(trace, "Attempted to free NULL\n");
    }
}

// Pin calls this function every time a new img is loaded.
// It is best to do probe replacement when the image is loaded,
// because only one thread knows about the image at this time.
VOID ImageLoad(IMG img, VOID *v) {
    if(!inMain) {
        inMain = IMG_IsMainExecutable(img);
        return;
    }
    // Hook Functions
    HookMalloc(img);
    HookFree(img);
}

void HookFree(IMG img) {
    RTN rtn = RTN_FindByName(img, "free");
    // TODO: Hack for skipping hooks to /lib64/ld-linux-x86-64.so.2
    if(RTN_Valid(rtn)) {
        freeNumber++;
    }
    if(RTN_Valid(rtn) && freeNumber > 0) {
        cout << "Replacing free in " << IMG_Name(img) << endl;
        // Return type, cstype, function name, arguments...
        PROTO proto = PROTO_Allocate(PIN_PARG(void), CALLINGSTD_DEFAULT, "free", PIN_PARG(void*), PIN_PARG_END());
        // Replace free
        RTN_ReplaceSignature(rtn, AFUNPTR(NewFree),
            IARG_PROTOTYPE,
            proto,
            IARG_ORIG_FUNCPTR,
            IARG_FUNCARG_ENTRYPOINT_VALUE,
            0,
            IARG_RETURN_IP,
            IARG_END);
        // Free the function prototype
        PROTO_Free(proto);
    }
}

void HookMalloc(IMG img) {
    // See if malloc() is present in the image.  If so, replace it.
    RTN rtnMalloc = RTN_FindByName(img, "malloc");
    if(RTN_Valid(rtnMalloc)) {
        mallocNumber++;
    }
    if(RTN_Valid(rtnMalloc) && mallocNumber > 0) {
        cout << "Replacing malloc in " << IMG_Name(img) << endl;
        PROTO proto_malloc = PROTO_Allocate(PIN_PARG(void *), CALLINGSTD_DEFAULT,
            "malloc", PIN_PARG(int), PIN_PARG_END());
        RTN_ReplaceSignature(rtnMalloc, AFUNPTR(NewMalloc),
            IARG_PROTOTYPE, proto_malloc,
            IARG_ORIG_FUNCPTR,
            IARG_FUNCARG_ENTRYPOINT_VALUE, 0,
            IARG_RETURN_IP,
            IARG_END);
        // Free the function prototype.
        PROTO_Free(proto_malloc);
    }
}

/* ===================================================================== */
/* Print Help Message                                                    */
/* ===================================================================== */

INT32 Usage() {
    cerr << "This tool demonstrates how to replace an original" << endl;
    cerr << " function with a custom function defined in the tool " << endl;
    cerr << " using probes.  The replacement function has a different " << endl;
    cerr << " signature from that of the original replaced function." << endl;
    cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
    return -1;
}

/* ===================================================================== */
/* Main: Initialize and start Pin in Probe mode.                         */
/* ===================================================================== */

int main(INT32 argc, CHAR *argv[]) {
    // Initialize symbol processing
    PIN_InitSymbols();
    // Initialize pin
    if (PIN_Init(argc, argv))
        return Usage();
    // Open up the trace file
    trace = fopen("zzz.out", "w");
    // Register ImageLoad to be called when an image is loaded
    IMG_AddInstrumentFunction(ImageLoad, 0);
    INS_AddInstrumentFunction(Instruction, 0);
    PIN_AddFiniFunction(Fini, 0);
    PIN_StartProgram();
    return 0;
}
<|endoftext|>