<commit_before>// ***************************************************************************
// bamtools_pileup_engine.cpp (c) 2010 Derek Barnett, Erik Garrison
// Marth Lab, Department of Biology, Boston College
// ---------------------------------------------------------------------------
// Last modified: 9 March 2012 (DB)
// ---------------------------------------------------------------------------
// Provides pileup at position functionality for various tools.
// ***************************************************************************

#include "utils/bamtools_pileup_engine.h"
using namespace BamTools;

#include <cstddef>
#include <iostream>

// ---------------------------------------------
// PileupEnginePrivate implementation

struct PileupEngine::PileupEnginePrivate
{

    // data members
    int CurrentId;
    int CurrentPosition;
    std::vector<BamAlignment> CurrentAlignments;
    PileupPosition CurrentPileupData;

    bool IsFirstAlignment;
    std::vector<PileupVisitor*> Visitors;

    // ctor & dtor
    PileupEnginePrivate()
        : CurrentId(-1)
        , CurrentPosition(-1)
        , IsFirstAlignment(true)
    {}

    // 'public' methods
    bool AddAlignment(const BamAlignment& al);
    void Flush();

    // internal methods
private:
    void ApplyVisitors();
    void ClearOldData();
    void CreatePileupData();
    void ParseAlignmentCigar(const BamAlignment& al);
};

bool PileupEngine::PileupEnginePrivate::AddAlignment(const BamAlignment& al)
{

    // if first time
    if (IsFirstAlignment) {

        // set initial markers
        CurrentId = al.RefID;
        CurrentPosition = al.Position;

        // store first entry
        CurrentAlignments.clear();
        CurrentAlignments.push_back(al);

        // set flag & return
        IsFirstAlignment = false;
        return true;
    }

    // if same reference
    if (al.RefID == CurrentId) {

        // if same position, store and move on
        if (al.Position == CurrentPosition) CurrentAlignments.push_back(al);

        // if less than CurrentPosition - sorting error => ABORT
        else if (al.Position < CurrentPosition) {
            std::cerr << "Pileup::Run() : Data not sorted correctly!" << std::endl;
            return false;
        }

        // else print pileup data until 'catching up' to CurrentPosition
        else {
            while (al.Position > CurrentPosition) {
                ApplyVisitors();
                ++CurrentPosition;
            }
            CurrentAlignments.push_back(al);
        }
    }

    // if reference ID less than CurrentId - sorting error => ABORT
    else if (al.RefID < CurrentId) {
        std::cerr << "Pileup::Run() : Data not sorted correctly!" << std::endl;
        return false;
    }

    // else moved forward onto next reference
    else {

        // print any remaining pileup data from previous reference
        while (!CurrentAlignments.empty()) {
            ApplyVisitors();
            ++CurrentPosition;
        }

        // store first entry on this new reference, update markers
        CurrentAlignments.clear();
        CurrentAlignments.push_back(al);
        CurrentId = al.RefID;
        CurrentPosition = al.Position;
    }

    return true;
}

void PileupEngine::PileupEnginePrivate::ApplyVisitors()
{

    // parse CIGAR data in BamAlignments to build up current pileup data
    CreatePileupData();

    // apply all visitors to current alignment set
    std::vector<PileupVisitor*>::const_iterator visitorIter = Visitors.begin();
    std::vector<PileupVisitor*>::const_iterator visitorEnd = Visitors.end();
    for (; visitorIter != visitorEnd; ++visitorIter)
        (*visitorIter)->Visit(CurrentPileupData);
}

void PileupEngine::PileupEnginePrivate::ClearOldData()
{

    // remove any alignments that end before our CurrentPosition
    // N.B. - BAM positions are 0-based, half-open. GetEndPosition() returns a 1-based position,
    //        while our CurrentPosition is 0-based. For example, an alignment with 'endPosition' of
    //        100 does not overlap a 'CurrentPosition' of 100, and should be discarded.

    std::size_t i = 0;
    std::size_t j = 0;
    const std::size_t numAlignments = CurrentAlignments.size();
    while (i < numAlignments) {

        // skip over alignment if its (1-based) endPosition is <= to (0-based) CurrentPosition
        // i.e. this entry will not be saved upon vector resize
        const int endPosition = CurrentAlignments[i].GetEndPosition();
        if (endPosition <= CurrentPosition) {
            ++i;
            continue;
        }

        // otherwise alignment ends after CurrentPosition
        // move it towards vector beginning, at index j
        if (i != j) CurrentAlignments[j] = CurrentAlignments[i];

        // increment our indices
        ++i;
        ++j;
    }

    // 'squeeze' vector to size j, discarding all remaining alignments in the container
    CurrentAlignments.resize(j);
}

void PileupEngine::PileupEnginePrivate::CreatePileupData()
{

    // remove any non-overlapping alignments
    ClearOldData();

    // set pileup refId, position to current markers
    CurrentPileupData.RefId = CurrentId;
    CurrentPileupData.Position = CurrentPosition;
    CurrentPileupData.PileupAlignments.clear();

    // parse CIGAR data in remaining alignments
    std::vector<BamAlignment>::const_iterator alIter = CurrentAlignments.begin();
    std::vector<BamAlignment>::const_iterator alEnd = CurrentAlignments.end();
    for (; alIter != alEnd; ++alIter)
        ParseAlignmentCigar((*alIter));
}

void PileupEngine::PileupEnginePrivate::Flush()
{
    while (!CurrentAlignments.empty()) {
        ApplyVisitors();
        ++CurrentPosition;
    }
}

void PileupEngine::PileupEnginePrivate::ParseAlignmentCigar(const BamAlignment& al)
{

    // skip if unmapped
    if (!al.IsMapped()) return;

    // intialize local variables
    int genomePosition = al.Position;
    int positionInAlignment = 0;
    bool isNewReadSegment = true;
    bool saveAlignment = true;
    PileupAlignment pileupAlignment(al);

    // iterate over CIGAR operations
    const int numCigarOps = (const int)al.CigarData.size();
    for (int i = 0; i < numCigarOps; ++i) {
        const CigarOp& op = al.CigarData.at(i);

        // if op is MATCH
        if (op.Type == 'M') {

            // if match op overlaps current position
            if (genomePosition + (int)op.Length > CurrentPosition) {

                // set pileup data
                pileupAlignment.IsCurrentDeletion = false;
                pileupAlignment.IsNextDeletion = false;
                pileupAlignment.IsNextInsertion = false;
                pileupAlignment.PositionInAlignment =
                    positionInAlignment + (CurrentPosition - genomePosition);

                // check for beginning of read segment
                if (genomePosition == CurrentPosition && isNewReadSegment)
                    pileupAlignment.IsSegmentBegin = true;

                // if we're at the end of a match operation
                if (genomePosition + (int)op.Length - 1 == CurrentPosition) {

                    // if not last operation
                    if (i < numCigarOps - 1) {

                        // check next CIGAR op
                        const CigarOp& nextOp = al.CigarData.at(i + 1);

                        // if next CIGAR op is DELETION
                        if (nextOp.Type == 'D') {
                            pileupAlignment.IsNextDeletion = true;
                            pileupAlignment.DeletionLength = nextOp.Length;
                        }

                        // if next CIGAR op is INSERTION
                        else if (nextOp.Type == 'I') {
                            pileupAlignment.IsNextInsertion = true;
                            pileupAlignment.InsertionLength = nextOp.Length;
                        }

                        // if next CIGAR op is either DELETION or INSERTION
                        if (nextOp.Type == 'D' || nextOp.Type == 'I') {

                            // if there is a CIGAR op after the DEL/INS
                            if (i < numCigarOps - 2) {
                                const CigarOp& nextNextOp = al.CigarData.at(i + 2);

                                // if next CIGAR op is clipping or ref_skip
                                if (nextNextOp.Type == 'S' || nextNextOp.Type == 'N' ||
                                    nextNextOp.Type == 'H')
                                    pileupAlignment.IsSegmentEnd = true;
                            } else {
                                pileupAlignment.IsSegmentEnd = true;

                                // if next CIGAR op is clipping or ref_skip
                                if (nextOp.Type == 'S' || nextOp.Type == 'N' || nextOp.Type == 'H')
                                    pileupAlignment.IsSegmentEnd = true;
                            }
                        }

                        // otherwise
                        else {

                            // if next CIGAR op is clipping or ref_skip
                            if (nextOp.Type == 'S' || nextOp.Type == 'N' || nextOp.Type == 'H')
                                pileupAlignment.IsSegmentEnd = true;
                        }
                    }

                    // else this is last operation
                    else
                        pileupAlignment.IsSegmentEnd = true;
                }
            }

            // increment markers
            genomePosition += op.Length;
            positionInAlignment += op.Length;
        }

        // if op is DELETION
        else if (op.Type == 'D') {

            // if deletion op overlaps current position
            if (genomePosition + (int)op.Length > CurrentPosition) {

                // set pileup data
                pileupAlignment.IsCurrentDeletion = true;
                pileupAlignment.IsNextDeletion = false;
                pileupAlignment.IsNextInsertion = true;
                pileupAlignment.PositionInAlignment =
                    positionInAlignment + (CurrentPosition - genomePosition);
            }

            // increment marker
            genomePosition += op.Length;
        }

        // if op is REF_SKIP
        else if (op.Type == 'N') {
            genomePosition += op.Length;
        }

        // if op is INSERTION or SOFT_CLIP
        else if (op.Type == 'I' || op.Type == 'S') {
            positionInAlignment += op.Length;
        }

        // checl for beginning of new read segment
        if (op.Type == 'N' || op.Type == 'S' || op.Type == 'H')
            isNewReadSegment = true;
        else
            isNewReadSegment = false;

        // if we've moved beyond current position
        if (genomePosition > CurrentPosition) {
            if (op.Type == 'N') saveAlignment = false;  // ignore alignment if REF_SKIP
            break;
        }
    }

    // save pileup position if flag is true
    if (saveAlignment) CurrentPileupData.PileupAlignments.push_back(pileupAlignment);
}

// ---------------------------------------------
// PileupEngine implementation

PileupEngine::PileupEngine()
    : d(new PileupEnginePrivate)
{}

PileupEngine::~PileupEngine()
{
    delete d;
    d = 0;
}

bool PileupEngine::AddAlignment(const BamAlignment& al)
{
    return d->AddAlignment(al);
}
void PileupEngine::AddVisitor(PileupVisitor* visitor)
{
    d->Visitors.push_back(visitor);
}
void PileupEngine::Flush()
{
    d->Flush();
}
<commit_msg>Fix `-Wignored-qualifiers`<commit_after>// ***************************************************************************
// bamtools_pileup_engine.cpp (c) 2010 Derek Barnett, Erik Garrison
// Marth Lab, Department of Biology, Boston College
// ---------------------------------------------------------------------------
// Last modified: 9 March 2012 (DB)
// ---------------------------------------------------------------------------
// Provides pileup at position functionality for various tools.
// ***************************************************************************

#include "utils/bamtools_pileup_engine.h"
using namespace BamTools;

#include <cstddef>
#include <iostream>

// ---------------------------------------------
// PileupEnginePrivate implementation

struct PileupEngine::PileupEnginePrivate
{

    // data members
    int CurrentId;
    int CurrentPosition;
    std::vector<BamAlignment> CurrentAlignments;
    PileupPosition CurrentPileupData;

    bool IsFirstAlignment;
    std::vector<PileupVisitor*> Visitors;

    // ctor & dtor
    PileupEnginePrivate()
        : CurrentId(-1)
        , CurrentPosition(-1)
        , IsFirstAlignment(true)
    {}

    // 'public' methods
    bool AddAlignment(const BamAlignment& al);
    void Flush();

    // internal methods
private:
    void ApplyVisitors();
    void ClearOldData();
    void CreatePileupData();
    void ParseAlignmentCigar(const BamAlignment& al);
};

bool PileupEngine::PileupEnginePrivate::AddAlignment(const BamAlignment& al)
{

    // if first time
    if (IsFirstAlignment) {

        // set initial markers
        CurrentId = al.RefID;
        CurrentPosition = al.Position;

        // store first entry
        CurrentAlignments.clear();
        CurrentAlignments.push_back(al);

        // set flag & return
        IsFirstAlignment = false;
        return true;
    }

    // if same reference
    if (al.RefID == CurrentId) {

        // if same position, store and move on
        if (al.Position == CurrentPosition) CurrentAlignments.push_back(al);

        // if less than CurrentPosition - sorting error => ABORT
        else if (al.Position < CurrentPosition) {
            std::cerr << "Pileup::Run() : Data not sorted correctly!" << std::endl;
            return false;
        }

        // else print pileup data until 'catching up' to CurrentPosition
        else {
            while (al.Position > CurrentPosition) {
                ApplyVisitors();
                ++CurrentPosition;
            }
            CurrentAlignments.push_back(al);
        }
    }

    // if reference ID less than CurrentId - sorting error => ABORT
    else if (al.RefID < CurrentId) {
        std::cerr << "Pileup::Run() : Data not sorted correctly!" << std::endl;
        return false;
    }

    // else moved forward onto next reference
    else {

        // print any remaining pileup data from previous reference
        while (!CurrentAlignments.empty()) {
            ApplyVisitors();
            ++CurrentPosition;
        }

        // store first entry on this new reference, update markers
        CurrentAlignments.clear();
        CurrentAlignments.push_back(al);
        CurrentId = al.RefID;
        CurrentPosition = al.Position;
    }

    return true;
}

void PileupEngine::PileupEnginePrivate::ApplyVisitors()
{

    // parse CIGAR data in BamAlignments to build up current pileup data
    CreatePileupData();

    // apply all visitors to current alignment set
    std::vector<PileupVisitor*>::const_iterator visitorIter = Visitors.begin();
    std::vector<PileupVisitor*>::const_iterator visitorEnd = Visitors.end();
    for (; visitorIter != visitorEnd; ++visitorIter)
        (*visitorIter)->Visit(CurrentPileupData);
}

void PileupEngine::PileupEnginePrivate::ClearOldData()
{

    // remove any alignments that end before our CurrentPosition
    // N.B. - BAM positions are 0-based, half-open. GetEndPosition() returns a 1-based position,
    //        while our CurrentPosition is 0-based. For example, an alignment with 'endPosition' of
    //        100 does not overlap a 'CurrentPosition' of 100, and should be discarded.

    std::size_t i = 0;
    std::size_t j = 0;
    const std::size_t numAlignments = CurrentAlignments.size();
    while (i < numAlignments) {

        // skip over alignment if its (1-based) endPosition is <= to (0-based) CurrentPosition
        // i.e. this entry will not be saved upon vector resize
        const int endPosition = CurrentAlignments[i].GetEndPosition();
        if (endPosition <= CurrentPosition) {
            ++i;
            continue;
        }

        // otherwise alignment ends after CurrentPosition
        // move it towards vector beginning, at index j
        if (i != j) CurrentAlignments[j] = CurrentAlignments[i];

        // increment our indices
        ++i;
        ++j;
    }

    // 'squeeze' vector to size j, discarding all remaining alignments in the container
    CurrentAlignments.resize(j);
}

void PileupEngine::PileupEnginePrivate::CreatePileupData()
{

    // remove any non-overlapping alignments
    ClearOldData();

    // set pileup refId, position to current markers
    CurrentPileupData.RefId = CurrentId;
    CurrentPileupData.Position = CurrentPosition;
    CurrentPileupData.PileupAlignments.clear();

    // parse CIGAR data in remaining alignments
    std::vector<BamAlignment>::const_iterator alIter = CurrentAlignments.begin();
    std::vector<BamAlignment>::const_iterator alEnd = CurrentAlignments.end();
    for (; alIter != alEnd; ++alIter)
        ParseAlignmentCigar((*alIter));
}

void PileupEngine::PileupEnginePrivate::Flush()
{
    while (!CurrentAlignments.empty()) {
        ApplyVisitors();
        ++CurrentPosition;
    }
}

void PileupEngine::PileupEnginePrivate::ParseAlignmentCigar(const BamAlignment& al)
{

    // skip if unmapped
    if (!al.IsMapped()) return;

    // intialize local variables
    int genomePosition = al.Position;
    int positionInAlignment = 0;
    bool isNewReadSegment = true;
    bool saveAlignment = true;
    PileupAlignment pileupAlignment(al);

    // iterate over CIGAR operations
    const int numCigarOps = al.CigarData.size();
    for (int i = 0; i < numCigarOps; ++i) {
        const CigarOp& op = al.CigarData.at(i);

        // if op is MATCH
        if (op.Type == 'M') {

            // if match op overlaps current position
            if (genomePosition + (int)op.Length > CurrentPosition) {

                // set pileup data
                pileupAlignment.IsCurrentDeletion = false;
                pileupAlignment.IsNextDeletion = false;
                pileupAlignment.IsNextInsertion = false;
                pileupAlignment.PositionInAlignment =
                    positionInAlignment + (CurrentPosition - genomePosition);

                // check for beginning of read segment
                if (genomePosition == CurrentPosition && isNewReadSegment)
                    pileupAlignment.IsSegmentBegin = true;

                // if we're at the end of a match operation
                if (genomePosition + (int)op.Length - 1 == CurrentPosition) {

                    // if not last operation
                    if (i < numCigarOps - 1) {

                        // check next CIGAR op
                        const CigarOp& nextOp = al.CigarData.at(i + 1);

                        // if next CIGAR op is DELETION
                        if (nextOp.Type == 'D') {
                            pileupAlignment.IsNextDeletion = true;
                            pileupAlignment.DeletionLength = nextOp.Length;
                        }

                        // if next CIGAR op is INSERTION
                        else if (nextOp.Type == 'I') {
                            pileupAlignment.IsNextInsertion = true;
                            pileupAlignment.InsertionLength = nextOp.Length;
                        }

                        // if next CIGAR op is either DELETION or INSERTION
                        if (nextOp.Type == 'D' || nextOp.Type == 'I') {

                            // if there is a CIGAR op after the DEL/INS
                            if (i < numCigarOps - 2) {
                                const CigarOp& nextNextOp = al.CigarData.at(i + 2);

                                // if next CIGAR op is clipping or ref_skip
                                if (nextNextOp.Type == 'S' || nextNextOp.Type == 'N' ||
                                    nextNextOp.Type == 'H')
                                    pileupAlignment.IsSegmentEnd = true;
                            } else {
                                pileupAlignment.IsSegmentEnd = true;

                                // if next CIGAR op is clipping or ref_skip
                                if (nextOp.Type == 'S' || nextOp.Type == 'N' || nextOp.Type == 'H')
                                    pileupAlignment.IsSegmentEnd = true;
                            }
                        }

                        // otherwise
                        else {

                            // if next CIGAR op is clipping or ref_skip
                            if (nextOp.Type == 'S' || nextOp.Type == 'N' || nextOp.Type == 'H')
                                pileupAlignment.IsSegmentEnd = true;
                        }
                    }

                    // else this is last operation
                    else
                        pileupAlignment.IsSegmentEnd = true;
                }
            }

            // increment markers
            genomePosition += op.Length;
            positionInAlignment += op.Length;
        }

        // if op is DELETION
        else if (op.Type == 'D') {

            // if deletion op overlaps current position
            if (genomePosition + (int)op.Length > CurrentPosition) {

                // set pileup data
                pileupAlignment.IsCurrentDeletion = true;
                pileupAlignment.IsNextDeletion = false;
                pileupAlignment.IsNextInsertion = true;
                pileupAlignment.PositionInAlignment =
                    positionInAlignment + (CurrentPosition - genomePosition);
            }

            // increment marker
            genomePosition += op.Length;
        }

        // if op is REF_SKIP
        else if (op.Type == 'N') {
            genomePosition += op.Length;
        }

        // if op is INSERTION or SOFT_CLIP
        else if (op.Type == 'I' || op.Type == 'S') {
            positionInAlignment += op.Length;
        }

        // checl for beginning of new read segment
        if (op.Type == 'N' || op.Type == 'S' || op.Type == 'H')
            isNewReadSegment = true;
        else
            isNewReadSegment = false;

        // if we've moved beyond current position
        if (genomePosition > CurrentPosition) {
            if (op.Type == 'N') saveAlignment = false;  // ignore alignment if REF_SKIP
            break;
        }
    }

    // save pileup position if flag is true
    if (saveAlignment) CurrentPileupData.PileupAlignments.push_back(pileupAlignment);
}

// ---------------------------------------------
// PileupEngine implementation

PileupEngine::PileupEngine()
    : d(new PileupEnginePrivate)
{}

PileupEngine::~PileupEngine()
{
    delete d;
    d = 0;
}

bool PileupEngine::AddAlignment(const BamAlignment& al)
{
    return d->AddAlignment(al);
}
void PileupEngine::AddVisitor(PileupVisitor* visitor)
{
    d->Visitors.push_back(visitor);
}
void PileupEngine::Flush()
{
    d->Flush();
}
<|endoftext|>


<commit_before>// Copyright (c) 2015-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <httprpc.h>

#include <chainparams.h>
#include <crypto/hmac_sha256.h>
#include <httpserver.h>
#include <rpc/protocol.h>
#include <rpc/server.h>
#include <ui_interface.h>
#include <util/strencodings.h>
#include <util/system.h>
#include <util/translation.h>
#include <walletinitinterface.h>

#include <algorithm>
#include <iterator>
#include <map>
#include <memory>
#include <stdio.h>
#include <set>
#include <string>

#include <boost/algorithm/string.hpp> // boost::trim

/** WWW-Authenticate to present with 401 Unauthorized response */
static const char* WWW_AUTH_HEADER_DATA = "Basic realm=\"jsonrpc\"";

/** Simple one-shot callback timer to be used by the RPC mechanism to e.g.
 * re-lock the wallet.
 */
class HTTPRPCTimer : public RPCTimerBase
{
public:
    HTTPRPCTimer(struct event_base* eventBase, std::function<void()>& func, int64_t millis) :
        ev(eventBase, false, func)
    {
        struct timeval tv;
        tv.tv_sec = millis/1000;
        tv.tv_usec = (millis%1000)*1000;
        ev.trigger(&tv);
    }
private:
    HTTPEvent ev;
};

class HTTPRPCTimerInterface : public RPCTimerInterface
{
public:
    explicit HTTPRPCTimerInterface(struct event_base* _base) : base(_base)
    {
    }
    const char* Name() override
    {
        return "HTTP";
    }
    RPCTimerBase* NewTimer(std::function<void()>& func, int64_t millis) override
    {
        return new HTTPRPCTimer(base, func, millis);
    }
private:
    struct event_base* base;
};

/* Pre-base64-encoded authentication token */
static std::string strRPCUserColonPass;
/* Stored RPC timer interface (for unregistration) */
static std::unique_ptr<HTTPRPCTimerInterface> httpRPCTimerInterface;
/* RPC Auth Whitelist */
static std::map<std::string, std::set<std::string>> g_rpc_whitelist;
static bool g_rpc_whitelist_default = false;

static void JSONErrorReply(HTTPRequest* req, const UniValue& objError, const UniValue& id)
{
    // Send error reply from json-rpc error object
    int nStatus = HTTP_INTERNAL_SERVER_ERROR;
    int code = find_value(objError, "code").get_int();

    if (code == RPC_INVALID_REQUEST)
        nStatus = HTTP_BAD_REQUEST;
    else if (code == RPC_METHOD_NOT_FOUND)
        nStatus = HTTP_NOT_FOUND;

    std::string strReply = JSONRPCReply(NullUniValue, objError, id);

    req->WriteHeader("Content-Type", "application/json");
    req->WriteReply(nStatus, strReply);
}

//This function checks username and password against -rpcauth
//entries from config file.
static bool multiUserAuthorized(std::string strUserPass)
{
    if (strUserPass.find(':') == std::string::npos) {
        return false;
    }
    std::string strUser = strUserPass.substr(0, strUserPass.find(':'));
    std::string strPass = strUserPass.substr(strUserPass.find(':') + 1);

    for (const std::string& strRPCAuth : gArgs.GetArgs("-rpcauth")) {
        //Search for multi-user login/pass "rpcauth" from config
        std::vector<std::string> vFields;
        boost::split(vFields, strRPCAuth, boost::is_any_of(":$"));
        if (vFields.size() != 3) {
            //Incorrect formatting in config file
            continue;
        }

        std::string strName = vFields[0];
        if (!TimingResistantEqual(strName, strUser)) {
            continue;
        }

        std::string strSalt = vFields[1];
        std::string strHash = vFields[2];

        static const unsigned int KEY_SIZE = 32;
        unsigned char out[KEY_SIZE];

        CHMAC_SHA256(reinterpret_cast<const unsigned char*>(strSalt.data()), strSalt.size()).Write(reinterpret_cast<const unsigned char*>(strPass.data()), strPass.size()).Finalize(out);
        std::vector<unsigned char> hexvec(out, out+KEY_SIZE);
        std::string strHashFromPass = HexStr(hexvec);

        if (TimingResistantEqual(strHashFromPass, strHash)) {
            return true;
        }
    }
    return false;
}

static bool RPCAuthorized(const std::string& strAuth, std::string& strAuthUsernameOut)
{
    if (strRPCUserColonPass.empty()) // Belt-and-suspenders measure if InitRPCAuthentication was not called
        return false;
    if (strAuth.substr(0, 6) != "Basic ")
        return false;
    std::string strUserPass64 = strAuth.substr(6);
    boost::trim(strUserPass64);
    std::string strUserPass = DecodeBase64(strUserPass64);

    if (strUserPass.find(':') != std::string::npos)
        strAuthUsernameOut = strUserPass.substr(0, strUserPass.find(':'));

    //Check if authorized under single-user field
    if (TimingResistantEqual(strUserPass, strRPCUserColonPass)) {
        return true;
    }
    return multiUserAuthorized(strUserPass);
}

static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
{
    // JSONRPC handles only POST
    if (req->GetRequestMethod() != HTTPRequest::POST) {
        req->WriteReply(HTTP_BAD_METHOD, "JSONRPC server handles only POST requests");
        return false;
    }
    // Check authorization
    std::pair<bool, std::string> authHeader = req->GetHeader("authorization");
    if (!authHeader.first) {
        req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA);
        req->WriteReply(HTTP_UNAUTHORIZED);
        return false;
    }

    JSONRPCRequest jreq;
    jreq.peerAddr = req->GetPeer().ToString();
    if (!RPCAuthorized(authHeader.second, jreq.authUser)) {
        LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", jreq.peerAddr);

        /* Deter brute-forcing
           If this results in a DoS the user really
           shouldn't have their RPC port exposed. */
        UninterruptibleSleep(std::chrono::milliseconds{250});

        req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA);
        req->WriteReply(HTTP_UNAUTHORIZED);
        return false;
    }

    try {
        // Parse request
        UniValue valRequest;
        if (!valRequest.read(req->ReadBody()))
            throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");

        // Set the URI
        jreq.URI = req->GetURI();

        std::string strReply;
        bool user_has_whitelist = g_rpc_whitelist.count(jreq.authUser);
        if (!user_has_whitelist && g_rpc_whitelist_default) {
            LogPrintf("RPC User %s not allowed to call any methods\n", jreq.authUser);
            req->WriteReply(HTTP_FORBIDDEN);
            return false;

        // singleton request
        } else if (valRequest.isObject()) {
            jreq.parse(valRequest);
            if (user_has_whitelist && !g_rpc_whitelist[jreq.authUser].count(jreq.strMethod)) {
                LogPrintf("RPC User %s not allowed to call method %s\n", jreq.authUser, jreq.strMethod);
                req->WriteReply(HTTP_FORBIDDEN);
                return false;
            }
            UniValue result = tableRPC.execute(jreq);

            // Send reply
            strReply = JSONRPCReply(result, NullUniValue, jreq.id);

        // array of requests
        } else if (valRequest.isArray()) {
            if (user_has_whitelist) {
                for (unsigned int reqIdx = 0; reqIdx < valRequest.size(); reqIdx++) {
                    if (!valRequest[reqIdx].isObject()) {
                        throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object");
                    } else {
                        const UniValue& request = valRequest[reqIdx].get_obj();
                        // Parse method
                        std::string strMethod = find_value(request, "method").get_str();
                        if (!g_rpc_whitelist[jreq.authUser].count(strMethod)) {
                            LogPrintf("RPC User %s not allowed to call method %s\n", jreq.authUser, strMethod);
                            req->WriteReply(HTTP_FORBIDDEN);
                            return false;
                        }
                    }
                }
            }
            strReply = JSONRPCExecBatch(jreq, valRequest.get_array());
        }
        else
            throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");

        req->WriteHeader("Content-Type", "application/json");
        req->WriteReply(HTTP_OK, strReply);
    } catch (const UniValue& objError) {
        JSONErrorReply(req, objError, jreq.id);
        return false;
    } catch (const std::exception& e) {
        JSONErrorReply(req, JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
        return false;
    }
    return true;
}

static bool InitRPCAuthentication()
{
    if (gArgs.GetArg("-rpcpassword", "") == "")
    {
        LogPrintf("No rpcpassword set - using random cookie authentication.\n");
        if (!GenerateAuthCookie(&strRPCUserColonPass)) {
            uiInterface.ThreadSafeMessageBox(
                _("Error: A fatal internal error occurred, see debug.log for details"), // Same message as AbortNode
                "", CClientUIInterface::MSG_ERROR);
            return false;
        }
    } else {
        LogPrintf("Config options rpcuser and rpcpassword will soon be deprecated. Locally-run instances may remove rpcuser to use cookie-based auth, or may be replaced with rpcauth. Please see share/rpcauth for rpcauth auth generation.\n");
        strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + gArgs.GetArg("-rpcpassword", "");
    }
    if (gArgs.GetArg("-rpcauth","") != "")
    {
        LogPrintf("Using rpcauth authentication.\n");
    }

    g_rpc_whitelist_default = gArgs.GetBoolArg("-rpcwhitelistdefault", gArgs.IsArgSet("-rpcwhitelist"));
    for (const std::string& strRPCWhitelist : gArgs.GetArgs("-rpcwhitelist")) {
        auto pos = strRPCWhitelist.find(':');
        std::string strUser = strRPCWhitelist.substr(0, pos);
        bool intersect = g_rpc_whitelist.count(strUser);
        std::set<std::string>& whitelist = g_rpc_whitelist[strUser];
        if (pos != std::string::npos) {
            std::string strWhitelist = strRPCWhitelist.substr(pos + 1);
            std::set<std::string> new_whitelist;
            boost::split(new_whitelist, strWhitelist, boost::is_any_of(", "));
            if (intersect) {
                std::set<std::string> tmp_whitelist;
                std::set_intersection(new_whitelist.begin(), new_whitelist.end(),
                       whitelist.begin(), whitelist.end(), std::inserter(tmp_whitelist, tmp_whitelist.end()));
                new_whitelist = std::move(tmp_whitelist);
            }
            whitelist = std::move(new_whitelist);
        }
    }

    return true;
}

bool StartHTTPRPC()
{
    LogPrint(BCLog::RPC, "Starting HTTP RPC server\n");
    if (!InitRPCAuthentication())
        return false;

    RegisterHTTPHandler("/", true, HTTPReq_JSONRPC);
    if (g_wallet_init_interface.HasWalletSupport()) {
        RegisterHTTPHandler("/wallet/", false, HTTPReq_JSONRPC);
    }
    struct event_base* eventBase = EventBase();
    assert(eventBase);
    httpRPCTimerInterface = MakeUnique<HTTPRPCTimerInterface>(eventBase);
    RPCSetTimerInterface(httpRPCTimerInterface.get());
    return true;
}

void InterruptHTTPRPC()
{
    LogPrint(BCLog::RPC, "Interrupting HTTP RPC server\n");
}

void StopHTTPRPC()
{
    LogPrint(BCLog::RPC, "Stopping HTTP RPC server\n");
    UnregisterHTTPHandler("/", true);
    if (g_wallet_init_interface.HasWalletSupport()) {
        UnregisterHTTPHandler("/wallet/", false);
    }
    if (httpRPCTimerInterface) {
        RPCUnsetTimerInterface(httpRPCTimerInterface.get());
        httpRPCTimerInterface.reset();
    }
}
<commit_msg>log: Remove "No rpcpassword set" from logs<commit_after>// Copyright (c) 2015-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <httprpc.h>

#include <chainparams.h>
#include <crypto/hmac_sha256.h>
#include <httpserver.h>
#include <rpc/protocol.h>
#include <rpc/server.h>
#include <ui_interface.h>
#include <util/strencodings.h>
#include <util/system.h>
#include <util/translation.h>
#include <walletinitinterface.h>

#include <algorithm>
#include <iterator>
#include <map>
#include <memory>
#include <stdio.h>
#include <set>
#include <string>

#include <boost/algorithm/string.hpp> // boost::trim

/** WWW-Authenticate to present with 401 Unauthorized response */
static const char* WWW_AUTH_HEADER_DATA = "Basic realm=\"jsonrpc\"";

/** Simple one-shot callback timer to be used by the RPC mechanism to e.g.
 * re-lock the wallet.
 */
class HTTPRPCTimer : public RPCTimerBase
{
public:
    HTTPRPCTimer(struct event_base* eventBase, std::function<void()>& func, int64_t millis) :
        ev(eventBase, false, func)
    {
        struct timeval tv;
        tv.tv_sec = millis/1000;
        tv.tv_usec = (millis%1000)*1000;
        ev.trigger(&tv);
    }
private:
    HTTPEvent ev;
};

class HTTPRPCTimerInterface : public RPCTimerInterface
{
public:
    explicit HTTPRPCTimerInterface(struct event_base* _base) : base(_base)
    {
    }
    const char* Name() override
    {
        return "HTTP";
    }
    RPCTimerBase* NewTimer(std::function<void()>& func, int64_t millis) override
    {
        return new HTTPRPCTimer(base, func, millis);
    }
private:
    struct event_base* base;
};

/* Pre-base64-encoded authentication token */
static std::string strRPCUserColonPass;
/* Stored RPC timer interface (for unregistration) */
static std::unique_ptr<HTTPRPCTimerInterface> httpRPCTimerInterface;
/* RPC Auth Whitelist */
static std::map<std::string, std::set<std::string>> g_rpc_whitelist;
static bool g_rpc_whitelist_default = false;

static void JSONErrorReply(HTTPRequest* req, const UniValue& objError, const UniValue& id)
{
    // Send error reply from json-rpc error object
    int nStatus = HTTP_INTERNAL_SERVER_ERROR;
    int code = find_value(objError, "code").get_int();

    if (code == RPC_INVALID_REQUEST)
        nStatus = HTTP_BAD_REQUEST;
    else if (code == RPC_METHOD_NOT_FOUND)
        nStatus = HTTP_NOT_FOUND;

    std::string strReply = JSONRPCReply(NullUniValue, objError, id);

    req->WriteHeader("Content-Type", "application/json");
    req->WriteReply(nStatus, strReply);
}

//This function checks username and password against -rpcauth
//entries from config file.
static bool multiUserAuthorized(std::string strUserPass)
{
    if (strUserPass.find(':') == std::string::npos) {
        return false;
    }
    std::string strUser = strUserPass.substr(0, strUserPass.find(':'));
    std::string strPass = strUserPass.substr(strUserPass.find(':') + 1);

    for (const std::string& strRPCAuth : gArgs.GetArgs("-rpcauth")) {
        //Search for multi-user login/pass "rpcauth" from config
        std::vector<std::string> vFields;
        boost::split(vFields, strRPCAuth, boost::is_any_of(":$"));
        if (vFields.size() != 3) {
            //Incorrect formatting in config file
            continue;
        }

        std::string strName = vFields[0];
        if (!TimingResistantEqual(strName, strUser)) {
            continue;
        }

        std::string strSalt = vFields[1];
        std::string strHash = vFields[2];

        static const unsigned int KEY_SIZE = 32;
        unsigned char out[KEY_SIZE];

        CHMAC_SHA256(reinterpret_cast<const unsigned char*>(strSalt.data()), strSalt.size()).Write(reinterpret_cast<const unsigned char*>(strPass.data()), strPass.size()).Finalize(out);
        std::vector<unsigned char> hexvec(out, out+KEY_SIZE);
        std::string strHashFromPass = HexStr(hexvec);

        if (TimingResistantEqual(strHashFromPass, strHash)) {
            return true;
        }
    }
    return false;
}

static bool RPCAuthorized(const std::string& strAuth, std::string& strAuthUsernameOut)
{
    if (strRPCUserColonPass.empty()) // Belt-and-suspenders measure if InitRPCAuthentication was not called
        return false;
    if (strAuth.substr(0, 6) != "Basic ")
        return false;
    std::string strUserPass64 = strAuth.substr(6);
    boost::trim(strUserPass64);
    std::string strUserPass = DecodeBase64(strUserPass64);

    if (strUserPass.find(':') != std::string::npos)
        strAuthUsernameOut = strUserPass.substr(0, strUserPass.find(':'));

    //Check if authorized under single-user field
    if (TimingResistantEqual(strUserPass, strRPCUserColonPass)) {
        return true;
    }
    return multiUserAuthorized(strUserPass);
}

static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
{
    // JSONRPC handles only POST
    if (req->GetRequestMethod() != HTTPRequest::POST) {
        req->WriteReply(HTTP_BAD_METHOD, "JSONRPC server handles only POST requests");
        return false;
    }
    // Check authorization
    std::pair<bool, std::string> authHeader = req->GetHeader("authorization");
    if (!authHeader.first) {
        req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA);
        req->WriteReply(HTTP_UNAUTHORIZED);
        return false;
    }

    JSONRPCRequest jreq;
    jreq.peerAddr = req->GetPeer().ToString();
    if (!RPCAuthorized(authHeader.second, jreq.authUser)) {
        LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", jreq.peerAddr);

        /* Deter brute-forcing
           If this results in a DoS the user really
           shouldn't have their RPC port exposed. */
        UninterruptibleSleep(std::chrono::milliseconds{250});

        req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA);
        req->WriteReply(HTTP_UNAUTHORIZED);
        return false;
    }

    try {
        // Parse request
        UniValue valRequest;
        if (!valRequest.read(req->ReadBody()))
            throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");

        // Set the URI
        jreq.URI = req->GetURI();

        std::string strReply;
        bool user_has_whitelist = g_rpc_whitelist.count(jreq.authUser);
        if (!user_has_whitelist && g_rpc_whitelist_default) {
            LogPrintf("RPC User %s not allowed to call any methods\n", jreq.authUser);
            req->WriteReply(HTTP_FORBIDDEN);
            return false;

        // singleton request
        } else if (valRequest.isObject()) {
            jreq.parse(valRequest);
            if (user_has_whitelist && !g_rpc_whitelist[jreq.authUser].count(jreq.strMethod)) {
                LogPrintf("RPC User %s not allowed to call method %s\n", jreq.authUser, jreq.strMethod);
                req->WriteReply(HTTP_FORBIDDEN);
                return false;
            }
            UniValue result = tableRPC.execute(jreq);

            // Send reply
            strReply = JSONRPCReply(result, NullUniValue, jreq.id);

        // array of requests
        } else if (valRequest.isArray()) {
            if (user_has_whitelist) {
                for (unsigned int reqIdx = 0; reqIdx < valRequest.size(); reqIdx++) {
                    if (!valRequest[reqIdx].isObject()) {
                        throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object");
                    } else {
                        const UniValue& request = valRequest[reqIdx].get_obj();
                        // Parse method
                        std::string strMethod = find_value(request, "method").get_str();
                        if (!g_rpc_whitelist[jreq.authUser].count(strMethod)) {
                            LogPrintf("RPC User %s not allowed to call method %s\n", jreq.authUser, strMethod);
                            req->WriteReply(HTTP_FORBIDDEN);
                            return false;
                        }
                    }
                }
            }
            strReply = JSONRPCExecBatch(jreq, valRequest.get_array());
        }
        else
            throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");

        req->WriteHeader("Content-Type", "application/json");
        req->WriteReply(HTTP_OK, strReply);
    } catch (const UniValue& objError) {
        JSONErrorReply(req, objError, jreq.id);
        return false;
    } catch (const std::exception& e) {
        JSONErrorReply(req, JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
        return false;
    }
    return true;
}

static bool InitRPCAuthentication()
{
    if (gArgs.GetArg("-rpcpassword", "") == "")
    {
        LogPrintf("Using random cookie authentication.\n");
        if (!GenerateAuthCookie(&strRPCUserColonPass)) {
            uiInterface.ThreadSafeMessageBox(
                _("Error: A fatal internal error occurred, see debug.log for details"), // Same message as AbortNode
                "", CClientUIInterface::MSG_ERROR);
            return false;
        }
    } else {
        LogPrintf("Config options rpcuser and rpcpassword will soon be deprecated. Locally-run instances may remove rpcuser to use cookie-based auth, or may be replaced with rpcauth. Please see share/rpcauth for rpcauth auth generation.\n");
        strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + gArgs.GetArg("-rpcpassword", "");
    }
    if (gArgs.GetArg("-rpcauth","") != "")
    {
        LogPrintf("Using rpcauth authentication.\n");
    }

    g_rpc_whitelist_default = gArgs.GetBoolArg("-rpcwhitelistdefault", gArgs.IsArgSet("-rpcwhitelist"));
    for (const std::string& strRPCWhitelist : gArgs.GetArgs("-rpcwhitelist")) {
        auto pos = strRPCWhitelist.find(':');
        std::string strUser = strRPCWhitelist.substr(0, pos);
        bool intersect = g_rpc_whitelist.count(strUser);
        std::set<std::string>& whitelist = g_rpc_whitelist[strUser];
        if (pos != std::string::npos) {
            std::string strWhitelist = strRPCWhitelist.substr(pos + 1);
            std::set<std::string> new_whitelist;
            boost::split(new_whitelist, strWhitelist, boost::is_any_of(", "));
            if (intersect) {
                std::set<std::string> tmp_whitelist;
                std::set_intersection(new_whitelist.begin(), new_whitelist.end(),
                       whitelist.begin(), whitelist.end(), std::inserter(tmp_whitelist, tmp_whitelist.end()));
                new_whitelist = std::move(tmp_whitelist);
            }
            whitelist = std::move(new_whitelist);
        }
    }

    return true;
}

bool StartHTTPRPC()
{
    LogPrint(BCLog::RPC, "Starting HTTP RPC server\n");
    if (!InitRPCAuthentication())
        return false;

    RegisterHTTPHandler("/", true, HTTPReq_JSONRPC);
    if (g_wallet_init_interface.HasWalletSupport()) {
        RegisterHTTPHandler("/wallet/", false, HTTPReq_JSONRPC);
    }
    struct event_base* eventBase = EventBase();
    assert(eventBase);
    httpRPCTimerInterface = MakeUnique<HTTPRPCTimerInterface>(eventBase);
    RPCSetTimerInterface(httpRPCTimerInterface.get());
    return true;
}

void InterruptHTTPRPC()
{
    LogPrint(BCLog::RPC, "Interrupting HTTP RPC server\n");
}

void StopHTTPRPC()
{
    LogPrint(BCLog::RPC, "Stopping HTTP RPC server\n");
    UnregisterHTTPHandler("/", true);
    if (g_wallet_init_interface.HasWalletSupport()) {
        UnregisterHTTPHandler("/wallet/", false);
    }
    if (httpRPCTimerInterface) {
        RPCUnsetTimerInterface(httpRPCTimerInterface.get());
        httpRPCTimerInterface.reset();
    }
}
<|endoftext|>


<commit_before>/**
 * @file hud_fox.cpp
 * @brief Purpose: Contains methods to game class' management.
 *
 * MIT License
 * Copyright (c) 2017 MindScape
 *
 * https://github.com/TecProg2017-2/mindscape/blob/master/LICENSE.md
 */
#include "../include/hud_fox.hpp"
#include "../engine/include/log.hpp"

using namespace mindscape;

/**
 * @brief Class Contructor.
 *
 * Sets Hud Fox's firsts informations (attributes' values).
 * (Hud Fox: Fox's health bar).
 *
 * @param name Hud Fox's name(name of the object).
 * @param position Hud Fox's coordinates in the game's map.
 * @param priority Hud Fox's priority in game's execution.
 * @return void.
 */
HudFox::HudFox(
    std::string name,
    std::pair<int, int> position,
    int priority)
    :engine::GameObject(
        name,
        position,
        priority,
        {
            //No engine Keyboard Event needed.
        }
    ) {
        initialize_animations();
        initialize_audio_effects();
};

/**
 * @brief Initiates Hud Fox's sound effect.
 *
 * Sets sound effect of heart.
 * @return void.
 */
void HudFox::initialize_audio_effects() {

    DEBUG("Started");

    /* Initiates sound effect */
    engine::Audio * take_this_hp = nullptr;
    take_this_hp = new engine::Audio(
        "heart", "../assets/audios/effects_songs/mindscape_heart.wav",
        engine::Audio::CHUNK);

    /* Set duration of the sound effect and add component in game */
    take_this_hp->set_duration(1);
    add_component(take_this_hp);

    DEBUG("Ended");
}

/**
 * @brief Notifies Hud Fox of Fox's state.
 *
 * Verifies Fox's state and sets stars' animation depending of the quantity of
 *  stars collected.
 *
 * @param game_object Object for observe game's situation,
 * in this case, the Fox.
 * @return void.
 */
void HudFox::notify(engine::Observable* game_object) {

    Fox* fox = nullptr;
    fox = dynamic_cast<Fox *>(game_object);

    if(fox) {
    /* If the fox exists */
        bool give_hp = false; /*< Boolean. Boolean that defines if
        hp is being given or not */
        give_hp = fox->get_animation_hud_fading();

        engine::Animation* actual = NULL;
        actual = get_actual_animation();

        if(actual == animations["three_star_fading"]) {
        /* If stars are fading */
            if(actual->is_finished) {
            /* If stars already faded */
                give_hp = false;
                fox->set_star_count(0);
                set_actual_animation(animations["zero_star"]);
            }
        }

        else {
        /* If the animation is not stars fading */
            int count = 0; /*< Integer. Number of stars */
            count = fox->get_star_count();

            if(count == 0) {
            /* If there are no stars */
                if(!(get_actual_animation() == animations["zero_star"])) {
                    set_actual_animation(animations["zero_star"]);
                }
            }

            else if(count == 1) {
            /* If there is one star */
                if(!(get_actual_animation() == animations["one_star"])){
                    set_actual_animation(animations["one_star"]);
                }
            }

            else if(count == 2) {
            /* If there are two stars */
                if(!(get_actual_animation() == animations["two_star"])) {
                    set_actual_animation(animations["two_star"]);
                }
            }

            else if(count == 3 && !give_hp) {
            /* If there are three stars and is not giving hp */
                if(!(get_actual_animation() == animations["three_star"])) {
                    set_actual_animation(animations["three_star"]);
                }
            }

            else if(count == 3 && give_hp) {
            /* If there are three stars and is giving hp */
                fox->set_animation_hud_fading(false);
                set_actual_animation(animations["three_star_fading"]);
                play_song("heart");
            }
        }
    }

    else {
        /* Do nothing */
        WARN("HudFox: Fox IS NULL");
    }

}

/**
 * @brief Initiates Hud Fox's animation.
 *
 * Initiates all Hud Fox's sprites(images).
 *
 * @return void.
 */
void HudFox::initialize_animations() {

    DEBUG("Started");

    engine::Animation* fox_zero_star = nullptr;
    fox_zero_star = create_animation(
        "../assets/images/sprites/hud/hud_fox_0.png",
        1,1,0.9, "RIGHT"
    );
    add_animation("zero_star", fox_zero_star);

    engine::Animation* fox_one_star = nullptr;
    fox_one_star = create_animation(
        "../assets/images/sprites/hud/hud_fox_1.png",
        1,1,0.9, "RIGHT"
    );
    add_animation("one_star", fox_one_star);

    engine::Animation* fox_two_star = nullptr;
    fox_two_star = create_animation(
        "../assets/images/sprites/hud/hud_fox_2.png",
        1,1,0.9, "RIGHT"
    );
    add_animation("two_star", fox_two_star);

    engine::Animation* fox_three_star = nullptr;
    fox_three_star = create_animation(
        "../assets/images/sprites/hud/hud_fox_3.png",
        1,1,0.9, "RIGHT"
    );
    add_animation("three_star", fox_three_star);

    engine::Animation* fox_three_star_fading = nullptr;
    fox_three_star_fading = create_animation(
        "../assets/images/sprites/hud/hud_fox_3_animation.png",
        1,4,1.0, "RIGHT"
    );
    fox_three_star_fading->in_loop = false;
    add_animation("three_star_fading", fox_three_star_fading);

    fox_zero_star->activate();
    set_actual_animation(fox_zero_star);

    DEBUG("Ended");
}

/**
 * @brief Creates Hud Fox's animation.
 *
 * Creates all Hud Fox's animation based on Hud Fox's sprites.
 *
 * @param image_path Path of the Hud Fox's sprite.
 * @param sprite_lines Line of the Hud Fox's sprite.
 * @warning Limitations of sprite_lines and sprite_columns are
 * 1 to the quantity of lines/columns in the image.
 * @param sprite_columns Column of the Fox's sprite needed.
 * @param duration Duration of the Hud Fox's image to show up.
 * @param direction Direction of the Hud Fox's image.
 * @return engine::Animation* The animation constructed.
 */
engine::Animation* HudFox::create_animation(
    std::string path,
    int sprite_lines,
    int sprite_columns,
    double duration,
    std::string direction) {

    DEBUG("Started");
    engine::Game& game = engine::Game::get_instance();

    engine::Animation* animation = nullptr;
    animation = new engine::Animation(
        game.get_renderer(),
        path,
        // is_active
        false,
        std::make_pair(0, 0),
        // priority
        1,
        sprite_lines,
        sprite_columns,
        duration,
        // in_loop
        true,
        direction
    );

    animation->set_values(
        std::make_pair(170, 78),
        std::make_pair(170, 78),
        std::make_pair(0, 0)
    );

    DEBUG("Ended");

    return animation;
}
<commit_msg>[DEFAULT BEHAVIOUR] Applies default behaviour in Hud_Fox.cpp<commit_after>/**
 * @file hud_fox.cpp
 * @brief Purpose: Contains methods to game class' management.
 *
 * MIT License
 * Copyright (c) 2017 MindScape
 *
 * https://github.com/TecProg2017-2/mindscape/blob/master/LICENSE.md
 */
#include "../include/hud_fox.hpp"
#include "../engine/include/log.hpp"

using namespace mindscape;

/**
 * @brief Class Contructor.
 *
 * Sets Hud Fox's firsts informations (attributes' values).
 * (Hud Fox: Fox's health bar).
 *
 * @param name Hud Fox's name(name of the object).
 * @param position Hud Fox's coordinates in the game's map.
 * @param priority Hud Fox's priority in game's execution.
 * @return void.
 */
HudFox::HudFox(
    std::string name,
    std::pair<int, int> position,
    int priority)
    :engine::GameObject(
        name,
        position,
        priority,
        {
            //No engine Keyboard Event needed.
        }
    ) {
        initialize_animations();
        initialize_audio_effects();
};

/**
 * @brief Initiates Hud Fox's sound effect.
 *
 * Sets sound effect of heart.
 * @return void.
 */
void HudFox::initialize_audio_effects() {

    DEBUG("Started");

    /* Initiates sound effect */
    engine::Audio * take_this_hp = nullptr;
    take_this_hp = new engine::Audio(
        "heart", "../assets/audios/effects_songs/mindscape_heart.wav",
        engine::Audio::CHUNK);

    /* Set duration of the sound effect and add component in game */
    take_this_hp->set_duration(1);
    add_component(take_this_hp);

    DEBUG("Ended");
}

/**
 * @brief Notifies Hud Fox of Fox's state.
 *
 * Verifies Fox's state and sets stars' animation depending of the quantity of
 *  stars collected.
 *
 * @param game_object Object for observe game's situation,
 * in this case, the Fox.
 * @return void.
 */
void HudFox::notify(engine::Observable* game_object) {

    Fox* fox = nullptr;
    fox = dynamic_cast<Fox *>(game_object);

    if(fox) {
    /* If the fox exists */
        bool give_hp = false; /*< Boolean. Boolean that defines if
        hp is being given or not */
        give_hp = fox->get_animation_hud_fading();

        engine::Animation* actual = NULL;
        actual = get_actual_animation();

        if(actual == animations["three_star_fading"]) {
        /* If stars are fading */
            if(actual->is_finished) {
            /* If stars already faded */
                give_hp = false;
                fox->set_star_count(0);
                set_actual_animation(animations["zero_star"]);
            }

            else {
                /* Do nothing */
            }
        }

        else {
        /* If the animation is not stars fading */
            int count = 0; /*< Integer. Number of stars */
            count = fox->get_star_count();

            if(count == 0) {
            /* If there are no stars */
                if(!(get_actual_animation() == animations["zero_star"])) {
                    set_actual_animation(animations["zero_star"]);
                }

                else {
                    /* Do nothing */
                }
            }

            else if(count == 1) {
            /* If there is one star */
                if(!(get_actual_animation() == animations["one_star"])){
                    set_actual_animation(animations["one_star"]);
                }

                else {
                    /* Do nothing */
                }
            }

            else if(count == 2) {
            /* If there are two stars */
                if(!(get_actual_animation() == animations["two_star"])) {
                    set_actual_animation(animations["two_star"]);
                }

                else {
                    /* Do nothing */
                }
            }

            else if(count == 3 && !give_hp) {
            /* If there are three stars and is not giving hp */
                if(!(get_actual_animation() == animations["three_star"])) {
                    set_actual_animation(animations["three_star"]);
                }
                else {
                    /* Do nothing */
                }
            }

            else if(count == 3 && give_hp) {
            /* If there are three stars and is giving hp */
                fox->set_animation_hud_fading(false);
                set_actual_animation(animations["three_star_fading"]);
                play_song("heart");
            }

            else {
                /* Do nothing */
            }
        }
    }

    else {
        /* Do nothing */
        WARN("HudFox: Fox IS NULL");
    }

}

/**
 * @brief Initiates Hud Fox's animation.
 *
 * Initiates all Hud Fox's sprites(images).
 *
 * @return void.
 */
void HudFox::initialize_animations() {

    DEBUG("Started");

    engine::Animation* fox_zero_star = nullptr;
    fox_zero_star = create_animation(
        "../assets/images/sprites/hud/hud_fox_0.png",
        1,1,0.9, "RIGHT"
    );
    add_animation("zero_star", fox_zero_star);

    engine::Animation* fox_one_star = nullptr;
    fox_one_star = create_animation(
        "../assets/images/sprites/hud/hud_fox_1.png",
        1,1,0.9, "RIGHT"
    );
    add_animation("one_star", fox_one_star);

    engine::Animation* fox_two_star = nullptr;
    fox_two_star = create_animation(
        "../assets/images/sprites/hud/hud_fox_2.png",
        1,1,0.9, "RIGHT"
    );
    add_animation("two_star", fox_two_star);

    engine::Animation* fox_three_star = nullptr;
    fox_three_star = create_animation(
        "../assets/images/sprites/hud/hud_fox_3.png",
        1,1,0.9, "RIGHT"
    );
    add_animation("three_star", fox_three_star);

    engine::Animation* fox_three_star_fading = nullptr;
    fox_three_star_fading = create_animation(
        "../assets/images/sprites/hud/hud_fox_3_animation.png",
        1,4,1.0, "RIGHT"
    );
    fox_three_star_fading->in_loop = false;
    add_animation("three_star_fading", fox_three_star_fading);

    fox_zero_star->activate();
    set_actual_animation(fox_zero_star);

    DEBUG("Ended");
}

/**
 * @brief Creates Hud Fox's animation.
 *
 * Creates all Hud Fox's animation based on Hud Fox's sprites.
 *
 * @param image_path Path of the Hud Fox's sprite.
 * @param sprite_lines Line of the Hud Fox's sprite.
 * @warning Limitations of sprite_lines and sprite_columns are
 * 1 to the quantity of lines/columns in the image.
 * @param sprite_columns Column of the Fox's sprite needed.
 * @param duration Duration of the Hud Fox's image to show up.
 * @param direction Direction of the Hud Fox's image.
 * @return engine::Animation* The animation constructed.
 */
engine::Animation* HudFox::create_animation(
    std::string path,
    int sprite_lines,
    int sprite_columns,
    double duration,
    std::string direction) {

    DEBUG("Started");
    engine::Game& game = engine::Game::get_instance();

    engine::Animation* animation = nullptr;
    animation = new engine::Animation(
        game.get_renderer(),
        path,
        // is_active
        false,
        std::make_pair(0, 0),
        // priority
        1,
        sprite_lines,
        sprite_columns,
        duration,
        // in_loop
        true,
        direction
    );

    animation->set_values(
        std::make_pair(170, 78),
        std::make_pair(170, 78),
        std::make_pair(0, 0)
    );

    DEBUG("Ended");

    return animation;
}
<|endoftext|>


<commit_before>// ---------------------------------------------------------------------------
//
// This file is part of the <kortex> library suite
//
// Copyright (C) 2013 Engin Tola
//
// See LICENSE file for license information.
//
// author: Engin Tola
// e-mail: engintola@gmail.com
// web   : http://www.engintola.com
//
// ---------------------------------------------------------------------------
#include <kortex/image_io.h>
#include <kortex/image.h>
#include <kortex/fileio.h>
#include <kortex/string.h>

#include <kortex/image_io_pnm.h>
#include <kortex/image_io_png.h>
#include <kortex/image_io_jpg.h>

namespace kortex {

    void save_binary( const string& file, const Image* img ) {
        passert_pointer( img );
        ofstream fout;
        open_or_fail( file, fout );
        insert_binary_stream_begin_tag( fout );
        write_bparam( fout, img->w() );
        write_bparam( fout, img->h() );
        write_bparam( fout, img->ch() );
        write_bparam( fout, (int)img->type() );
        size_t imsz = img->pixel_count();
        switch( img->type() ) {
        case IT_U_GRAY: write_bparam( fout, img->get_row_u (0  ), imsz ); break;
        case IT_U_PRGB: write_bparam( fout, img->get_row_u (0  ), imsz ); break;
        case IT_U_IRGB: write_bparam( fout, img->get_row_ui(0,0), imsz ); break;
        case IT_F_GRAY: write_bparam( fout, img->get_row_f (0  ), imsz ); break;
        case IT_F_PRGB: write_bparam( fout, img->get_row_f (0  ), imsz ); break;
        case IT_F_IRGB: write_bparam( fout, img->get_row_fi(0,0), imsz ); break;
        default: switch_fatality();
        }
        insert_binary_stream_end_tag( fout );
        fout.close();
    }

    void load_binary( const string& file, Image* img ) {
        passert_pointer( img );
        ifstream fin;
        open_or_fail( file, fin );
        check_binary_stream_begin_tag( fin );
        int w, h, ch, type;
        read_bparam( fin, w );
        read_bparam( fin, h );
        read_bparam( fin, ch );
        read_bparam( fin, type );
        img->create( w, h, get_image_type(type) );
        size_t imsz = img->pixel_count();
        switch( img->type() ) {
        case IT_U_GRAY: read_bparam( fin, img->get_row_u (0  ), imsz ); break;
        case IT_U_PRGB: read_bparam( fin, img->get_row_u (0  ), imsz ); break;
        case IT_U_IRGB: read_bparam( fin, img->get_row_ui(0,0), imsz ); break;
        case IT_F_GRAY: read_bparam( fin, img->get_row_f (0  ), imsz ); break;
        case IT_F_PRGB: read_bparam( fin, img->get_row_f (0  ), imsz ); break;
        case IT_F_IRGB: read_bparam( fin, img->get_row_fi(0,0), imsz ); break;
        default: switch_fatality();
        }
        check_binary_stream_end_tag( fin );
        fin.close();
    }

    void read_ibin_size( const string& file, int& w, int& h, int& nc ) {
        ifstream fin;
        open_or_fail( file, fin );
        check_binary_stream_begin_tag( fin );
        read_bparam( fin, w );
        read_bparam( fin, h );
        read_bparam( fin, nc );
        fin.close();
    }

    void read_image_size( const string& file, int& w, int& h, int& nc ) {
        file_exists_or_fail(file);
        switch( get_file_format(file) ) {
        case FF_PGM :
        case FF_PPM : read_pnm_size ( file, w, h, nc ); break;
        case FF_JPG : read_jpg_size ( file, w, h, nc ); break;
        case FF_PNG : read_png_size ( file, w, h, nc ); break;
        case FF_IBIN: read_ibin_size( file, w, h, nc ); break;
        default     : logman_fatal_g( "unhandled image format [%s]", get_file_extension(file).c_str() );
        }
    }

    void load_image( const string& file, Image* img) {
        file_exists_or_fail(file);
        switch( get_file_format(file) ) {
        case FF_PGM : load_pgm   ( file, img ); break;
        case FF_PPM : load_ppm   ( file, img ); break;
        case FF_JPG : load_jpg   ( file, img ); break;
        case FF_PNG : load_png   ( file, img ); break;
        case FF_IBIN: load_binary( file, img ); break;
        default     : logman_fatal_g( "unhandled image format [%s]", get_file_extension(file).c_str() );
        }
    }

    void save_image( const string& file, const Image* img) {
        switch( get_file_format(file) ) {
        case FF_PGM : save_pgm   ( file, img ); break;
        case FF_PPM : save_ppm   ( file, img ); break;
        case FF_JPG : save_jpg   ( file, img ); break;
        case FF_PNG : save_png   ( file, img ); break;
        case FF_IBIN: save_binary( file, img ); break;
        default: switch_fatality();
        }
    }

}

<commit_msg>image_io update - pixel_count element_count in binary load<commit_after>// ---------------------------------------------------------------------------
//
// This file is part of the <kortex> library suite
//
// Copyright (C) 2013 Engin Tola
//
// See LICENSE file for license information.
//
// author: Engin Tola
// e-mail: engintola@gmail.com
// web   : http://www.engintola.com
//
// ---------------------------------------------------------------------------
#include <kortex/image_io.h>
#include <kortex/image.h>
#include <kortex/fileio.h>
#include <kortex/string.h>

#include <kortex/image_io_pnm.h>
#include <kortex/image_io_png.h>
#include <kortex/image_io_jpg.h>

namespace kortex {

    void save_binary( const string& file, const Image* img ) {
        passert_pointer( img );
        ofstream fout;
        open_or_fail( file, fout );
        insert_binary_stream_begin_tag( fout );
        write_bparam( fout, img->w() );
        write_bparam( fout, img->h() );
        write_bparam( fout, img->ch() );
        write_bparam( fout, (int)img->type() );
        size_t imsz = img->element_count();
        switch( img->type() ) {
        case IT_U_GRAY: write_bparam( fout, img->get_row_u (0  ), imsz ); break;
        case IT_U_PRGB: write_bparam( fout, img->get_row_u (0  ), imsz ); break;
        case IT_U_IRGB: write_bparam( fout, img->get_row_ui(0,0), imsz ); break;
        case IT_F_GRAY: write_bparam( fout, img->get_row_f (0  ), imsz ); break;
        case IT_F_PRGB: write_bparam( fout, img->get_row_f (0  ), imsz ); break;
        case IT_F_IRGB: write_bparam( fout, img->get_row_fi(0,0), imsz ); break;
        default: switch_fatality();
        }
        insert_binary_stream_end_tag( fout );
        fout.close();
    }

    void load_binary( const string& file, Image* img ) {
        passert_pointer( img );
        ifstream fin;
        open_or_fail( file, fin );
        check_binary_stream_begin_tag( fin );
        int w, h, ch, type;
        read_bparam( fin, w );
        read_bparam( fin, h );
        read_bparam( fin, ch );
        read_bparam( fin, type );
        img->create( w, h, get_image_type(type) );
        size_t imsz = img->element_count();
        switch( img->type() ) {
        case IT_U_GRAY: read_bparam( fin, img->get_row_u (0  ), imsz ); break;
        case IT_U_PRGB: read_bparam( fin, img->get_row_u (0  ), imsz ); break;
        case IT_U_IRGB: read_bparam( fin, img->get_row_ui(0,0), imsz ); break;
        case IT_F_GRAY: read_bparam( fin, img->get_row_f (0  ), imsz ); break;
        case IT_F_PRGB: read_bparam( fin, img->get_row_f (0  ), imsz ); break;
        case IT_F_IRGB: read_bparam( fin, img->get_row_fi(0,0), imsz ); break;
        default: switch_fatality();
        }
        check_binary_stream_end_tag( fin );
        fin.close();
    }

    void read_ibin_size( const string& file, int& w, int& h, int& nc ) {
        ifstream fin;
        open_or_fail( file, fin );
        check_binary_stream_begin_tag( fin );
        read_bparam( fin, w );
        read_bparam( fin, h );
        read_bparam( fin, nc );
        fin.close();
    }

    void read_image_size( const string& file, int& w, int& h, int& nc ) {
        file_exists_or_fail(file);
        switch( get_file_format(file) ) {
        case FF_PGM :
        case FF_PPM : read_pnm_size ( file, w, h, nc ); break;
        case FF_JPG : read_jpg_size ( file, w, h, nc ); break;
        case FF_PNG : read_png_size ( file, w, h, nc ); break;
        case FF_IBIN: read_ibin_size( file, w, h, nc ); break;
        default     : logman_fatal_g( "unhandled image format [%s]", get_file_extension(file).c_str() );
        }
    }

    void load_image( const string& file, Image* img) {
        file_exists_or_fail(file);
        switch( get_file_format(file) ) {
        case FF_PGM : load_pgm   ( file, img ); break;
        case FF_PPM : load_ppm   ( file, img ); break;
        case FF_JPG : load_jpg   ( file, img ); break;
        case FF_PNG : load_png   ( file, img ); break;
        case FF_IBIN: load_binary( file, img ); break;
        default     : logman_fatal_g( "unhandled image format [%s]", get_file_extension(file).c_str() );
        }
    }

    void save_image( const string& file, const Image* img) {
        switch( get_file_format(file) ) {
        case FF_PGM : save_pgm   ( file, img ); break;
        case FF_PPM : save_ppm   ( file, img ); break;
        case FF_JPG : save_jpg   ( file, img ); break;
        case FF_PNG : save_png   ( file, img ); break;
        case FF_IBIN: save_binary( file, img ); break;
        default: switch_fatality();
        }
    }

}

<|endoftext|>


<commit_before># ifndef H_GOO_PARAMETERS_DICTIONARY_DICTIONARY_H
# define H_GOO_PARAMETERS_DICTIONARY_DICTIONARY_H

# include "goo_types.h"
# include "goo_exception.hpp"
# include <list>
# include <cassert>

namespace goo {
namespace dict {

template<typename ValueT>
class iParameter;

/**@class iAbstractParameter
 * @brief An abstract parameter is a base class for most entity in
 * Goo's dictionaries
 *
 * We're following here to POSIX convention, so option-arguments are
 * never optional:
 * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02
 *
 * The following subclasses are expected:
 *  - single-char keys (here referred as `shortcuts')   (flags or with values, multiple time)
 *  - long options                                      (flags or with values)
 *  - unnamed positional arguments
 *  - sections (dictionaries itself)
 */
class iAbstractParameter /* {{{ */ {
public:
    typedef UByte ParameterEntryFlag;
    static const ParameterEntryFlag
            set,
            option,
            positional,
            atomic,
            singular,
            required,
            shortened
        ;
private:
    char * _name,           ///< Name of the option. Can be set to nullptr.
         * _description;    ///< Description of the option. Can be set to nullptr.
    /// Stores logical description of an instance.
    ParameterEntryFlag _flags;
protected:
    /// Used only when shortened flag is set.
    char _shortcut;
protected:
    /// Sets the «set» flag translating instance to initialized state.
    void _set_set_flag();

    /// Sets the «required» flag marking a mandatory parameter.
    void _set_required_flag();

    /// This method is to be used by lists only.
    void _unset_singular();

    /// Single ctr can be only invoked by descendants.
    iAbstractParameter( const char * name,
                        const char * description,
                        ParameterEntryFlag flags,
                        char shortcut = '\0');
public:
    virtual ~iAbstractParameter();

    /// Returns pointer to name string.
    const char * name() const;

    /// Returns pointer to description string.
    const char * description() const;

    /// Returns shortcut if it was set. Otherwise returns '\0'.
    char shortcut() const { return _shortcut; }

    /// Returns true, if parameter has a value set (even if it is a default one).
    bool is_set() const {
            return _flags & set;
        }
    /// Returns true, if parameter means logical flags (e.g. is option).
    bool is_option() const {
            return _flags & option;
        }
    /// Returns true, if parameter expects a value (or already contain a default one).
    bool has_value() const {
            return !is_option();
        }
    /// Returns true, if parameter has no name (at all --- even one-letter shortcut).
    bool is_positional() const {
            return _flags & positional;
        }
    /// Returns true, if parameter is not a dictionary.
    bool is_atomic() const {
            return _flags & atomic;
        }
    /// Returns true, if parameter is a dictionary.
    bool is_dictionary() const {
            return is_atomic();
        }
    /// Returns true, if parameter has only one value.
    bool is_singular() const {
            return _flags & singular;
        }
    /// Returns true, if parameter has a set of values.
    bool has_multiple_values() const {
            return !is_singular();
        }
    /// Returns true, if parameter is mandatory.
    bool is_mandatory() const {
            return _flags & required;
        }
    /// Returns true, if parameter can be omitted.
    bool is_optional() const {
            return !is_mandatory();
        }
    /// Returns true, if parameter has a single-character shortcut.
    bool has_shortcut() const {
            return _flags & shortened;
        }
};  /*}}}*/ // class iAbstractParameter

/* @class iSingularParameter
 * @brief Generic command-line parameter features interface.
 *
 * At this level of inheritance the less-generic definition of
 * parameter dictionary entries is defined.
 */
class iSingularParameter : public iAbstractParameter /*{{{*/ {
protected:
    virtual void _V_parse_argument( const char * ) = 0;
    virtual std::string _V_to_string() const = 0;
public:
    /// Returns single-char shortcut for this parameter.
    char shortcut() const { return _shortcut; }

    /// Parses argument from string representation.
    void parse_argument( const char * strval ) {  _V_parse_argument( strval ); }

    /// Forms a human-readable string to be displayed at logs.
    std::string to_string() const { return _V_to_string(); }

    iSingularParameter( const char * name,
                        const char * description,
                        ParameterEntryFlag flags,
                        char shortcut = '\0' );

    /// Getter method.
    template<typename T> const T &
    as() const {
        auto ptr = dynamic_cast<iParameter<T> const *>(this);
        if( !ptr ) {
            if( this->name() ) {
                emraise(badCast, "Couldn't cast parameter \"%s\" to specified type.", name() );
            } else {
                emraise(badCast, "Couldn't cast parameter '%c' to specified type.", shortcut() );
            }
        }
        return ptr->value();
    }
};  // }}} class iSingularParameter

/**@class iParameter
 * @brief A valued intermediate class representing dictionary entry with
 * value of certain type.
 *
 * Defines common value-operation routines.
 * */
template<typename ValueT>
class iParameter : public iSingularParameter /*{{{*/ {
public:
    typedef ValueT Value;
private:
    Value _value;
protected:
    void _set_value( const ValueT & );
    virtual void _V_parse_argument( const char * strval ) override {
        _set_value( _V_parse( strval ) ); }
    virtual std::string _V_to_string( ) const override {
        assert( is_set() );
        return _V_stringify_value( value() ); }

    virtual Value _V_parse( const char * ) const = 0;
    virtual std::string _V_stringify_value( const Value & ) const = 0;
public:
    iParameter( const char * name,
                const char * description,
                ParameterEntryFlag,
                char shortcut_ = '\0' );

    iParameter( const char * name,
                const char * description,
                const ValueT & defaultValue,
                ParameterEntryFlag,
                char shortcut_ = '\0' );

    ~iParameter() {}

    const ValueT & value() const;
};  // class iParameter

template<typename ValueT>
iParameter<ValueT>::iParameter( const char * name,
                                const char * description,
                                ParameterEntryFlag flags,
                                char shortcut_ ) :
        iSingularParameter( name, description, flags, shortcut_ ) {
    // Checks for consistency:
    /* ... */
}

template<typename ValueT>
iParameter<ValueT>::iParameter( const char * name,
                                const char * description,
                                const ValueT & defaultValue,
                                ParameterEntryFlag flags,
                                char shortcut_ ) :
        iSingularParameter( name, description, flags, shortcut_ ),
        _value(defaultValue) {
    // Checks for consistency:
    /* ... */
}

template<typename ValueT> const ValueT &
iParameter<ValueT>::value() const {
    return _value;
}

template<typename ValueT> void
iParameter<ValueT>::_set_value( const ValueT & val ) {
    _set_set_flag();
    _value = val;
}

/**@class Parameter
 * @brief User-side implementation class. Extension point for user parameters type.
 *
 * There is no default implementation of this class --- only standard C classes
 * are implemented in Goo library.
 */
template<typename ValueT>
class Parameter {
    //std::static_assert<false>( "dft" );
};  // Defailt implementation is empty.

/**@brief
 *
 * Ctrs are heavily restricted here.
 * TODO: track `default' values overriding.
 */
template<typename ValueT>
class Parameter<std::list<ValueT> > : protected Parameter<ValueT> {
private:
    std::list<ValueT> _values;
protected:
    virtual void _V_push_value( const ValueT & v ) {
        _values.push_back( v ); }

    virtual void _V_parse_argument( const char * strval ) override {
        Parameter<ValueT>::_V_parse_argument( strval );
        _V_push_value( Parameter<ValueT>::value() ); }
public:
    const std::list<ValueT> & values() const { return _values; }

    template<class ... Types>
    Parameter( const std::initializer_list<ValueT> & il, Types ... args ) :
        Parameter<ValueT>( args ... , *il.begin() )
    { /* TODO: push back all the default values */
        this->_unset_singular();
        assert( !(this->name() == nullptr && !this->has_shortcut()) );
        assert( this->description() ); }

    template<class ... Types>
    Parameter( Types ... args ) :
        Parameter<ValueT>( args ... )
    {   this->_unset_singular();
        assert( !(this->name() == nullptr && !this->has_shortcut()) );
        assert( this->description() ); }

    ~Parameter() {}

    friend class InsertionProxy;

    using iAbstractParameter::name;
    using iAbstractParameter::description;
    using iAbstractParameter::shortcut;
    // ... whatever?
};

//
// Specializations
/////////////////

/**@brief Logic option argument type.
 *
 * Most common usage of this object is to provide logical flag for
 * enabling/disabling some functionality. E.g.:
 *      $ do_something -v
 * Or, with equivalent meaning:
 *      $ do_something --verbose=true
 * Besides of true/false values, the following synonims are accepted:
 *      true : True, TRUE, yes, Yes, YES, enable, Enable, ENABLE, on, On, ON
 *      false: False, FALSE, no, No, NO, disable, Disable, DISABLE, off, Off, OFF
 * Note, that this kind of argument can not be required.
 * Possible construction variants:
 *      .p<bool>( 'v', "Enables verbose output" )
 *      .p<bool>( 'q', "Be quiet", true )
 *      .p<bool>( "quet", "Be quiet", true )
 *      .p<bool>( "verbose", "Enables verbose output" )
 *      .p<bool>( 'v', "verbose", "Enables verbose output" )
 *      .p<bool>( 'q', "quet", "Be quiet", true )
 * If there are default argument specified, the argument for such kind of an option
 * is mandatory. Otherwise, it must be omitted. E.g.:
 *   o to enable `.p<bool>( 'v', "Enables verbose output" )` it is enough to:
 *      $ myprogram -v
 *   o contraversary, for .p<bool>( 'q', "Be quiet", true ) it is necessary to:
 *      $ myprogram -q false
 * This aspect affects generated help message.
 * */
template<>
class Parameter<bool> : public iParameter<bool> {
public:
    /// Only long option ctr.
    Parameter( const char * name_,
               const char * description_ );
    /// Long option with shortcut.
    Parameter( char shortcut_,
               const char * name_,
               const char * description_ );
    /// Only short option.
    Parameter( char shortcut_,
               const char * description_ );
    /// Only long option ctr.
    Parameter( const char * name_,
               const char * description_,
               bool default_ );
    /// Long option with shortcut.
    Parameter( char shortcut_,
               const char * name_,
               const char * description_,
               bool default_ );
    /// Only short option.
    Parameter( char shortcut_,
               const char * description_,
               bool default_ );

    // This is to prevent implicit conversion from char * to bool --- fails at compile time.
    Parameter( const char *,
               const char *,
               const char * );
    // This is to prevent implicit conversion from char * to bool --- fails at compile time.
    Parameter( char,
               const char *,
               const char *,
               const char * );

    /// This method is used mostly by Configuration class.
    virtual void set_option( bool );

protected:
    /// Sets parameter value from string. Following strings are acceptable
    /// with appropriate meaning (case insensitive):
    /// (true|enable|on|yes|1)    logically corresponds to `true';
    /// (false|disable|off|no|0)  logically corresponds to `false'.
    virtual Value _V_parse( const char * ) const override;

    /// Returns 'True' or 'False' depending on current value.
    virtual std::string _V_stringify_value( const Value & ) const override;
};

}  // namespace dict
}  // namespace goo

# endif  // H_GOO_PARAMETERS_DICTIONARY_DICTIONARY_H

<commit_msg>+ introducing int-parameter explicit specification<commit_after># ifndef H_GOO_PARAMETERS_DICTIONARY_DICTIONARY_H
# define H_GOO_PARAMETERS_DICTIONARY_DICTIONARY_H

# include "goo_types.h"
# include "goo_exception.hpp"
# include <list>
# include <cassert>

namespace goo {
namespace dict {

template<typename ValueT>
class iParameter;

/**@class iAbstractParameter
 * @brief An abstract parameter is a base class for most entity in
 * Goo's dictionaries
 *
 * We're following here to POSIX convention, so option-arguments are
 * never optional:
 * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02
 *
 * The following subclasses are expected:
 *  - single-char keys (here referred as `shortcuts')   (flags or with values, multiple time)
 *  - long options                                      (flags or with values)
 *  - unnamed positional arguments
 *  - sections (dictionaries itself)
 */
class iAbstractParameter /* {{{ */ {
public:
    typedef UByte ParameterEntryFlag;
    static const ParameterEntryFlag
            set,
            option,
            positional,
            atomic,
            singular,
            required,
            shortened
        ;
private:
    char * _name,           ///< Name of the option. Can be set to nullptr.
         * _description;    ///< Description of the option. Can be set to nullptr.
    /// Stores logical description of an instance.
    ParameterEntryFlag _flags;
protected:
    /// Used only when shortened flag is set.
    char _shortcut;
protected:
    /// Sets the «set» flag translating instance to initialized state.
    void _set_set_flag();

    /// Sets the «required» flag marking a mandatory parameter.
    void _set_required_flag();

    /// This method is to be used by lists only.
    void _unset_singular();

    /// Single ctr can be only invoked by descendants.
    iAbstractParameter( const char * name,
                        const char * description,
                        ParameterEntryFlag flags,
                        char shortcut = '\0');
public:
    virtual ~iAbstractParameter();

    /// Returns pointer to name string.
    const char * name() const;

    /// Returns pointer to description string.
    const char * description() const;

    /// Returns shortcut if it was set. Otherwise returns '\0'.
    char shortcut() const { return _shortcut; }

    /// Returns true, if parameter has a value set (even if it is a default one).
    bool is_set() const {
            return _flags & set;
        }
    /// Returns true, if parameter means logical flags (e.g. is option).
    bool is_option() const {
            return _flags & option;
        }
    /// Returns true, if parameter expects a value (or already contain a default one).
    bool has_value() const {
            return !is_option();
        }
    /// Returns true, if parameter has no name (at all --- even one-letter shortcut).
    bool is_positional() const {
            return _flags & positional;
        }
    /// Returns true, if parameter is not a dictionary.
    bool is_atomic() const {
            return _flags & atomic;
        }
    /// Returns true, if parameter is a dictionary.
    bool is_dictionary() const {
            return is_atomic();
        }
    /// Returns true, if parameter has only one value.
    bool is_singular() const {
            return _flags & singular;
        }
    /// Returns true, if parameter has a set of values.
    bool has_multiple_values() const {
            return !is_singular();
        }
    /// Returns true, if parameter is mandatory.
    bool is_mandatory() const {
            return _flags & required;
        }
    /// Returns true, if parameter can be omitted.
    bool is_optional() const {
            return !is_mandatory();
        }
    /// Returns true, if parameter has a single-character shortcut.
    bool has_shortcut() const {
            return _flags & shortened;
        }
};  /*}}}*/ // class iAbstractParameter

/* @class iSingularParameter
 * @brief Generic command-line parameter features interface.
 *
 * At this level of inheritance the less-generic definition of
 * parameter dictionary entries is defined.
 */
class iSingularParameter : public iAbstractParameter /*{{{*/ {
protected:
    virtual void _V_parse_argument( const char * ) = 0;
    virtual std::string _V_to_string() const = 0;
public:
    /// Returns single-char shortcut for this parameter.
    char shortcut() const { return _shortcut; }

    /// Parses argument from string representation.
    void parse_argument( const char * strval ) {  _V_parse_argument( strval ); }

    /// Forms a human-readable string to be displayed at logs.
    std::string to_string() const { return _V_to_string(); }

    iSingularParameter( const char * name,
                        const char * description,
                        ParameterEntryFlag flags,
                        char shortcut = '\0' );

    /// Getter method.
    template<typename T> const T &
    as() const {
        auto ptr = dynamic_cast<iParameter<T> const *>(this);
        if( !ptr ) {
            if( this->name() ) {
                emraise(badCast, "Couldn't cast parameter \"%s\" to specified type.", name() );
            } else {
                emraise(badCast, "Couldn't cast parameter '%c' to specified type.", shortcut() );
            }
        }
        return ptr->value();
    }
};  // }}} class iSingularParameter

/**@class iParameter
 * @brief A valued intermediate class representing dictionary entry with
 * value of certain type.
 *
 * Defines common value-operation routines.
 * */
template<typename ValueT>
class iParameter : public iSingularParameter /*{{{*/ {
public:
    typedef ValueT Value;
private:
    Value _value;
protected:
    void _set_value( const ValueT & );
    virtual void _V_parse_argument( const char * strval ) override {
        _set_value( _V_parse( strval ) ); }
    virtual std::string _V_to_string( ) const override {
        assert( is_set() );
        return _V_stringify_value( value() ); }

    virtual Value _V_parse( const char * ) const = 0;
    virtual std::string _V_stringify_value( const Value & ) const = 0;
public:
    iParameter( const char * name,
                const char * description,
                ParameterEntryFlag,
                char shortcut_ = '\0' );

    iParameter( const char * name,
                const char * description,
                const ValueT & defaultValue,
                ParameterEntryFlag,
                char shortcut_ = '\0' );

    ~iParameter() {}

    const ValueT & value() const;
};  // class iParameter

template<typename ValueT>
iParameter<ValueT>::iParameter( const char * name,
                                const char * description,
                                ParameterEntryFlag flags,
                                char shortcut_ ) :
        iSingularParameter( name, description, flags, shortcut_ ) {
    // Checks for consistency:
    /* ... */
}

template<typename ValueT>
iParameter<ValueT>::iParameter( const char * name,
                                const char * description,
                                const ValueT & defaultValue,
                                ParameterEntryFlag flags,
                                char shortcut_ ) :
        iSingularParameter( name, description, flags, shortcut_ ),
        _value(defaultValue) {
    // Checks for consistency:
    /* ... */
}

template<typename ValueT> const ValueT &
iParameter<ValueT>::value() const {
    return _value;
}

template<typename ValueT> void
iParameter<ValueT>::_set_value( const ValueT & val ) {
    _set_set_flag();
    _value = val;
}

/**@class Parameter
 * @brief User-side implementation class. Extension point for user parameters type.
 *
 * There is no default implementation of this class --- only standard C classes
 * are implemented in Goo library.
 */
template<typename ValueT>
class Parameter {
    //std::static_assert<false>( "dft" );
};  // Defailt implementation is empty.

/**@brief
 *
 * Ctrs are heavily restricted here.
 * TODO: track `default' values overriding.
 */
template<typename ValueT>
class Parameter<std::list<ValueT> > : protected Parameter<ValueT> {
private:
    std::list<ValueT> _values;
protected:
    virtual void _V_push_value( const ValueT & v ) {
        _values.push_back( v ); }

    virtual void _V_parse_argument( const char * strval ) override {
        Parameter<ValueT>::_V_parse_argument( strval );
        _V_push_value( Parameter<ValueT>::value() ); }
public:
    const std::list<ValueT> & values() const { return _values; }

    template<class ... Types>
    Parameter( const std::initializer_list<ValueT> & il, Types ... args ) :
        Parameter<ValueT>( args ... , *il.begin() )
    { /* TODO: push back all the default values */
        this->_unset_singular();
        assert( !(this->name() == nullptr && !this->has_shortcut()) );
        assert( this->description() ); }

    template<class ... Types>
    Parameter( Types ... args ) :
        Parameter<ValueT>( args ... )
    {   this->_unset_singular();
        assert( !(this->name() == nullptr && !this->has_shortcut()) );
        assert( this->description() ); }

    ~Parameter() {}

    friend class InsertionProxy;

    using iAbstractParameter::name;
    using iAbstractParameter::description;
    using iAbstractParameter::shortcut;
    // ... whatever?
};

//
// Specializations
/////////////////

/**@brief Logic option argument type.
 *
 * Most common usage of this object is to provide logical flag for
 * enabling/disabling some functionality. E.g.:
 *      $ do_something -v
 * Or, with equivalent meaning:
 *      $ do_something --verbose=true
 * Besides of true/false values, the following synonims are accepted:
 *      true : True, TRUE, yes, Yes, YES, enable, Enable, ENABLE, on, On, ON
 *      false: False, FALSE, no, No, NO, disable, Disable, DISABLE, off, Off, OFF
 * Note, that this kind of argument can not be required.
 * Possible construction variants:
 *      .p<bool>( 'v', "Enables verbose output" )
 *      .p<bool>( 'q', "Be quiet", true )
 *      .p<bool>( "quet", "Be quiet", true )
 *      .p<bool>( "verbose", "Enables verbose output" )
 *      .p<bool>( 'v', "verbose", "Enables verbose output" )
 *      .p<bool>( 'q', "quet", "Be quiet", true )
 * If there are default argument specified, the argument for such kind of an option
 * is mandatory. Otherwise, it must be omitted. E.g.:
 *   o to enable `.p<bool>( 'v', "Enables verbose output" )` it is enough to:
 *      $ myprogram -v
 *   o contraversary, for .p<bool>( 'q', "Be quiet", true ) it is necessary to:
 *      $ myprogram -q false
 * This aspect affects generated help message.
 * */
template<>
class Parameter<bool> : public iParameter<bool> {
public:
    /// Only long option ctr.
    Parameter( const char * name_,
               const char * description_ );
    /// Long option with shortcut.
    Parameter( char shortcut_,
               const char * name_,
               const char * description_ );
    /// Only short option.
    Parameter( char shortcut_,
               const char * description_ );
    /// Only long option ctr.
    Parameter( const char * name_,
               const char * description_,
               bool default_ );
    /// Long option with shortcut.
    Parameter( char shortcut_,
               const char * name_,
               const char * description_,
               bool default_ );
    /// Only short option.
    Parameter( char shortcut_,
               const char * description_,
               bool default_ );

    // This is to prevent implicit conversion from char * to bool --- fails at compile time.
    Parameter( const char *,
               const char *,
               const char * );
    // This is to prevent implicit conversion from char * to bool --- fails at compile time.
    Parameter( char,
               const char *,
               const char *,
               const char * );

    /// This method is used mostly by Configuration class.
    virtual void set_option( bool );

protected:
    /// Sets parameter value from string. Following strings are acceptable
    /// with appropriate meaning (case insensitive):
    /// (true|enable|on|yes|1)    logically corresponds to `true';
    /// (false|disable|off|no|0)  logically corresponds to `false'.
    virtual Value _V_parse( const char * ) const override;

    /// Returns 'True' or 'False' depending on current value.
    virtual std::string _V_stringify_value( const Value & ) const override;
};

template<>
class Parameter<int> : public iParameter<int> {
public:
    /// Only long option ctr.
    Parameter( const char * name_,
               const char * description_ );
    /// Long option with shortcut.
    Parameter( char shortcut_,
               const char * name_,
               const char * description_ );
    /// Only short option.
    Parameter( char shortcut_,
               const char * description_ );
    /// Only long option ctr.
    Parameter( const char * name_,
               const char * description_,
               int default_ );
    /// Long option with shortcut.
    Parameter( char shortcut_,
               const char * name_,
               const char * description_,
               int default_ );
    /// Only short option.
    Parameter( char shortcut_,
               const char * description_,
               int default_ );

protected:
    /// Internally uses strtol() from standard library.
    virtual Value _V_parse( const char * ) const override;

    /// Returns 'True' or 'False' depending on current value.
    virtual std::string _V_stringify_value( const Value & ) const override;
};

}  // namespace dict
}  // namespace goo

# endif  // H_GOO_PARAMETERS_DICTIONARY_DICTIONARY_H

<|endoftext|>