<commit_before>// This code is based on Sabberstone project.
// Copyright (c) 2017-2019 SabberStone Team, darkfriend77 & rnilva
// RosettaStone is hearthstone simulator using C++ with reinforcement learning.
// Copyright (c) 2019 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

#include <Rosetta/Commons/Utils.hpp>
#include <Rosetta/Enchants/Trigger.hpp>
#include <Rosetta/Games/Game.hpp>
#include <Rosetta/Models/Enchantment.hpp>
#include <Rosetta/Tasks/ITask.hpp>

#include <stdexcept>

namespace RosettaStone
{
Trigger::Trigger(TriggerType type) : m_triggerType(type)
{
    switch (type)
    {
        case TriggerType::PLAY_CARD:
            m_sequenceType = SequenceType::PLAY_CARD;
            break;
        case TriggerType::CAST_SPELL:
        case TriggerType::AFTER_CAST:
            m_sequenceType = SequenceType::PLAY_SPELL;
            break;
        case TriggerType::TARGET:
            m_sequenceType = SequenceType::TARGET;
            break;
        case TriggerType::TURN_END:
            fastExecution = true;
            break;
        default:
            m_sequenceType = SequenceType::NONE;
    }
}

Trigger::Trigger(Trigger& prototype, Entity& owner)
    : triggerSource(prototype.triggerSource),
      tasks(prototype.tasks),
      condition(prototype.condition),
      fastExecution(prototype.fastExecution),
      removeAfterTriggered(prototype.removeAfterTriggered),
      m_owner(&owner),
      m_triggerType(prototype.m_triggerType),
      m_triggerActivation(prototype.m_triggerActivation),
      m_sequenceType(prototype.m_sequenceType)
{
    // Do nothing
}

void Trigger::Activate(Entity* source, TriggerActivation activation, bool cloning)
{
    if (!cloning && activation != m_triggerActivation)
    {
        if (m_triggerActivation != TriggerActivation::HAND_OR_PLAY)
        {
            return;
        }

        if (activation == TriggerActivation::DECK)
        {
            return;
        }
    }

    auto* instance = new Trigger(*this, *source);
    Game* game = source->owner->GetGame();

    source->activatedTrigger = instance;

    auto triggerFunc = [instance](Player* p, Entity* e) {
        instance->Process(p, e);
    };

    if (m_sequenceType != SequenceType::NONE)
    {
        source->owner->GetGame()->triggers.emplace_back(instance);
    }

    switch (m_triggerType)
    {
        case TriggerType::TURN_START:
            game->triggerManager.startTurnTrigger = std::move(triggerFunc);
            break;
        case TriggerType::TURN_END:
            game->triggerManager.endTurnTrigger = std::move(triggerFunc);
            break;
        case TriggerType::PLAY_CARD:
            game->triggerManager.playCardTrigger = std::move(triggerFunc);
            break;
        case TriggerType::CAST_SPELL:
            game->triggerManager.castSpellTrigger = std::move(triggerFunc);
            break;
        case TriggerType::AFTER_CAST:
            game->triggerManager.afterCastTrigger = std::move(triggerFunc);
            break;
        case TriggerType::HEAL:
            game->triggerManager.healTrigger = std::move(triggerFunc);
            break;
        case TriggerType::ATTACK:
            game->triggerManager.attackTrigger = std::move(triggerFunc);
            break;
        case TriggerType::AFTER_ATTACK:
            switch (triggerSource)
            {
                case TriggerSource::HERO:
                {
                    source->owner->GetHero()->afterAttackTrigger =
                        std::move(triggerFunc);
                    break;
                }
                case TriggerSource::SELF:
                {
                    auto minion = dynamic_cast<Minion*>(source);
                    minion->afterAttackTrigger = std::move(triggerFunc);
                    break;
                }
                case TriggerSource::ENCHANTMENT_TARGET:
                {
                    const auto enchantment = dynamic_cast<Enchantment*>(source);
                    auto minion =
                        dynamic_cast<Minion*>(enchantment->GetTarget());
                    minion->afterAttackTrigger = std::move(triggerFunc);
                    break;
                }
                default:
                    break;
            }
            break;
        case TriggerType::SUMMON:
            game->triggerManager.summonTrigger = std::move(triggerFunc);
            break;
        case TriggerType::PREDAMAGE:
            switch (triggerSource)
            {
                case TriggerSource::HERO:
                {
                    source->owner->GetHero()->preDamageTrigger =
                        std::move(triggerFunc);
                    break;
                }
                case TriggerSource::SELF:
                {
                    auto minion = dynamic_cast<Minion*>(source);
                    minion->preDamageTrigger = std::move(triggerFunc);
                    break;
                }
                case TriggerSource::ENCHANTMENT_TARGET:
                {
                    const auto enchantment = dynamic_cast<Enchantment*>(source);
                    auto minion =
                        dynamic_cast<Minion*>(enchantment->GetTarget());
                    minion->preDamageTrigger = std::move(triggerFunc);
                    break;
                }
                default:
                    break;
            }
            break;
        case TriggerType::TAKE_DAMAGE:
            game->triggerManager.takeDamageTrigger = std::move(triggerFunc);
            break;
        case TriggerType::TARGET:
            game->triggerManager.targetTrigger = std::move(triggerFunc);
            break;
        default:
            throw std::invalid_argument(
                "Trigger::Activate() - Invalid trigger type!");
    }
}

void Trigger::Remove() const
{
    Game* game = m_owner->owner->GetGame();

    switch (m_triggerType)
    {
        case TriggerType::TURN_START:
            game->triggerManager.startTurnTrigger = nullptr;
            break;
        case TriggerType::TURN_END:
            game->triggerManager.endTurnTrigger = nullptr;
            break;
        case TriggerType::PLAY_CARD:
            game->triggerManager.playCardTrigger = nullptr;
            break;
        case TriggerType::CAST_SPELL:
            game->triggerManager.castSpellTrigger = nullptr;
            break;
        case TriggerType::AFTER_CAST:
            game->triggerManager.afterCastTrigger = nullptr;
            break;
        case TriggerType::HEAL:
            game->triggerManager.healTrigger = nullptr;
            break;
        case TriggerType::ATTACK:
            game->triggerManager.attackTrigger = nullptr;
            break;
        case TriggerType::AFTER_ATTACK:
            switch (triggerSource)
            {
                case TriggerSource::HERO:
                {
                    m_owner->owner->GetHero()->afterAttackTrigger = nullptr;
                    break;
                }
                case TriggerSource::SELF:
                {
                    auto minion = dynamic_cast<Minion*>(m_owner);
                    minion->afterAttackTrigger = nullptr;
                    break;
                }
                case TriggerSource::ENCHANTMENT_TARGET:
                {
                    const auto enchantment =
                        dynamic_cast<Enchantment*>(m_owner);
                    auto minion =
                        dynamic_cast<Minion*>(enchantment->GetTarget());
                    minion->afterAttackTrigger = nullptr;
                    break;
                }
                default:
                    break;
            }
        case TriggerType::SUMMON:
            game->triggerManager.summonTrigger = nullptr;
            break;
        case TriggerType::PREDAMAGE:
            switch (triggerSource)
            {
                case TriggerSource::HERO:
                {
                    m_owner->owner->GetHero()->preDamageTrigger = nullptr;
                    break;
                }
                case TriggerSource::SELF:
                {
                    auto minion = dynamic_cast<Minion*>(m_owner);
                    minion->preDamageTrigger = nullptr;
                    break;
                }
                case TriggerSource::ENCHANTMENT_TARGET:
                {
                    const auto enchantment =
                        dynamic_cast<Enchantment*>(m_owner);
                    auto minion =
                        dynamic_cast<Minion*>(enchantment->GetTarget());
                    minion->preDamageTrigger = nullptr;
                    break;
                }
                default:
                    break;
            }
        case TriggerType::TAKE_DAMAGE:
            game->triggerManager.takeDamageTrigger = nullptr;
            break;
        case TriggerType::TARGET:
            game->triggerManager.targetTrigger = nullptr;
            break;
        default:
            throw std::invalid_argument(
                "Trigger::Remove() - Invalid trigger type!");
    }

    if (m_sequenceType != SequenceType::NONE)
    {
        EraseIf(game->triggers,
                [this](Trigger* trigger) { return trigger == this; });
    }

    delete m_owner->activatedTrigger;
}

void Trigger::ValidateTriggers(Game* game, Entity* source, SequenceType type)
{
    for (auto& trigger : game->triggers)
    {
        if (trigger->m_sequenceType == type)
        {
            trigger->Validate(&game->GetCurrentPlayer(), source);
        }
    }
}

void Trigger::Process(Player* player, Entity* source)
{
    if (m_sequenceType == SequenceType::NONE)
    {
        Validate(player, source);
    }

    if (!m_isValidated)
    {
        return;
    }

    ProcessInternal(source);
}

void Trigger::ProcessInternal(Entity* source)
{
    m_isValidated = false;

    for (auto& task : tasks)
    {
        task->SetPlayer(m_owner->owner);
        task->SetSource(m_owner);

        if (source != nullptr)
        {
            task->SetTarget(source);
        }
        else
        {
            const auto enchantment = dynamic_cast<Enchantment*>(m_owner);
            if (enchantment != nullptr && enchantment->GetTarget() != nullptr)
            {
                task->SetTarget(enchantment->GetTarget());
            }
            else
            {
                task->SetTarget(nullptr);
            }
        }

        if (fastExecution)
        {
            task->Run();
        }
        else
        {
            m_owner->owner->GetGame()->taskQueue.Enqueue(task);
        }

        if (removeAfterTriggered)
        {
            Remove();
        }
    }

    m_isValidated = false;
}

void Trigger::Validate(Player* player, Entity* source)
{
    switch (triggerSource)
    {
        case TriggerSource::NONE:
            break;
        case TriggerSource::SELF:
            if (source != m_owner)
            {
                return;
            }
            break;
        case TriggerSource::HERO:
            if (dynamic_cast<Hero*>(source) == nullptr ||
                source->owner != m_owner->owner)
            {
                return;
            }
            break;
        case TriggerSource::ALL_MINIONS:
            if (dynamic_cast<Minion*>(source) == nullptr)
            {
                return;
            }
            break;
        case TriggerSource::MINIONS_EXCEPT_SELF:
            if (dynamic_cast<Minion*>(source) == nullptr ||
                source->owner != m_owner->owner || source == m_owner)
            {
                return;
            }
            break;
        case TriggerSource::ENCHANTMENT_TARGET:
        {
            const auto enchantment = dynamic_cast<Enchantment*>(m_owner);
            if (enchantment == nullptr ||
                enchantment->GetTarget()->id != source->id)
            {
                return;
            }
            break;
        }
        case TriggerSource::FRIENDLY:
        {
            if (source->owner != m_owner->owner)
            {
                return;
            }
            break;
        }
        default:
            throw std::invalid_argument(
                "Trigger::Validate() - Invalid source trigger!");
    }

    switch (m_triggerType)
    {
        case TriggerType::TURN_START:
        case TriggerType::TURN_END:
            if (player != m_owner->owner)
            {
                return;
            }
            break;
        case TriggerType::PLAY_CARD:
        case TriggerType::SUMMON:
            if (source == m_owner)
            {
                return;
            }
            break;
        default:
            break;
    }

    if (condition != nullptr)
    {
        const bool res = (source != nullptr) ? condition->Evaluate(source)
                                             : condition->Evaluate(m_owner);

        if (!res)
        {
            return;
        }
    }

    m_isValidated = true;
}
}  // namespace RosettaStone
<commit_msg>fix: Remove unused code<commit_after>// This code is based on Sabberstone project.
// Copyright (c) 2017-2019 SabberStone Team, darkfriend77 & rnilva
// RosettaStone is hearthstone simulator using C++ with reinforcement learning.
// Copyright (c) 2019 Chris Ohk, Youngjoong Kim, SeungHyun Jeon

#include <Rosetta/Commons/Utils.hpp>
#include <Rosetta/Enchants/Trigger.hpp>
#include <Rosetta/Games/Game.hpp>
#include <Rosetta/Models/Enchantment.hpp>
#include <Rosetta/Tasks/ITask.hpp>

#include <stdexcept>

namespace RosettaStone
{
Trigger::Trigger(TriggerType type) : m_triggerType(type)
{
    switch (type)
    {
        case TriggerType::PLAY_CARD:
            m_sequenceType = SequenceType::PLAY_CARD;
            break;
        case TriggerType::CAST_SPELL:
        case TriggerType::AFTER_CAST:
            m_sequenceType = SequenceType::PLAY_SPELL;
            break;
        case TriggerType::TARGET:
            m_sequenceType = SequenceType::TARGET;
            break;
        case TriggerType::TURN_END:
            fastExecution = true;
            break;
        default:
            m_sequenceType = SequenceType::NONE;
    }
}

Trigger::Trigger(Trigger& prototype, Entity& owner)
    : triggerSource(prototype.triggerSource),
      tasks(prototype.tasks),
      condition(prototype.condition),
      fastExecution(prototype.fastExecution),
      removeAfterTriggered(prototype.removeAfterTriggered),
      m_owner(&owner),
      m_triggerType(prototype.m_triggerType),
      m_triggerActivation(prototype.m_triggerActivation),
      m_sequenceType(prototype.m_sequenceType)
{
    // Do nothing
}

void Trigger::Activate(Entity* source, TriggerActivation activation, bool cloning)
{
    if (!cloning && activation != m_triggerActivation)
    {
        if (m_triggerActivation != TriggerActivation::HAND_OR_PLAY)
        {
            return;
        }
    }

    auto* instance = new Trigger(*this, *source);
    Game* game = source->owner->GetGame();

    source->activatedTrigger = instance;

    auto triggerFunc = [instance](Player* p, Entity* e) {
        instance->Process(p, e);
    };

    if (m_sequenceType != SequenceType::NONE)
    {
        source->owner->GetGame()->triggers.emplace_back(instance);
    }

    switch (m_triggerType)
    {
        case TriggerType::TURN_START:
            game->triggerManager.startTurnTrigger = std::move(triggerFunc);
            break;
        case TriggerType::TURN_END:
            game->triggerManager.endTurnTrigger = std::move(triggerFunc);
            break;
        case TriggerType::PLAY_CARD:
            game->triggerManager.playCardTrigger = std::move(triggerFunc);
            break;
        case TriggerType::CAST_SPELL:
            game->triggerManager.castSpellTrigger = std::move(triggerFunc);
            break;
        case TriggerType::AFTER_CAST:
            game->triggerManager.afterCastTrigger = std::move(triggerFunc);
            break;
        case TriggerType::HEAL:
            game->triggerManager.healTrigger = std::move(triggerFunc);
            break;
        case TriggerType::ATTACK:
            game->triggerManager.attackTrigger = std::move(triggerFunc);
            break;
        case TriggerType::AFTER_ATTACK:
            switch (triggerSource)
            {
                case TriggerSource::HERO:
                {
                    source->owner->GetHero()->afterAttackTrigger =
                        std::move(triggerFunc);
                    break;
                }
                default:
                    break;
            }
            break;
        case TriggerType::SUMMON:
            game->triggerManager.summonTrigger = std::move(triggerFunc);
            break;
        case TriggerType::PREDAMAGE:
            switch (triggerSource)
            {
                case TriggerSource::SELF:
                {
                    auto minion = dynamic_cast<Minion*>(source);
                    minion->preDamageTrigger = std::move(triggerFunc);
                    break;
                }
                default:
                    break;
            }
            break;
        case TriggerType::TAKE_DAMAGE:
            game->triggerManager.takeDamageTrigger = std::move(triggerFunc);
            break;
        case TriggerType::TARGET:
            game->triggerManager.targetTrigger = std::move(triggerFunc);
            break;
        default:
            throw std::invalid_argument(
                "Trigger::Activate() - Invalid trigger type!");
    }
}

void Trigger::Remove() const
{
    Game* game = m_owner->owner->GetGame();

    switch (m_triggerType)
    {
        case TriggerType::TURN_START:
            game->triggerManager.startTurnTrigger = nullptr;
            break;
        case TriggerType::TURN_END:
            game->triggerManager.endTurnTrigger = nullptr;
            break;
        case TriggerType::PLAY_CARD:
            game->triggerManager.playCardTrigger = nullptr;
            break;
        case TriggerType::CAST_SPELL:
            game->triggerManager.castSpellTrigger = nullptr;
            break;
        case TriggerType::AFTER_CAST:
            game->triggerManager.afterCastTrigger = nullptr;
            break;
        case TriggerType::HEAL:
            game->triggerManager.healTrigger = nullptr;
            break;
        case TriggerType::ATTACK:
            game->triggerManager.attackTrigger = nullptr;
            break;
        case TriggerType::AFTER_ATTACK:
            switch (triggerSource)
            {
                case TriggerSource::HERO:
                {
                    m_owner->owner->GetHero()->afterAttackTrigger = nullptr;
                    break;
                }
                default:
                    break;
            }
        case TriggerType::SUMMON:
            game->triggerManager.summonTrigger = nullptr;
            break;
        case TriggerType::PREDAMAGE:
            switch (triggerSource)
            {
                case TriggerSource::SELF:
                {
                    auto minion = dynamic_cast<Minion*>(m_owner);
                    minion->preDamageTrigger = nullptr;
                    break;
                }
                default:
                    break;
            }
        case TriggerType::TAKE_DAMAGE:
            game->triggerManager.takeDamageTrigger = nullptr;
            break;
        case TriggerType::TARGET:
            game->triggerManager.targetTrigger = nullptr;
            break;
        default:
            throw std::invalid_argument(
                "Trigger::Remove() - Invalid trigger type!");
    }

    if (m_sequenceType != SequenceType::NONE)
    {
        EraseIf(game->triggers,
                [this](Trigger* trigger) { return trigger == this; });
    }

    delete m_owner->activatedTrigger;
}

void Trigger::ValidateTriggers(Game* game, Entity* source, SequenceType type)
{
    for (auto& trigger : game->triggers)
    {
        if (trigger->m_sequenceType == type)
        {
            trigger->Validate(&game->GetCurrentPlayer(), source);
        }
    }
}

void Trigger::Process(Player* player, Entity* source)
{
    if (m_sequenceType == SequenceType::NONE)
    {
        Validate(player, source);
    }

    if (!m_isValidated)
    {
        return;
    }

    ProcessInternal(source);
}

void Trigger::ProcessInternal(Entity* source)
{
    m_isValidated = false;

    for (auto& task : tasks)
    {
        task->SetPlayer(m_owner->owner);
        task->SetSource(m_owner);

        if (source != nullptr)
        {
            task->SetTarget(source);
        }
        else
        {
            const auto enchantment = dynamic_cast<Enchantment*>(m_owner);
            if (enchantment != nullptr && enchantment->GetTarget() != nullptr)
            {
                task->SetTarget(enchantment->GetTarget());
            }
            else
            {
                task->SetTarget(nullptr);
            }
        }

        if (fastExecution)
        {
            task->Run();
        }
        else
        {
            m_owner->owner->GetGame()->taskQueue.Enqueue(task);
        }

        if (removeAfterTriggered)
        {
            Remove();
        }
    }

    m_isValidated = false;
}

void Trigger::Validate(Player* player, Entity* source)
{
    switch (triggerSource)
    {
        case TriggerSource::NONE:
            break;
        case TriggerSource::SELF:
            if (source != m_owner)
            {
                return;
            }
            break;
        case TriggerSource::HERO:
            if (dynamic_cast<Hero*>(source) == nullptr ||
                source->owner != m_owner->owner)
            {
                return;
            }
            break;
        case TriggerSource::ALL_MINIONS:
            if (dynamic_cast<Minion*>(source) == nullptr)
            {
                return;
            }
            break;
        case TriggerSource::MINIONS_EXCEPT_SELF:
            if (dynamic_cast<Minion*>(source) == nullptr ||
                source->owner != m_owner->owner || source == m_owner)
            {
                return;
            }
            break;
        case TriggerSource::ENCHANTMENT_TARGET:
        {
            const auto enchantment = dynamic_cast<Enchantment*>(m_owner);
            if (enchantment == nullptr ||
                enchantment->GetTarget()->id != source->id)
            {
                return;
            }
            break;
        }
        case TriggerSource::FRIENDLY:
        {
            if (source->owner != m_owner->owner)
            {
                return;
            }
            break;
        }
        default:
            throw std::invalid_argument(
                "Trigger::Validate() - Invalid source trigger!");
    }

    switch (m_triggerType)
    {
        case TriggerType::TURN_START:
        case TriggerType::TURN_END:
            if (player != m_owner->owner)
            {
                return;
            }
            break;
        case TriggerType::PLAY_CARD:
        case TriggerType::SUMMON:
            if (source == m_owner)
            {
                return;
            }
            break;
        default:
            break;
    }

    if (condition != nullptr)
    {
        const bool res = (source != nullptr) ? condition->Evaluate(source)
                                             : condition->Evaluate(m_owner);

        if (!res)
        {
            return;
        }
    }

    m_isValidated = true;
}
}  // namespace RosettaStone
<|endoftext|>


<commit_before>/************************************************
 * 该例程是守护进程和看门狗进程的编程实现
************************************************/
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/param.h>  // NOFILE
#include <sys/stat.h>   // umask
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

void childProcessFunc()
{
    FILE* file = NULL;
    time_t t = 0;
    int i = 0;

    // 每隔5秒向test.log报告运行状态
    while (true)
    {
        ++i;
        sleep(5);
        file = fopen("./var/test.log", "a+");
        if (file != NULL)
        {
            t = time(NULL);
            fprintf(file, "i: %d, I am here at %s\n", i, asctime(localtime(&t)));
            fclose(file);
        }

        if (i == 5)
        {
            // 子进程主动退出
            exit(0);
        }
    }
}

void forkChildProcess(int)
{
    int status = 0;
    // 等待子进程中断或终止，释放子进程资源
    // 否则死掉的子进程会变成僵尸进程
    int pid = wait(&status);
    if (pid < 0)
    {
        printf("error: %s\n", strerror(errno));
        return;
    }

    // 如果子进程是由于某种信号退出的，捕获该信号
    if (WIFSIGNALED(status))
    {
        int signalNum = WTERMSIG(status);
        printf("Child process was killed by signal num: %d\n", signalNum);
    }

    // 等待3秒钟重新启动子进程
    sleep(3);

    pid = fork();
    if (pid == 0)
    {
        printf("Fork new child process\n");
        childProcessFunc();
    }
}

bool initWatchDog()
{
    int pid = fork();
    if (pid)
    {
        // 父进程一直监视子进程的运行状态
        while (true)
        {
            // 捕获子进程结束信号
            signal(SIGCHLD, forkChildProcess);
            // 父进程挂起，当有信号来时被唤醒
            pause();
        }
    }
    else if (pid < 0)
    {
        return false;
    }

    return true;
}

bool initDaemon()
{
    // 屏蔽一些有关控制终端操作的信号
    // 防止守护进程没有正常运转起来时，因控制终端受到干扰退出或挂起
    signal(SIGINT, SIG_IGN); // 终端中断
    signal(SIGHUP, SIG_IGN); // 连接挂断
    signal(SIGQUIT, SIG_IGN);// 终端退出
    signal(SIGPIPE, SIG_IGN);// 向无读进程的管道写数据
    signal(SIGTTOU, SIG_IGN);// 后台程序尝试写操作
    signal(SIGTTIN, SIG_IGN);// 后台程序尝试读操作
    signal(SIGTERM, SIG_IGN);// 终止

    // [1] 创建一个子进程，父进程退出
    int pid = fork();
    if (pid)
    {
        // 父进程退出
        exit(0);
    }
    else if (pid < 0)
    {
        return false;
    }

    // 子进程继续运行

    // [2] 在子进程中创建新的会话，setsid有三个作用
    // a.让进程摆脱原会话的控制
    // b.让进程摆脱原进程组的控制
    // c.让进程摆脱原控制终端的控制
    int ret = setsid();
    if (ret < 0)
    {
        return false;
    }

    // [3] 禁止进程重新打开控制终端
    // 进程已经成为无终端的会话组长，但它可以重新申请打开一个控制终端
    // 可以通过使进程不再成为会话组长来禁止进程重新打开控制终端
    pid = fork();
    if (pid)
    {
        // 结束第一个子进程
        exit(0);
    }
    else if (pid < 0)
    {
        return false;
    }

    // 第二个子进程继续运行

    // [4] 关闭打开的文件描述符
    // 进程从创建它的父进程那里继承了打开的文件描述符，如果不关闭，将会浪费系统资源，
    // 造成进程所在的文件系统无法卸下以及引起无法预料的错误
    for (int i = 0; i < NOFILE; ++i)
    {
        close(i);
    }

    // [5] 改变当前工作目录
    // 进程活动时，其工作目录所在的文件系统不能卸下，一般将工作目录改变到根目录
    ret = chdir("/");
    if (ret < 0)
    {
        return false;
    }

    // [6] 重新设置文件创建掩码
    // 进程从创建它的父进程那里继承了文件创建掩码，它可能修改守护进程所创建的文件的存取位
    // 所以将文件创建掩码清除
    umask(0);

    return true;
}

int main()
{
    // 注意：要编写带有看门狗并且后台运行的程序
    // 需要先初始化守护进程（让该程序成为后台程序）
    // 然后才初始化看门狗进程

    // 初始化守护进程
    bool ret = initDaemon();
    if (!ret)
    {
        return 1;
    }

    // 初始化看门狗进程
    ret = initWatchDog();
    if (!ret)
    {
        return 1;
    }

    // 运行子进程代码
    childProcessFunc();

    return 0;
}
<commit_msg>Update DaemonAndWatchDog<commit_after>/************************************************
 * 该例程是守护进程和看门狗进程的编程实现
************************************************/
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/param.h>  // NOFILE
#include <sys/stat.h>   // umask
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <assert.h>

void childProcessFunc()
{
    FILE* file = NULL;
    time_t t = 0;
    int i = 0;

    // 每隔5秒向test.log报告运行状态
    while (true)
    {
        ++i;
        sleep(5);
        file = fopen("./var/test.log", "a+");
        if (file != NULL)
        {
            t = time(NULL);
            fprintf(file, "i: %d, I am here at %s\n", i, asctime(localtime(&t)));
            fclose(file);
        }

        if (i == 5)
        {
            // 子进程主动退出
            exit(0);
        }
    }
}

void forkChildProcess(int)
{
    int status = 0;
    // 等待子进程中断或终止，释放子进程资源
    // 否则死掉的子进程会变成僵尸进程
    int pid = wait(&status);
    if (pid < 0)
    {
        printf("error: %s\n", strerror(errno));
        return;
    }

    // 如果子进程是由于某种信号退出的，捕获该信号
    if (WIFSIGNALED(status))
    {
        int signalNum = WTERMSIG(status);
        printf("Child process was killed by signal num: %d\n", signalNum);
    }

    // 等待3秒钟重新启动子进程
    sleep(3);

    pid = fork();
    if (pid == 0)
    {
        printf("Fork new child process\n");
        childProcessFunc();
    }
}

bool initWatchDog()
{
    int pid = fork();
    if (pid)
    {
        // 父进程一直监视子进程的运行状态
        while (true)
        {
            // 捕获子进程结束信号
            assert(signal(SIGCHLD, forkChildProcess) != SIG_ERR);
            // 父进程挂起，当有信号来时被唤醒
            pause();
        }
    }
    else if (pid < 0)
    {
        return false;
    }

    return true;
}

bool initDaemon()
{
    // 屏蔽一些有关控制终端操作的信号
    // 防止守护进程没有正常运转起来时，因控制终端受到干扰退出或挂起
    assert(signal(SIGINT, SIG_IGN) != SIG_ERR); // 终端中断
    assert(signal(SIGHUP, SIG_IGN) != SIG_ERR); // 连接挂断
    assert(signal(SIGQUIT, SIG_IGN) != SIG_ERR);// 终端退出
    assert(signal(SIGPIPE, SIG_IGN) != SIG_ERR);// 向无读进程的管道写数据
    assert(signal(SIGTTOU, SIG_IGN) != SIG_ERR);// 后台程序尝试写操作
    assert(signal(SIGTTIN, SIG_IGN) != SIG_ERR);// 后台程序尝试读操作
    assert(signal(SIGTERM, SIG_IGN) != SIG_ERR);// 终止

    // [1] 创建一个子进程，父进程退出
    int pid = fork();
    if (pid)
    {
        // 父进程退出
        exit(0);
    }
    else if (pid < 0)
    {
        return false;
    }

    // 子进程继续运行

    // [2] 在子进程中创建新的会话，setsid有三个作用
    // a.让进程摆脱原会话的控制
    // b.让进程摆脱原进程组的控制
    // c.让进程摆脱原控制终端的控制
    int ret = setsid();
    if (ret < 0)
    {
        return false;
    }

    // [3] 禁止进程重新打开控制终端
    // 进程已经成为无终端的会话组长，但它可以重新申请打开一个控制终端
    // 可以通过使进程不再成为会话组长来禁止进程重新打开控制终端
    pid = fork();
    if (pid)
    {
        // 结束第一个子进程
        exit(0);
    }
    else if (pid < 0)
    {
        return false;
    }

    // 第二个子进程继续运行

    // [4] 关闭打开的文件描述符
    // 进程从创建它的父进程那里继承了打开的文件描述符，如果不关闭，将会浪费系统资源，
    // 造成进程所在的文件系统无法卸下以及引起无法预料的错误
    for (int i = 0; i < NOFILE; ++i)
    {
        close(i);
    }

    // [5] 改变当前工作目录
    // 进程活动时，其工作目录所在的文件系统不能卸下，一般将工作目录改变到根目录
    ret = chdir("/");
    if (ret < 0)
    {
        return false;
    }

    // [6] 重新设置文件创建掩码
    // 进程从创建它的父进程那里继承了文件创建掩码，它可能修改守护进程所创建的文件的存取位
    // 所以将文件创建掩码清除
    umask(0);

    return true;
}

int main()
{
    // 注意：要编写带有看门狗并且后台运行的程序
    // 需要先初始化守护进程（让该程序成为后台程序）
    // 然后才初始化看门狗进程

    // 初始化守护进程
    bool ret = initDaemon();
    if (!ret)
    {
        return 1;
    }

    // 初始化看门狗进程
    ret = initWatchDog();
    if (!ret)
    {
        return 1;
    }

    // 运行子进程代码
    childProcessFunc();

    return 0;
}
<|endoftext|>


<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2009 Scientific Computing and Imaging Institute,
   University of Utah.

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

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

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

#include <Modules/Legacy/Fields/GetFieldBoundary.h>
#include <Core/Algorithms/Legacy/Fields/MeshDerivatives/GetFieldBoundary.h>

using namespace SCIRun;
using namespace SCIRun::Core::Datatypes;
using namespace SCIRun::Dataflow::Networks;
using namespace SCIRun::Modules::Fields;

GetFieldBoundary::GetFieldBoundary()
  : Module(ModuleLookupInfo("GetFieldBoundary", "NewField", "SCIRun"), false)
{
  algo_ = algoFactory_->create(get_module_name(), getLogger());
}

void
GetFieldBoundary::execute()
{
  FieldHandle field;

  get_input_handle("Field",field,true);

  // If parameters changed, do algorithm
  if (inputs_changed_ ||
      !oport_cached("BoundaryField") ||
      !oport_cached("Mapping"))
  {
    update_state(Executing);

    // Output dataflow objects:
    FieldHandle ofield;
    MatrixHandle mapping;

    // Entry point to algorithm
    if (!(algo_.run(field,ofield,mapping))) return;

    // Send Data flow objects downstream
    send_output_handle("BoundaryField", ofield);
    send_output_handle("Mapping", mapping);
  }
}
<commit_msg>Remove superfluous comments<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2009 Scientific Computing and Imaging Institute,
   University of Utah.

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

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

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

#include <Modules/Legacy/Fields/GetFieldBoundary.h>
#include <Core/Algorithms/Legacy/Fields/MeshDerivatives/GetFieldBoundary.h>

using namespace SCIRun;
using namespace SCIRun::Core::Datatypes;
using namespace SCIRun::Dataflow::Networks;
using namespace SCIRun::Modules::Fields;

GetFieldBoundary::GetFieldBoundary()
  : Module(ModuleLookupInfo("GetFieldBoundary", "NewField", "SCIRun"), false)
{
  algo_ = algoFactory_->create(get_module_name(), getLogger());
}

void
GetFieldBoundary::execute()
{
  FieldHandle field;

  get_input_handle("Field",field,true);

  // If parameters changed, do algorithm
  if (inputs_changed_ ||
      !oport_cached("BoundaryField") ||
      !oport_cached("Mapping"))
  {
    update_state(Executing);

    FieldHandle ofield;
    MatrixHandle mapping;

    if (!(algo_.run(field,ofield,mapping))) return;

    send_output_handle("BoundaryField", ofield);
    send_output_handle("Mapping", mapping);
  }
}
<|endoftext|>


<commit_before>#include <math.h>
#include <iostream>
#include <vector>

using namespace std;

void printVect(vector<int> v){
	int size = v.size();
	for (int i = 0; i < size; i++){
		cout << v.at(i) << " ";
	}
}

vector<int> DivideAndConquere(vector<int> v){
	int size = v.size();
	int half_size = size / 2;
	if (size < 1){
		cout << "Error size is " << size << endl;
		return  v;
	}
	if (size == 1) {
		cout << "out vector " << v[0] << endl;
		return v;
	}

	printVect(v); cout << "--->";
	vector<int> v_out(size);
	vector<int> v_left(v.begin(), v.begin() + size - half_size);
	printVect(v_left); cout << "----";
	vector<int> v_right(v.begin() + size - half_size, v.end());
	printVect(v_right); cout << endl;

	v_left = DivideAndConquere(v_left);
	v_right = DivideAndConquere(v_right);

	//merge
	int left = 0;
	int right = 0;
	for (int i = 0; i < size; i++){
		if ((left >= size - half_size) || (v_right[right] < v_left[left])){
			v_out[i] = v_right[right];
			right++;
		}
		else{
			if ((right >= half_size) || (v_left[left] < v_right[right])){
				v_out[i] = v_left[left];
				left++;
			}
		}
	}
	cout << "out vector ";
	printVect(v_out); cout << endl;

	return v_out;
}

void DivideAndConquereAndTest(){
	vector <int> v = { 38, 27, 43, 3, 9, 82, 10 };
	cout << endl << "un-ordered vector ";
	printVect(v); cout << endl;

	v = DivideAndConquere(v);
	cout << endl << "ordered vector ";
	printVect(v); cout << endl;
}

int main(int argc, char* argv[])
{
	//KaratsubaMultiplicationAndTest();
	DivideAndConquereAndTest();
	system("pause");
	return 0;
}

<commit_msg>rename DivideAndConquere fonction to MergeAnd Sort<commit_after>#include <math.h>
#include <iostream>
#include <vector>

using namespace std;

void printVect(vector<int> v){
	int size = v.size();
	for (int i = 0; i < size; i++){
		cout << v.at(i) << " ";
	}
}

vector<int> MergeAndSort(vector<int> v){
	int size = v.size();
	int half_size = size / 2;
	if (size < 1){
		cout << "Error size is " << size << endl;
		return  v;
	}
	if (size == 1) {
		cout << "out vector " << v[0] << endl;
		return v;
	}

	printVect(v); cout << "--->";
	vector<int> v_out(size);
	vector<int> v_left(v.begin(), v.begin() + size - half_size);
	printVect(v_left); cout << "----";
	vector<int> v_right(v.begin() + size - half_size, v.end());
	printVect(v_right); cout << endl;

	v_left = MergeAndSort(v_left);
	v_right = MergeAndSort(v_right);

	//merge
	int left = 0;
	int right = 0;
	for (int i = 0; i < size; i++){
		if ((left >= size - half_size) || (v_right[right] < v_left[left])){
			v_out[i] = v_right[right];
			right++;
		}
		else{
			if ((right >= half_size) || (v_left[left] < v_right[right])){
				v_out[i] = v_left[left];
				left++;
			}
		}
	}
	cout << "out vector ";
	printVect(v_out); cout << endl;

	return v_out;
}

void MergeAndSortAndTest(){
	vector <int> v = { 38, 27, 43, 3, 9, 82, 10 };
	cout << endl << "un-ordered vector ";
	printVect(v); cout << endl;

	v = MergeAndSort(v);
	cout << endl << "ordered vector ";
	printVect(v); cout << endl;
}

int main(int argc, char* argv[])
{
	MergeAndSortAndTest();
	system("pause");
	return 0;
}

<|endoftext|>


<commit_before>#include <boost/test/unit_test.hpp>

#include "core/connection.hpp"
#include "ports/events/event_sink_with_queue.hpp"
#include "ports/event_ports.hpp"
#include <vector>
#include <algorithm>
#include "move_token.hpp"

using namespace fc;

BOOST_AUTO_TEST_SUITE(test_tokens_testing)

BOOST_AUTO_TEST_CASE( move_token_ )
{
	// no default constructor
	// how to test for "does not compile"?
//	move_token t;

	// non-copyable
	move_token t("foo");
	move_token u(move_token("bar"));

	std::vector<move_token> v(10);
	std::sort(v.begin(), v.end());
	v.push_back(move_token("foo"));
}

BOOST_AUTO_TEST_CASE( moving )
{
	auto set_bar = [](auto&& t) -> move_token&& { t.value() = "bar"; return std::move(t); };
//	auto set_bar = [](move_token&& t) { t.value() = "bar"; return std::move(t); };

	event_out_port<move_token&&> source;
	event_in_port<move_token> sink([](move_token&& t){ std::cout << "move: " << t.value() << "\n";});

	std::function<void(move_token&&)> bla = sink;
	source >> set_bar >> bla;
	source.fire(move_token("foo"));
}

//test case to make sure objects are not move if we don't want them to be
BOOST_AUTO_TEST_CASE( non_moving )
{
	typedef std::shared_ptr<int> non_move; //shared_ptr is nulled after move, so we can check
	event_out_port<non_move> source;
	bool moved = false;
	event_in_port<non_move> sink([&moved](non_move&& t){ moved = !t.operator bool() ;});
	event_in_port<non_move> sink2([&moved](non_move&& t){ moved = !t.operator bool() ;});

	source >> sink;

	source.fire(std::make_shared<int>(1));
	BOOST_CHECK(!moved);

	source >> sink2; //now we have two connections
	source.fire(std::make_shared<int>(1));
	BOOST_CHECK(!moved);

}

BOOST_AUTO_TEST_SUITE_END()

<commit_msg>added first test for moving state, currently fails<commit_after>#include <boost/test/unit_test.hpp>

#include "core/connection.hpp"
#include "ports/events/event_sink_with_queue.hpp"
#include "ports/event_ports.hpp"
#include "ports/state_ports.hpp"

#include <vector>
#include <algorithm>
#include "move_token.hpp"

using namespace fc;

BOOST_AUTO_TEST_SUITE(test_tokens_testing)

BOOST_AUTO_TEST_CASE( move_token_ )
{
	// no default constructor
	// how to test for "does not compile"?
//	move_token t;

	// non-copyable
	move_token t("foo");
	move_token u(move_token("bar"));

	std::vector<move_token> v(10);
	std::sort(v.begin(), v.end());
	v.push_back(move_token("foo"));
}

BOOST_AUTO_TEST_CASE( moving_events )
{
	auto set_bar = [](auto&& t) -> move_token&& { t.value() = "bar"; return std::move(t); };
//	auto set_bar = [](move_token&& t) { t.value() = "bar"; return std::move(t); };

	event_out_port<move_token&&> source;
	event_in_port<move_token> sink([](move_token&& t){ std::cout << "move: " << t.value() << "\n";});

	std::function<void(move_token&&)> bla = sink;
	source >> set_bar >> bla;
	source.fire(move_token("foo"));
}

BOOST_AUTO_TEST_CASE( moving_state )
{
	auto set_bar = [](auto&& t) -> move_token&& { t.value() = "bar"; return std::move(t); };
	state_sink<move_token> sink;
	state_source_call_function<move_token> source([](){ return move_token("foo"); });

	source >> set_bar >> sink;
	BOOST_CHECK_EQUAL(sink.get().value(), "bar");

}

//test case to make sure objects are not move if we don't want them to be
BOOST_AUTO_TEST_CASE( non_moving )
{
	typedef std::shared_ptr<int> non_move; //shared_ptr is nulled after move, so we can check
	event_out_port<non_move> source;
	bool moved = false;
	event_in_port<non_move> sink([&moved](non_move&& t){ moved = !t.operator bool() ;});
	event_in_port<non_move> sink2([&moved](non_move&& t){ moved = !t.operator bool() ;});

	source >> sink;

	source.fire(std::make_shared<int>(1));
	BOOST_CHECK(!moved);

	source >> sink2; //now we have two connections
	source.fire(std::make_shared<int>(1));
	BOOST_CHECK(!moved);

}

BOOST_AUTO_TEST_SUITE_END()

<|endoftext|>


<commit_before>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  You may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */

#include <seastar/core/reactor.hh>
#include <seastar/core/app-template.hh>
#include <seastar/core/print.hh>
#include <seastar/core/shared_ptr.hh>

using namespace seastar;

int main(int ac, char** av) {
    class lister {
        file _f;
        subscription<directory_entry> _listing;
    public:
        lister(file f)
                : _f(std::move(f))
                , _listing(_f.list_directory([this] (directory_entry de) { return report(de); })) {
        }
        future<> done() { return _listing.done(); }
    private:
        future<> report(directory_entry de) {
            fmt::print("{}\n", de.name);
            return make_ready_future<>();
        }
    };
    return app_template().run_deprecated(ac, av, [] {
        return engine().open_directory(".").then([] (file f) {
            auto l = make_lw_shared<lister>(std::move(f));
            return l->done().then([l] {
                // ugly thing to keep *l alive
                engine().exit(0);
            });
        });
    });
}
<commit_msg>directory_test: incorporate file_stat<commit_after>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  You may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */

#include <seastar/core/reactor.hh>
#include <seastar/core/app-template.hh>
#include <seastar/core/print.hh>
#include <seastar/core/shared_ptr.hh>

using namespace seastar;

const char* de_type_desc(directory_entry_type t)
{
    switch (t) {
    case directory_entry_type::unknown:
        return "unknown";
    case directory_entry_type::block_device:
        return "block_device";
    case directory_entry_type::char_device:
        return "char_device";
    case directory_entry_type::directory:
        return "directory";
    case directory_entry_type::fifo:
        return "fifo";
    case directory_entry_type::link:
        return "link";
    case directory_entry_type::regular:
        return "regular";
    case directory_entry_type::socket:
        return "socket";
    }
    assert(0 && "should not get here");
    return nullptr;
}

int main(int ac, char** av) {
    class lister {
        file _f;
        subscription<directory_entry> _listing;
    public:
        lister(file f)
                : _f(std::move(f))
                , _listing(_f.list_directory([this] (directory_entry de) { return report(de); })) {
        }
        future<> done() { return _listing.done(); }
    private:
        future<> report(directory_entry de) {
            return file_stat(de.name, follow_symlink::no).then([de = std::move(de)] (stat_data sd) {
                if (de.type) {
                    assert(*de.type == sd.type);
                } else {
                    assert(sd.type == directory_entry_type::unknown);
                }
                fmt::print("{} (type={})\n", de.name, de_type_desc(sd.type));
                return make_ready_future<>();
            });
        }
    };
    return app_template().run_deprecated(ac, av, [] {
        return engine().open_directory(".").then([] (file f) {
            auto l = make_lw_shared<lister>(std::move(f));
            return l->done().then([l] {
                // ugly thing to keep *l alive
                engine().exit(0);
            });
        });
    });
}
<|endoftext|>


<commit_before>//
// RemotePhotoTool - remote camera control software
// Copyright (C) 2008-2014 Michael Fink
//
/// \file ViewFinderImageWindow.cpp Viewfinder image window
//

// includes
#include "stdafx.h"
#include "ViewFinderImageWindow.hpp"
#include "Viewfinder.hpp"
#include "JpegMemoryReader.hpp"
#include "Logging.hpp"

/// ratio to draw lines for "golden ratio" mode
const double c_dGoldenRatio = 0.618;

/// number of milliseconds until zebra pattern is moved to the right
const unsigned int c_uiZebraPatternMovementInMs = 300;

ViewFinderImageWindow::ViewFinderImageWindow()
:m_uiResX(0),
 m_uiResY(0),
 m_enLinesMode(linesModeNoLines),
 m_bShowZebraPattern(false),
 m_bShowHistogram(false)
{
   SetupZebraBrush();
}

ViewFinderImageWindow::~ViewFinderImageWindow() throw()
{
   m_brushZebraPattern.DeleteObject();
}

void ViewFinderImageWindow::EnableUpdate(bool bEnable)
{
   if (bEnable)
   {
      if (m_spViewfinder != nullptr)
         m_spViewfinder->SetAvailImageHandler(
            std::bind(&ViewFinderImageWindow::OnAvailViewfinderImage, this, std::placeholders::_1));
   }
   else
   {
      m_spViewfinder->SetAvailImageHandler();
   }
}

void ViewFinderImageWindow::SetViewfinder(std::shared_ptr<Viewfinder> spViewfinder)
{
   if (spViewfinder == nullptr && m_spViewfinder != nullptr)
   {
      m_spViewfinder->SetAvailImageHandler();
      SetBitmap(NULL);
   }

   m_spViewfinder = spViewfinder;

   if (spViewfinder != nullptr)
      EnableUpdate(true);
}

void ViewFinderImageWindow::OnAvailViewfinderImage(const std::vector<BYTE>& vecImage)
{
   if (m_spViewfinder == nullptr)
      return;

   if (vecImage.empty())
      return;

   //{
   //   static DWORD s_dwLastCall = GetTickCount();
   //   DWORD dwNow = GetTickCount();
   //   ATLTRACE(_T("last view finder image was %u ms ago\n"), dwNow - s_dwLastCall);
   //
   //   s_dwLastCall = dwNow;
   //}

   DecodeJpegImage(vecImage);

   if (IsWindow())
      PostMessage(WM_VIEWFINDER_AVAIL_IMAGE);
}

LRESULT ViewFinderImageWindow::OnMessageViewfinderAvailImage(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
   CBitmapHandle bmp;

   CreateBitmap(bmp);
   SetBitmap(bmp);

   // invalidate control to force redraw
   Invalidate();

   TraceViewfinderFps();

   return 0;
}

void ViewFinderImageWindow::SetupZebraBrush()
{
   const WORD c_bitsZebraPatternBrush[8] = { 0x9f, 0x3f, 0x7e, 0xfc, 0xf9, 0xf3, 0xe7, 0xcf };

   CBitmap bmZebraPattern;
   bmZebraPattern.CreateBitmap(8, 8, 1, 1, c_bitsZebraPatternBrush);

   LOGBRUSH logBrush = { 0 };
   logBrush.lbStyle = BS_PATTERN;
   logBrush.lbHatch = (ULONG_PTR)bmZebraPattern.m_hBitmap;
   logBrush.lbColor = RGB(192, 192, 192);

   m_brushZebraPattern.CreateBrushIndirect(&logBrush);
}

void ViewFinderImageWindow::DecodeJpegImage(const std::vector<BYTE>& vecImage)
{
   //DWORD dwStart = GetTickCount();
   JpegMemoryReader jpegReader(vecImage);

   try
   {
      jpegReader.Read();
   }
   catch(...)
   {
      static bool s_bWarnedAboutJPEG = false;
      if (!s_bWarnedAboutJPEG)
      {
         LOG_TRACE(_T("DecodeJpegImage: failed loading JPEG!\n"));
         s_bWarnedAboutJPEG = true;
      }
      return;
   }

   //DWORD dwEnd = GetTickCount();
   //ATLTRACE(_T("decoding jpg took %u ms\n"), dwEnd - dwStart);

   std::vector<BYTE>& vecBitmapData = jpegReader.BitmapData();

   JpegImageInfo imageInfo = jpegReader.ImageInfo();

   {
      LightweightMutex::LockType lock(m_mtxViewfinderData);
      std::swap(m_vecCurrentViewfinderData, vecBitmapData);

      m_uiResX = imageInfo.Width();
      m_uiResY = imageInfo.Height();
   }
}

void ViewFinderImageWindow::MakeOverexposedTransparent(std::vector<BYTE>& vecBitmapData)
{
   ATLASSERT((vecBitmapData.size() % 3) == 0);

   size_t uiValues = vecBitmapData.size() / 3;

   // 0xff means fully opaque
   std::vector<BYTE> vecTransparentBitmapData(uiValues * 4, 0xff);

   for (size_t ui = 0; ui < uiValues; ui++)
   {
      memcpy(&vecTransparentBitmapData[ui * 4], &vecBitmapData[ui * 3], 3);

      if (vecBitmapData[ui * 3 + 0] == 0xff ||
          vecBitmapData[ui * 3 + 1] == 0xff ||
          vecBitmapData[ui * 3 + 2] == 0xff)
      {
         vecTransparentBitmapData[ui * 4 + 3] = 0; // make transparent
      }
   }

   vecBitmapData.swap(vecTransparentBitmapData);
}

void ViewFinderImageWindow::CreateBitmap(CBitmapHandle& bmp)
{
   BITMAPINFO bi = {0};

   BITMAPINFOHEADER& bih = bi.bmiHeader;
   bih.biSize = sizeof(bih);
   bih.biBitCount = 24;
   bih.biClrUsed = 0;
   bih.biCompression = BI_RGB;
   bih.biPlanes = 1;

   bih.biHeight = -static_cast<LONG>(m_uiResY); // negative, since bytes represent a top-bottom DIB
   bih.biWidth = m_uiResX;

   BITMAPINFOHEADER* lpbmih = &bih;
   BITMAPINFO* lpbmi = &bi;

   {
      LightweightMutex::LockType lock(m_mtxViewfinderData);

      LPCVOID lpDIBBits = m_vecCurrentViewfinderData.data();

      CClientDC dc(m_hWnd);
      bmp.CreateDIBitmap(dc, lpbmih, CBM_INIT, lpDIBBits, lpbmi, DIB_RGB_COLORS);
   }
}

void ViewFinderImageWindow::SetBitmap(CBitmapHandle bmpViewfinder)
{
   m_bmpViewfinder = bmpViewfinder;
}

void ViewFinderImageWindow::TraceViewfinderFps()
{
   static unsigned int s_uiViewfinderImageCount = 0;
   static DWORD s_dwLastFpsTime = GetTickCount();

   s_uiViewfinderImageCount++;

   DWORD dwNow = GetTickCount();

   DWORD dwElapsed = dwNow - s_dwLastFpsTime;
   if (dwElapsed > 500)
   {
      CString cszText;
      cszText.Format(_T("Viewfinder: %u fps"), s_uiViewfinderImageCount * 1000 / dwElapsed);
      ATLTRACE(_T("%s\n"), cszText);

      s_uiViewfinderImageCount = 0;
      s_dwLastFpsTime = dwNow;
   }
}

void ViewFinderImageWindow::ScaleBitmapSize(const BITMAP& bm, int& iWidth, int& iHeight)
{
   CRect rcWindow;
   GetClientRect(rcWindow);

   double dRatioWindow = rcWindow.Height() == 0 ? 1.0 : (double(rcWindow.Width()) / rcWindow.Height());
   double dRatioBitmap = bm.bmHeight == 0 ? 1.0 : (double(bm.bmWidth) / bm.bmHeight);

   if (dRatioBitmap < dRatioWindow)
      iWidth = int(iHeight * dRatioBitmap);
   else
      iHeight = int(iWidth / dRatioBitmap);
}

void ViewFinderImageWindow::DrawLines(CDC& dc, int iWidth, int iHeight)
{
   // pen color is the inverse of the background color
   int iLastDrawMode = dc.SetROP2(R2_NOTXORPEN);

   CPen pen;
   pen.CreatePen(PS_DOT, 3, RGB(0, 0, 0));
   CPenHandle oldPen = dc.SelectPen(pen);

   double dRatio1 = 1.0 / 3.0;
   if (m_enLinesMode == linesModeGoldenRatio)
      dRatio1 = c_dGoldenRatio;

   double dRatio2 = 1.0 - dRatio1;

   // horizontal lines
   dc.MoveTo(0, int(iHeight * dRatio1));
   dc.LineTo(iWidth-1, int(iHeight * dRatio1));

   dc.MoveTo(0, int(iHeight * dRatio2));
   dc.LineTo(iWidth-1,int(iHeight * dRatio2));

   // vertical lines
   dc.MoveTo(int(iWidth * dRatio1), 0);
   dc.LineTo(int(iWidth * dRatio1), iHeight-1);

   dc.MoveTo(int(iWidth * dRatio2), 0);
   dc.LineTo(int(iWidth * dRatio2), iHeight-1);

   dc.SelectPen(oldPen);

   dc.SetROP2(iLastDrawMode);
}

void ViewFinderImageWindow::DrawZebraPattern(CDC& dc, int iWidth, int iHeight)
{
   // draw zebra pattern
   HBRUSH hOldBrush = dc.SelectBrush(m_brushZebraPattern);

   dc.SetBkMode(TRANSPARENT);
   dc.SetBkColor(RGB(255, 255, 255));

   // in order to move zebra pattern, set pattern brush origin
   DWORD dwNow = GetTickCount();
   int iOffset = (dwNow / c_uiZebraPatternMovementInMs) % 8;
   dc.SetBrushOrg(iOffset, 0);

   CRect rcImage(CPoint(0, 0), CSize(iWidth, iHeight));
   dc.Rectangle(&rcImage);

   dc.SelectBrush(hOldBrush);
}

LRESULT ViewFinderImageWindow::OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
   // disable erasing
   return FALSE;
}

LRESULT ViewFinderImageWindow::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
   CPaintDC dc(m_hWnd);

   if (m_bmpViewfinder.IsNull())
   {
      dc.FillSolidRect(&dc.m_ps.rcPaint, RGB(0,0,0));
      return 0;
   }

   // calculate bitmap size
   BITMAP bm = {0};
   GetObject(m_bmpViewfinder, sizeof(bm), &bm);

   CRect rcPaint(dc.m_ps.rcPaint);

   int iWidth = rcPaint.Width();
   int iHeight = rcPaint.Height();

   ScaleBitmapSize(bm, iWidth, iHeight);

   rcPaint = CRect(0, 0, iWidth, iHeight);

   // select bitmap into bitmap DC
   CDC bmpDC;
   bmpDC.CreateCompatibleDC();

   HBITMAP hbmT = bmpDC.SelectBitmap(m_bmpViewfinder);

   // draw to memory DC
   CMemoryDC memDC(dc, dc.m_ps.rcPaint);
   memDC.FillSolidRect(&dc.m_ps.rcPaint, ::GetSysColor(COLOR_3DFACE));

   // blit bitmap
   if (m_bShowZebraPattern)
   {
      DrawZebraPattern(memDC, iWidth, iHeight);

      // draw viewfinder bitmap with transparency
      memDC.TransparentBlt(0, 0, iWidth, iHeight, bmpDC, 0, 0, bm.bmWidth, bm.bmHeight, RGB(255,255,255));
   }
   else
      memDC.StretchBlt(0, 0, iWidth, iHeight, bmpDC, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);

   bmpDC.SelectBitmap(hbmT);

   // draw lines
   if (m_enLinesMode != linesModeNoLines)
      DrawLines(memDC, iWidth, iHeight);

   return 0;
}

LRESULT ViewFinderImageWindow::OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
   if (m_spViewfinder != nullptr)
   {
      m_spViewfinder->SetAvailImageHandler();
      m_spViewfinder.reset();
   }

   return 0;
}
<commit_msg>set StretchBlt mode to properly draw viewfinder image<commit_after>//
// RemotePhotoTool - remote camera control software
// Copyright (C) 2008-2014 Michael Fink
//
/// \file ViewFinderImageWindow.cpp Viewfinder image window
//

// includes
#include "stdafx.h"
#include "ViewFinderImageWindow.hpp"
#include "Viewfinder.hpp"
#include "JpegMemoryReader.hpp"
#include "Logging.hpp"

/// ratio to draw lines for "golden ratio" mode
const double c_dGoldenRatio = 0.618;

/// number of milliseconds until zebra pattern is moved to the right
const unsigned int c_uiZebraPatternMovementInMs = 300;

ViewFinderImageWindow::ViewFinderImageWindow()
:m_uiResX(0),
 m_uiResY(0),
 m_enLinesMode(linesModeNoLines),
 m_bShowZebraPattern(false),
 m_bShowHistogram(false)
{
   SetupZebraBrush();
}

ViewFinderImageWindow::~ViewFinderImageWindow() throw()
{
   m_brushZebraPattern.DeleteObject();
}

void ViewFinderImageWindow::EnableUpdate(bool bEnable)
{
   if (bEnable)
   {
      if (m_spViewfinder != nullptr)
         m_spViewfinder->SetAvailImageHandler(
            std::bind(&ViewFinderImageWindow::OnAvailViewfinderImage, this, std::placeholders::_1));
   }
   else
   {
      m_spViewfinder->SetAvailImageHandler();
   }
}

void ViewFinderImageWindow::SetViewfinder(std::shared_ptr<Viewfinder> spViewfinder)
{
   if (spViewfinder == nullptr && m_spViewfinder != nullptr)
   {
      m_spViewfinder->SetAvailImageHandler();
      SetBitmap(NULL);
   }

   m_spViewfinder = spViewfinder;

   if (spViewfinder != nullptr)
      EnableUpdate(true);
}

void ViewFinderImageWindow::OnAvailViewfinderImage(const std::vector<BYTE>& vecImage)
{
   if (m_spViewfinder == nullptr)
      return;

   if (vecImage.empty())
      return;

   //{
   //   static DWORD s_dwLastCall = GetTickCount();
   //   DWORD dwNow = GetTickCount();
   //   ATLTRACE(_T("last view finder image was %u ms ago\n"), dwNow - s_dwLastCall);
   //
   //   s_dwLastCall = dwNow;
   //}

   DecodeJpegImage(vecImage);

   if (IsWindow())
      PostMessage(WM_VIEWFINDER_AVAIL_IMAGE);
}

LRESULT ViewFinderImageWindow::OnMessageViewfinderAvailImage(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
   CBitmapHandle bmp;

   CreateBitmap(bmp);
   SetBitmap(bmp);

   // invalidate control to force redraw
   Invalidate();

   TraceViewfinderFps();

   return 0;
}

void ViewFinderImageWindow::SetupZebraBrush()
{
   const WORD c_bitsZebraPatternBrush[8] = { 0x9f, 0x3f, 0x7e, 0xfc, 0xf9, 0xf3, 0xe7, 0xcf };

   CBitmap bmZebraPattern;
   bmZebraPattern.CreateBitmap(8, 8, 1, 1, c_bitsZebraPatternBrush);

   LOGBRUSH logBrush = { 0 };
   logBrush.lbStyle = BS_PATTERN;
   logBrush.lbHatch = (ULONG_PTR)bmZebraPattern.m_hBitmap;
   logBrush.lbColor = RGB(192, 192, 192);

   m_brushZebraPattern.CreateBrushIndirect(&logBrush);
}

void ViewFinderImageWindow::DecodeJpegImage(const std::vector<BYTE>& vecImage)
{
   //DWORD dwStart = GetTickCount();
   JpegMemoryReader jpegReader(vecImage);

   try
   {
      jpegReader.Read();
   }
   catch(...)
   {
      static bool s_bWarnedAboutJPEG = false;
      if (!s_bWarnedAboutJPEG)
      {
         LOG_TRACE(_T("DecodeJpegImage: failed loading JPEG!\n"));
         s_bWarnedAboutJPEG = true;
      }
      return;
   }

   //DWORD dwEnd = GetTickCount();
   //ATLTRACE(_T("decoding jpg took %u ms\n"), dwEnd - dwStart);

   std::vector<BYTE>& vecBitmapData = jpegReader.BitmapData();

   JpegImageInfo imageInfo = jpegReader.ImageInfo();

   {
      LightweightMutex::LockType lock(m_mtxViewfinderData);
      std::swap(m_vecCurrentViewfinderData, vecBitmapData);

      m_uiResX = imageInfo.Width();
      m_uiResY = imageInfo.Height();
   }
}

void ViewFinderImageWindow::MakeOverexposedTransparent(std::vector<BYTE>& vecBitmapData)
{
   ATLASSERT((vecBitmapData.size() % 3) == 0);

   size_t uiValues = vecBitmapData.size() / 3;

   // 0xff means fully opaque
   std::vector<BYTE> vecTransparentBitmapData(uiValues * 4, 0xff);

   for (size_t ui = 0; ui < uiValues; ui++)
   {
      memcpy(&vecTransparentBitmapData[ui * 4], &vecBitmapData[ui * 3], 3);

      if (vecBitmapData[ui * 3 + 0] == 0xff ||
          vecBitmapData[ui * 3 + 1] == 0xff ||
          vecBitmapData[ui * 3 + 2] == 0xff)
      {
         vecTransparentBitmapData[ui * 4 + 3] = 0; // make transparent
      }
   }

   vecBitmapData.swap(vecTransparentBitmapData);
}

void ViewFinderImageWindow::CreateBitmap(CBitmapHandle& bmp)
{
   BITMAPINFO bi = {0};

   BITMAPINFOHEADER& bih = bi.bmiHeader;
   bih.biSize = sizeof(bih);
   bih.biBitCount = 24;
   bih.biClrUsed = 0;
   bih.biCompression = BI_RGB;
   bih.biPlanes = 1;

   bih.biHeight = -static_cast<LONG>(m_uiResY); // negative, since bytes represent a top-bottom DIB
   bih.biWidth = m_uiResX;

   BITMAPINFOHEADER* lpbmih = &bih;
   BITMAPINFO* lpbmi = &bi;

   {
      LightweightMutex::LockType lock(m_mtxViewfinderData);

      LPCVOID lpDIBBits = m_vecCurrentViewfinderData.data();

      CClientDC dc(m_hWnd);
      bmp.CreateDIBitmap(dc, lpbmih, CBM_INIT, lpDIBBits, lpbmi, DIB_RGB_COLORS);
   }
}

void ViewFinderImageWindow::SetBitmap(CBitmapHandle bmpViewfinder)
{
   m_bmpViewfinder = bmpViewfinder;
}

void ViewFinderImageWindow::TraceViewfinderFps()
{
   static unsigned int s_uiViewfinderImageCount = 0;
   static DWORD s_dwLastFpsTime = GetTickCount();

   s_uiViewfinderImageCount++;

   DWORD dwNow = GetTickCount();

   DWORD dwElapsed = dwNow - s_dwLastFpsTime;
   if (dwElapsed > 500)
   {
      CString cszText;
      cszText.Format(_T("Viewfinder: %u fps"), s_uiViewfinderImageCount * 1000 / dwElapsed);
      ATLTRACE(_T("%s\n"), cszText);

      s_uiViewfinderImageCount = 0;
      s_dwLastFpsTime = dwNow;
   }
}

void ViewFinderImageWindow::ScaleBitmapSize(const BITMAP& bm, int& iWidth, int& iHeight)
{
   CRect rcWindow;
   GetClientRect(rcWindow);

   double dRatioWindow = rcWindow.Height() == 0 ? 1.0 : (double(rcWindow.Width()) / rcWindow.Height());
   double dRatioBitmap = bm.bmHeight == 0 ? 1.0 : (double(bm.bmWidth) / bm.bmHeight);

   if (dRatioBitmap < dRatioWindow)
      iWidth = int(iHeight * dRatioBitmap);
   else
      iHeight = int(iWidth / dRatioBitmap);
}

void ViewFinderImageWindow::DrawLines(CDC& dc, int iWidth, int iHeight)
{
   // pen color is the inverse of the background color
   int iLastDrawMode = dc.SetROP2(R2_NOTXORPEN);

   CPen pen;
   pen.CreatePen(PS_DOT, 3, RGB(0, 0, 0));
   CPenHandle oldPen = dc.SelectPen(pen);

   double dRatio1 = 1.0 / 3.0;
   if (m_enLinesMode == linesModeGoldenRatio)
      dRatio1 = c_dGoldenRatio;

   double dRatio2 = 1.0 - dRatio1;

   // horizontal lines
   dc.MoveTo(0, int(iHeight * dRatio1));
   dc.LineTo(iWidth-1, int(iHeight * dRatio1));

   dc.MoveTo(0, int(iHeight * dRatio2));
   dc.LineTo(iWidth-1,int(iHeight * dRatio2));

   // vertical lines
   dc.MoveTo(int(iWidth * dRatio1), 0);
   dc.LineTo(int(iWidth * dRatio1), iHeight-1);

   dc.MoveTo(int(iWidth * dRatio2), 0);
   dc.LineTo(int(iWidth * dRatio2), iHeight-1);

   dc.SelectPen(oldPen);

   dc.SetROP2(iLastDrawMode);
}

void ViewFinderImageWindow::DrawZebraPattern(CDC& dc, int iWidth, int iHeight)
{
   // draw zebra pattern
   HBRUSH hOldBrush = dc.SelectBrush(m_brushZebraPattern);

   dc.SetBkMode(TRANSPARENT);
   dc.SetBkColor(RGB(255, 255, 255));

   // in order to move zebra pattern, set pattern brush origin
   DWORD dwNow = GetTickCount();
   int iOffset = (dwNow / c_uiZebraPatternMovementInMs) % 8;
   dc.SetBrushOrg(iOffset, 0);

   CRect rcImage(CPoint(0, 0), CSize(iWidth, iHeight));
   dc.Rectangle(&rcImage);

   dc.SelectBrush(hOldBrush);
}

LRESULT ViewFinderImageWindow::OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
   // disable erasing
   return FALSE;
}

LRESULT ViewFinderImageWindow::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
   CPaintDC dc(m_hWnd);

   if (m_bmpViewfinder.IsNull())
   {
      dc.FillSolidRect(&dc.m_ps.rcPaint, RGB(0,0,0));
      return 0;
   }

   // calculate bitmap size
   BITMAP bm = {0};
   GetObject(m_bmpViewfinder, sizeof(bm), &bm);

   CRect rcPaint(dc.m_ps.rcPaint);

   int iWidth = rcPaint.Width();
   int iHeight = rcPaint.Height();

   ScaleBitmapSize(bm, iWidth, iHeight);

   rcPaint = CRect(0, 0, iWidth, iHeight);

   // select bitmap into bitmap DC
   CDC bmpDC;
   bmpDC.CreateCompatibleDC();

   HBITMAP hbmT = bmpDC.SelectBitmap(m_bmpViewfinder);

   // draw to memory DC
   CMemoryDC memDC(dc, dc.m_ps.rcPaint);
   memDC.FillSolidRect(&dc.m_ps.rcPaint, ::GetSysColor(COLOR_3DFACE));

   // blit bitmap
   if (m_bShowZebraPattern)
   {
      DrawZebraPattern(memDC, iWidth, iHeight);

      // draw viewfinder bitmap with transparency
      memDC.TransparentBlt(0, 0, iWidth, iHeight, bmpDC, 0, 0, bm.bmWidth, bm.bmHeight, RGB(255,255,255));
   }
   else
   {
      memDC.SetStretchBltMode(COLORONCOLOR);
      memDC.StretchBlt(0, 0, iWidth, iHeight, bmpDC, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
   }

   bmpDC.SelectBitmap(hbmT);

   // draw lines
   if (m_enLinesMode != linesModeNoLines)
      DrawLines(memDC, iWidth, iHeight);

   return 0;
}

LRESULT ViewFinderImageWindow::OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
   if (m_spViewfinder != nullptr)
   {
      m_spViewfinder->SetAvailImageHandler();
      m_spViewfinder.reset();
   }

   return 0;
}
<|endoftext|>


<commit_before>//
// Copyright (C) 2005 Stefan Seefeld
// All rights reserved.
// Licensed to the public under the terms of the GNU LGPL (>= 2),
// see the file COPYING for details.
//
#ifndef Synopsis_TypeAnalysis_OverloadResolver_hh_
#define Synopsis_TypeAnalysis_OverloadResolver_hh_

#include <Synopsis/SymbolLookup/Table.hh>

namespace Synopsis
{
namespace TypeAnalysis
{

//. Resolve a function call in the context of the given scope.
SymbolLookup::Symbol const *resolve_funcall(PTree::FuncallExpr const *funcall,
					    SymbolLookup::Scope const *);

}
}

#endif

<commit_msg>Fix include directive.<commit_after>//
// Copyright (C) 2005 Stefan Seefeld
// All rights reserved.
// Licensed to the public under the terms of the GNU LGPL (>= 2),
// see the file COPYING for details.
//
#ifndef Synopsis_TypeAnalysis_OverloadResolver_hh_
#define Synopsis_TypeAnalysis_OverloadResolver_hh_

#include <Synopsis/PTree.hh>
#include <Synopsis/SymbolLookup.hh>

namespace Synopsis
{
namespace TypeAnalysis
{

//. Resolve a function call in the context of the given scope.
SymbolLookup::Symbol const *resolve_funcall(PTree::FuncallExpr const *funcall,
					    SymbolLookup::Scope const *);

}
}

#endif

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: officeipcthread.hxx,v $
 *
 *  $Revision: 1.11 $
 *
 *  last change: $Author: hr $ $Date: 2003-03-25 13:51:19 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _DESKTOP_OFFICEIPCTHREAD_HXX_
#define _DESKTOP_OFFICEIPCTHREAD_HXX_

#ifndef _COM_SUN_STAR_LANG_XSERVICEINFO_HPP_
#include <com/sun/star/lang/XServiceInfo.hpp>
#endif
#ifndef _COM_SUN_STAR_FRAME_XTERMINATELISTENER_HPP_
#include <com/sun/star/frame/XTerminateListener.hpp>
#endif

#ifndef _VOS_PIPE_HXX_
#include <vos/pipe.hxx>
#endif
#ifndef _VOS_SECURITY_HXX_
#include <vos/security.hxx>
#endif
#ifndef _VOS_THREAD_HXX_
#include <vos/thread.hxx>
#endif
#ifndef _VOS_SIGNAL_HXX_
#include <vos/signal.hxx>
#endif
#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif
#ifndef _CPPUHELPER_WEAKBASE2_HXX_
#include <cppuhelper/implbase2.hxx>
#endif
#ifndef _OSL_CONDITN_HXX_
#include <osl/conditn.hxx>
#endif

namespace desktop
{

class SalMainPipeExchangeSignalHandler : public vos::OSignalHandler
{
    virtual TSignalAction SAL_CALL signal(TSignalInfo *pInfo);
};

// A request for the current office
// that was given by command line or by IPC pipe communication.
struct ProcessDocumentsRequest
{
    ::rtl::OUString aOpenList;      // Documents that should be opened in the default way
    ::rtl::OUString aViewList;              // Documents that should be opened in viewmode
    ::rtl::OUString aPrintList;     // Documents that should be printed on default printer
    ::rtl::OUString aForceOpenList; // Documents that should be forced to open for editing (even templates)
    ::rtl::OUString aForceNewList;  // Documents that should be forced to create a new document
    ::rtl::OUString aPrinterName;   // The printer name that should be used for printing
    ::rtl::OUString aPrintToList;   // Documents that should be printed on the given printer
    ::osl::Condition cProcessed;    // condition to be set when the request has been processed
};

class DispatchWatcher;
class OfficeIPCThread : public vos::OThread
{
  private:
    static OfficeIPCThread*     pGlobalOfficeIPCThread;
    static ::osl::Mutex*        pOfficeIPCThreadMutex;

    vos::OPipe                  maPipe;
    vos::OStreamPipe            maStreamPipe;
    static vos::OSecurity       maSecurity;
    rtl::OUString               maPipeIdent;
    sal_Bool                    mbBlockRequests;
    int                         mnPendingRequests;
    DispatchWatcher*            mpDispatchWatcher;
    sal_Bool                    mbShutdownInProgress;

    static ::osl::Mutex&        GetMutex();
    static const char *sc_aTerminationSequence;
    static const int sc_nTSeqLength;
    static const char *sc_aShowSequence;
    static const int sc_nShSeqLength;
    static const char *sc_aConfirmationSequence;
    static const int sc_nCSeqLength;

    OfficeIPCThread();

  protected:
    /// Working method which should be overridden
    virtual void SAL_CALL run();

  public:
    enum Status
    {
        IPC_STATUS_OK,
        IPC_STATUS_2ND_OFFICE,
        IPC_STATUS_BOOTSTRAP_ERROR
    };

    virtual ~OfficeIPCThread();

    // controlling pipe communication during shutdown
    static OfficeIPCThread*     GetOfficeIPCThread();
    static void                 BlockAllRequests();
    static sal_Bool             AreRequestsPending();
    static void                 RequestsCompleted( int n = 1 );
    static void                 ExecuteCmdLineRequests( ProcessDocumentsRequest& );

    // return FALSE if second office
    static Status               EnableOfficeIPCThread();
    static void                 DisableOfficeIPCThread();
};

class OfficeIPCThreadController : public ::cppu::WeakImplHelper2<
                                            ::com::sun::star::lang::XServiceInfo,
                                            ::com::sun::star::frame::XTerminateListener >
{
    public:
        OfficeIPCThreadController() {}
        virtual ~OfficeIPCThreadController() {}

        // XServiceInfo
        virtual ::rtl::OUString SAL_CALL getImplementationName()
            throw ( ::com::sun::star::uno::RuntimeException );
        virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName )
            throw ( ::com::sun::star::uno::RuntimeException );
        virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames()
            throw ( ::com::sun::star::uno::RuntimeException );

        // XEventListener
        virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source )
            throw( ::com::sun::star::uno::RuntimeException );

        // XTerminateListener
        virtual void SAL_CALL queryTermination( const ::com::sun::star::lang::EventObject& aEvent )
            throw( ::com::sun::star::frame::TerminationVetoException, ::com::sun::star::uno::RuntimeException );
        virtual void SAL_CALL notifyTermination( const ::com::sun::star::lang::EventObject& aEvent )
            throw( ::com::sun::star::uno::RuntimeException );
};

}

#endif // _DESKTOP_OFFICEIPCTHREAD_HXX_
<commit_msg>INTEGRATION: CWS draw10 (1.11.22); FILE MERGED 2003/04/30 09:37:26 lo 1.11.22.1: #109140# -start for StartPresentation<commit_after>/*************************************************************************
 *
 *  $RCSfile: officeipcthread.hxx,v $
 *
 *  $Revision: 1.12 $
 *
 *  last change: $Author: vg $ $Date: 2003-05-16 14:22:30 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _DESKTOP_OFFICEIPCTHREAD_HXX_
#define _DESKTOP_OFFICEIPCTHREAD_HXX_

#ifndef _COM_SUN_STAR_LANG_XSERVICEINFO_HPP_
#include <com/sun/star/lang/XServiceInfo.hpp>
#endif
#ifndef _COM_SUN_STAR_FRAME_XTERMINATELISTENER_HPP_
#include <com/sun/star/frame/XTerminateListener.hpp>
#endif

#ifndef _VOS_PIPE_HXX_
#include <vos/pipe.hxx>
#endif
#ifndef _VOS_SECURITY_HXX_
#include <vos/security.hxx>
#endif
#ifndef _VOS_THREAD_HXX_
#include <vos/thread.hxx>
#endif
#ifndef _VOS_SIGNAL_HXX_
#include <vos/signal.hxx>
#endif
#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif
#ifndef _CPPUHELPER_WEAKBASE2_HXX_
#include <cppuhelper/implbase2.hxx>
#endif
#ifndef _OSL_CONDITN_HXX_
#include <osl/conditn.hxx>
#endif

namespace desktop
{

class SalMainPipeExchangeSignalHandler : public vos::OSignalHandler
{
    virtual TSignalAction SAL_CALL signal(TSignalInfo *pInfo);
};

// A request for the current office
// that was given by command line or by IPC pipe communication.
struct ProcessDocumentsRequest
{
    ::rtl::OUString aOpenList;      // Documents that should be opened in the default way
    ::rtl::OUString aViewList;      // Documents that should be opened in viewmode
    ::rtl::OUString aStartList;     // Documents/Presentations that should be started
    ::rtl::OUString aPrintList;     // Documents that should be printed on default printer
    ::rtl::OUString aForceOpenList; // Documents that should be forced to open for editing (even templates)
    ::rtl::OUString aForceNewList;  // Documents that should be forced to create a new document
    ::rtl::OUString aPrinterName;   // The printer name that should be used for printing
    ::rtl::OUString aPrintToList;   // Documents that should be printed on the given printer
    ::osl::Condition cProcessed;    // condition to be set when the request has been processed
};

class DispatchWatcher;
class OfficeIPCThread : public vos::OThread
{
  private:
    static OfficeIPCThread*     pGlobalOfficeIPCThread;
    static ::osl::Mutex*        pOfficeIPCThreadMutex;

    vos::OPipe                  maPipe;
    vos::OStreamPipe            maStreamPipe;
    static vos::OSecurity       maSecurity;
    rtl::OUString               maPipeIdent;
    sal_Bool                    mbBlockRequests;
    int                         mnPendingRequests;
    DispatchWatcher*            mpDispatchWatcher;
    sal_Bool                    mbShutdownInProgress;

    static ::osl::Mutex&        GetMutex();
    static const char *sc_aTerminationSequence;
    static const int sc_nTSeqLength;
    static const char *sc_aShowSequence;
    static const int sc_nShSeqLength;
    static const char *sc_aConfirmationSequence;
    static const int sc_nCSeqLength;

    OfficeIPCThread();

  protected:
    /// Working method which should be overridden
    virtual void SAL_CALL run();

  public:
    enum Status
    {
        IPC_STATUS_OK,
        IPC_STATUS_2ND_OFFICE,
        IPC_STATUS_BOOTSTRAP_ERROR
    };

    virtual ~OfficeIPCThread();

    // controlling pipe communication during shutdown
    static OfficeIPCThread*     GetOfficeIPCThread();
    static void                 BlockAllRequests();
    static sal_Bool             AreRequestsPending();
    static void                 RequestsCompleted( int n = 1 );
    static void                 ExecuteCmdLineRequests( ProcessDocumentsRequest& );

    // return FALSE if second office
    static Status               EnableOfficeIPCThread();
    static void                 DisableOfficeIPCThread();
};

class OfficeIPCThreadController : public ::cppu::WeakImplHelper2<
                                            ::com::sun::star::lang::XServiceInfo,
                                            ::com::sun::star::frame::XTerminateListener >
{
    public:
        OfficeIPCThreadController() {}
        virtual ~OfficeIPCThreadController() {}

        // XServiceInfo
        virtual ::rtl::OUString SAL_CALL getImplementationName()
            throw ( ::com::sun::star::uno::RuntimeException );
        virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName )
            throw ( ::com::sun::star::uno::RuntimeException );
        virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames()
            throw ( ::com::sun::star::uno::RuntimeException );

        // XEventListener
        virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source )
            throw( ::com::sun::star::uno::RuntimeException );

        // XTerminateListener
        virtual void SAL_CALL queryTermination( const ::com::sun::star::lang::EventObject& aEvent )
            throw( ::com::sun::star::frame::TerminationVetoException, ::com::sun::star::uno::RuntimeException );
        virtual void SAL_CALL notifyTermination( const ::com::sun::star::lang::EventObject& aEvent )
            throw( ::com::sun::star::uno::RuntimeException );
};

}

#endif // _DESKTOP_OFFICEIPCTHREAD_HXX_
<|endoftext|>


<commit_before>/**
  * Touhou Community Reliant Automatic Patcher
  * Tasogare Frontier support plugin
  *
  * ----
  *
  * Plugin breakpoints and hooks for th175.
  */

#include <thcrap.h>
#include "thcrap_tasofro.h"
#include "files_list.h"
#include "act-nut.h"

int th175_init()
{
	patchhook_register("*.pl", patch_th175_pl, nullptr);
	patchhook_register("*.nut", patch_nut, nullptr);

	return 0;
}

struct AVfile_handle
{
	void *vtable;
	HANDLE hFile;
	uint32_t unk1;
	uint32_t unk2;
};

struct AVFileIO_DefaultReader
{
	void *vtable;
	AVfile_handle handle;
};

struct AVPackageReader
{
	void* vtable;
	DWORD refcount; // from IUnknown
	uint32_t unk_08;
	uint32_t unk_0C;
	uint32_t file_offset;
	uint32_t unk_14;
	uint32_t file_size;
	uint32_t unk_1c;
	// Game does SetFilePointer(..., file_offset + file_segment_offset, ...)
	uint32_t file_segment_offset;
	uint32_t unk_24;
	uint32_t unk_28;

	AVFileIO_DefaultReader* file_reader;
};

static std::map<AVPackageReader*, TasofroFile> open_files;
std::mutex open_files_mutex;

extern "C" int BP_th175_open_file(x86_reg_t *regs, json_t *bp_info)
{
	const char *file_name = (const char*)json_object_get_immediate(bp_info, regs, "file_name");
	AVPackageReader *reader = (AVPackageReader*)json_object_get_immediate(bp_info, regs, "file_reader");

	if (!file_name || !reader) {
		return 1;
	}

	std::scoped_lock<std::mutex> lock(open_files_mutex);
	TasofroFile& fr = open_files[reader];

	fr.init(file_name);
	if (!fr.need_replace()) {
		open_files.erase(reader);
		return 1;
	}

	reader->file_size = fr.init_game_file_size(static_cast<size_t>(reader->file_size));

	return 1;
}

void do_partial_xor(uint8_t* dst, uint8_t* src, size_t size)
{
	for (size_t i = 0; i < size; i++) {
		dst[i] ^= src[i];
	}
}

// More readable version of the decrypt code.
// This one also doesn't require the input buffer size to be divisible by 4
uint32_t do_decrypt_step(uint32_t key)
{
	int64_t a = key * 0x5E4789C9ll;
	uint32_t b = (a >> 0x2E) + (a >> 0x3F);
	uint32_t ret = (key - b * 0xADC8) * 0xBC8F + b * 0xFFFFF2B9;
	if ((int32_t)ret <= 0) {
		ret += 0x7FFFFFFF;
	}
	return ret;
}

void th175_crypt_file(uint8_t* buffer, size_t size, size_t offset_in_file)
{
	size_t bytes_processed = 0;
	// File key, derived from the file's size and its offset in the archive file.
	uint32_t file_key = size ^ offset_in_file;

	for (size_t pos = 0; pos < size; pos += 4) {
		uint32_t xor = 0;
		uint32_t tmp_key = file_key;
		for (size_t i = 0; i < 4; i++) {
			tmp_key = do_decrypt_step(tmp_key);
			xor = (xor << 8) | (tmp_key & 0xFF);
		}

		if (pos + 4 <= size) {
			*(uint32_t*)(buffer + pos) ^= xor;
			bytes_processed += 4;
		}
		else {
			do_partial_xor(buffer + pos, (uint8_t*)&xor, size - pos);
			bytes_processed += size - pos;
		}
		file_key++;
	}

	assert(bytes_processed == size);
}

extern "C" int BP_th175_replaceReadFile(x86_reg_t *regs, json_t *bp_info)
{
	AVfile_handle *handle = (AVfile_handle*)json_object_get_immediate(bp_info, regs, "file_handle");

	std::scoped_lock<std::mutex> lock(open_files_mutex);
	auto it = std::find_if(open_files.begin(), open_files.end(), [handle](const std::pair<AVPackageReader* const, TasofroFile>& it) {
		return &it.first->file_reader->handle == handle;
	});
	if (it == open_files.end()) {
		return 1;
	}

	return it->second.replace_ReadFile(regs,
		[&it](TasofroFile *fr, BYTE *buffer, DWORD size) {
			// Make sure we use the old size, which is part of the xor
			if (fr->pre_json_size > size) {
				return;
			}
			th175_crypt_file(buffer, fr->pre_json_size, it->first->file_offset + it->first->file_segment_offset);
		},
		[&it](TasofroFile *fr, BYTE *buffer, DWORD size) {
			// Make sure we use the game reader's size, which will be used when the game decrypts its file
			if (it->first->file_size > size) {
				return;
			}
			th175_crypt_file(buffer, static_cast<size_t>(it->first->file_size), it->first->file_offset + it->first->file_segment_offset);
		}
	);
}

extern "C" int BP_th175_close_file(x86_reg_t *regs, json_t *bp_info)
{
	AVPackageReader *reader = (AVPackageReader*)json_object_get_immediate(bp_info, regs, "file_reader");

	std::scoped_lock<std::mutex> lock(open_files_mutex);
	auto it = open_files.find(reader);
	if (it == open_files.end()) {
		return 1;
	}

	open_files.erase(it);
	return 1;
}
<commit_msg>tasofro: pass better parameters to th175_crypt_file<commit_after>/**
  * Touhou Community Reliant Automatic Patcher
  * Tasogare Frontier support plugin
  *
  * ----
  *
  * Plugin breakpoints and hooks for th175.
  */

#include <thcrap.h>
#include "thcrap_tasofro.h"
#include "files_list.h"
#include "act-nut.h"

int th175_init()
{
	patchhook_register("*.pl", patch_th175_pl, nullptr);
	patchhook_register("*.nut", patch_nut, nullptr);

	return 0;
}

struct AVfile_handle
{
	void *vtable;
	HANDLE hFile;
	uint32_t unk1;
	uint32_t unk2;
};

struct AVFileIO_DefaultReader
{
	void *vtable;
	AVfile_handle handle;
};

struct AVPackageReader
{
	void* vtable;
	DWORD refcount; // from IUnknown
	uint32_t unk_08;
	uint32_t unk_0C;
	uint32_t file_offset;
	uint32_t unk_14;
	uint32_t file_size;
	uint32_t unk_1c;
	// Game does SetFilePointer(..., file_offset + file_segment_offset, ...)
	uint32_t file_segment_offset;
	uint32_t unk_24;
	uint32_t unk_28;

	AVFileIO_DefaultReader* file_reader;
};

static std::map<AVPackageReader*, TasofroFile> open_files;
std::mutex open_files_mutex;

extern "C" int BP_th175_open_file(x86_reg_t *regs, json_t *bp_info)
{
	const char *file_name = (const char*)json_object_get_immediate(bp_info, regs, "file_name");
	AVPackageReader *reader = (AVPackageReader*)json_object_get_immediate(bp_info, regs, "file_reader");

	if (!file_name || !reader) {
		return 1;
	}

	std::scoped_lock<std::mutex> lock(open_files_mutex);
	TasofroFile& fr = open_files[reader];

	fr.init(file_name);
	if (!fr.need_replace()) {
		open_files.erase(reader);
		return 1;
	}

	reader->file_size = fr.init_game_file_size(static_cast<size_t>(reader->file_size));

	return 1;
}

void do_partial_xor(uint8_t* dst, uint8_t* src, size_t size)
{
	for (size_t i = 0; i < size; i++) {
		dst[i] ^= src[i];
	}
}

// More readable version of the decrypt code.
// This one also doesn't require the input buffer size to be divisible by 4
uint32_t do_decrypt_step(uint32_t key)
{
	int64_t a = key * 0x5E4789C9ll;
	uint32_t b = (a >> 0x2E) + (a >> 0x3F);
	uint32_t ret = (key - b * 0xADC8) * 0xBC8F + b * 0xFFFFF2B9;
	if ((int32_t)ret <= 0) {
		ret += 0x7FFFFFFF;
	}
	return ret;
}

void th175_crypt_file(uint8_t* buffer, size_t size, size_t offset_in_file)
{
	size_t bytes_processed = 0;
	// File key, derived from the file's size and its offset in the archive file.
	uint32_t file_key = size ^ offset_in_file;

	for (size_t pos = 0; pos < size; pos += 4) {
		uint32_t xor = 0;
		uint32_t tmp_key = file_key;
		for (size_t i = 0; i < 4; i++) {
			tmp_key = do_decrypt_step(tmp_key);
			xor = (xor << 8) | (tmp_key & 0xFF);
		}

		if (pos + 4 <= size) {
			*(uint32_t*)(buffer + pos) ^= xor;
			bytes_processed += 4;
		}
		else {
			do_partial_xor(buffer + pos, (uint8_t*)&xor, size - pos);
			bytes_processed += size - pos;
		}
		file_key++;
	}

	assert(bytes_processed == size);
}

extern "C" int BP_th175_replaceReadFile(x86_reg_t *regs, json_t *bp_info)
{
	AVfile_handle *handle = (AVfile_handle*)json_object_get_immediate(bp_info, regs, "file_handle");

	std::scoped_lock<std::mutex> lock(open_files_mutex);
	auto it = std::find_if(open_files.begin(), open_files.end(), [handle](const std::pair<AVPackageReader* const, TasofroFile>& it) {
		return &it.first->file_reader->handle == handle;
	});
	if (it == open_files.end()) {
		return 1;
	}

	return it->second.replace_ReadFile(regs,
		[&it](TasofroFile *fr, BYTE *buffer, DWORD size) {
			// Make sure we use the old size, which is part of the xor
			if (fr->pre_json_size > size) {
				return;
			}
			th175_crypt_file(buffer, fr->pre_json_size, it->second.offset);
		},
		[&it](TasofroFile *fr, BYTE *buffer, DWORD size) {
			// Make sure we use the game reader's size, which will be used when the game decrypts its file
			if (it->first->file_size > size) {
				return;
			}
			th175_crypt_file(buffer, static_cast<size_t>(it->first->file_size), it->first->file_offset);
		}
	);
}

extern "C" int BP_th175_close_file(x86_reg_t *regs, json_t *bp_info)
{
	AVPackageReader *reader = (AVPackageReader*)json_object_get_immediate(bp_info, regs, "file_reader");

	std::scoped_lock<std::mutex> lock(open_files_mutex);
	auto it = open_files.find(reader);
	if (it == open_files.end()) {
		return 1;
	}

	open_files.erase(it);
	return 1;
}
<|endoftext|>


<commit_before>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2010, 2011, 2012, 2013, 2014, 2015
Raffaello D. Di Napoli

This file is part of Abaclade.

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

Abaclade is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#include <abaclade.hxx>

////////////////////////////////////////////////////////////////////////////////////////////////////

namespace abc {

void to_str_backend<text::char_ptr_to_str_adapter>::write(
   text::char_ptr_to_str_adapter const & cs, io::text::writer * ptwOut
) {
   void const * p;
   std::size_t cb;
   text::encoding enc;
   if (cs.m_psz) {
      p = cs.m_psz;
      std::size_t cch = text::size_in_chars(cs.m_psz);
      enc = text::guess_encoding(cs.m_psz, cs.m_psz + cch);
      cb = sizeof(char) * cch;
   } else {
      static char_t const sc_szNull[] = ABC_SL("<nullptr>");
      p = sc_szNull;
      enc = text::encoding::host;
      cb = sizeof(char_t) * ABC_SL_SIZE(sc_szNull);
   }
   text::detail::str_to_str_backend::write(p, cb, enc, ptwOut);
}

} //namespace abc
<commit_msg>Avoid explicitly naming types<commit_after>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2010, 2011, 2012, 2013, 2014, 2015
Raffaello D. Di Napoli

This file is part of Abaclade.

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

Abaclade is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#include <abaclade.hxx>

////////////////////////////////////////////////////////////////////////////////////////////////////

namespace abc {

void to_str_backend<text::char_ptr_to_str_adapter>::write(
   text::char_ptr_to_str_adapter const & cs, io::text::writer * ptwOut
) {
   void const * p;
   std::size_t cb;
   text::encoding enc;
   if (cs.m_psz) {
      p = cs.m_psz;
      std::size_t cch = text::size_in_chars(cs.m_psz);
      enc = text::guess_encoding(cs.m_psz, cs.m_psz + cch);
      cb = sizeof cs.m_psz[0] * cch;
   } else {
      static char_t const sc_szNull[] = ABC_SL("<nullptr>");
      p = sc_szNull;
      enc = text::encoding::host;
      cb = sizeof sc_szNull - sizeof sc_szNull[0] /*NUL*/;
   }
   text::detail::str_to_str_backend::write(p, cb, enc, ptwOut);
}

} //namespace abc
<|endoftext|>