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

#include <map>

#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>

#include "key.h"

// Generate a private key from just the secret parameter
int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
{
    int ok = 0;
    BN_CTX *ctx = NULL;
    EC_POINT *pub_key = NULL;

    if (!eckey) return 0;

    const EC_GROUP *group = EC_KEY_get0_group(eckey);

    if ((ctx = BN_CTX_new()) == NULL)
        goto err;

    pub_key = EC_POINT_new(group);

    if (pub_key == NULL)
        goto err;

    if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx))
        goto err;

    EC_KEY_set_private_key(eckey,priv_key);
    EC_KEY_set_public_key(eckey,pub_key);

    ok = 1;

err:

    if (pub_key)
        EC_POINT_free(pub_key);
    if (ctx != NULL)
        BN_CTX_free(ctx);

    return(ok);
}

// Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields
// recid selects which key is recovered
// if check is nonzero, additional checks are performed
int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check)
{
    if (!eckey) return 0;

    int ret = 0;
    BN_CTX *ctx = NULL;

    BIGNUM *x = NULL;
    BIGNUM *e = NULL;
    BIGNUM *order = NULL;
    BIGNUM *sor = NULL;
    BIGNUM *eor = NULL;
    BIGNUM *field = NULL;
    EC_POINT *R = NULL;
    EC_POINT *O = NULL;
    EC_POINT *Q = NULL;
    BIGNUM *rr = NULL;
    BIGNUM *zero = NULL;
    int n = 0;
    int i = recid / 2;

    const EC_GROUP *group = EC_KEY_get0_group(eckey);
    if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; }
    BN_CTX_start(ctx);
    order = BN_CTX_get(ctx);
    if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; }
    x = BN_CTX_get(ctx);
    if (!BN_copy(x, order)) { ret=-1; goto err; }
    if (!BN_mul_word(x, i)) { ret=-1; goto err; }
    if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; }
    field = BN_CTX_get(ctx);
    if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; }
    if (BN_cmp(x, field) >= 0) { ret=0; goto err; }
    if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
    if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; }
    if (check)
    {
        if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
        if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; }
        if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; }
    }
    if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
    n = EC_GROUP_get_degree(group);
    e = BN_CTX_get(ctx);
    if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; }
    if (8*msglen > n) BN_rshift(e, e, 8-(n & 7));
    zero = BN_CTX_get(ctx);
    if (!BN_zero(zero)) { ret=-1; goto err; }
    if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; }
    rr = BN_CTX_get(ctx);
    if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; }
    sor = BN_CTX_get(ctx);
    if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; }
    eor = BN_CTX_get(ctx);
    if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; }
    if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; }
    if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; }

    ret = 1;

err:
    if (ctx) {
        BN_CTX_end(ctx);
        BN_CTX_free(ctx);
    }
    if (R != NULL) EC_POINT_free(R);
    if (O != NULL) EC_POINT_free(O);
    if (Q != NULL) EC_POINT_free(Q);
    return ret;
}

void CKey::SetCompressedPubKey()
{
    EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED);
    fCompressedPubKey = true;
}

void CKey::Reset()
{
    fCompressedPubKey = false;
    pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
    if (pkey == NULL)
        throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed");
    fSet = false;
}

CKey::CKey()
{
    Reset();
}

CKey::CKey(const CKey& b)
{
    pkey = EC_KEY_dup(b.pkey);
    if (pkey == NULL)
        throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed");
    fSet = b.fSet;
}

CKey& CKey::operator=(const CKey& b)
{
    if (!EC_KEY_copy(pkey, b.pkey))
        throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed");
    fSet = b.fSet;
    return (*this);
}

CKey::~CKey()
{
    EC_KEY_free(pkey);
}

bool CKey::IsNull() const
{
    return !fSet;
}

bool CKey::IsCompressed() const
{
    return fCompressedPubKey;
}

void CKey::MakeNewKey(bool fCompressed)
{
    if (!EC_KEY_generate_key(pkey))
        throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
    if (fCompressed)
        SetCompressedPubKey();
    fSet = true;
}

bool CKey::SetPrivKey(const CPrivKey& vchPrivKey)
{
    const unsigned char* pbegin = &vchPrivKey[0];
    if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size()))
        return false;
    fSet = true;
    return true;
}

bool CKey::SetSecret(const CSecret& vchSecret, bool fCompressed)
{
    EC_KEY_free(pkey);
    pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
    if (pkey == NULL)
        throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed");
    if (vchSecret.size() != 32)
        throw key_error("CKey::SetSecret() : secret must be 32 bytes");
    BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new());
    if (bn == NULL)
        throw key_error("CKey::SetSecret() : BN_bin2bn failed");
    if (!EC_KEY_regenerate_key(pkey,bn))
    {
        BN_clear_free(bn);
        throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed");
    }
    BN_clear_free(bn);
    fSet = true;
    if (fCompressed || fCompressedPubKey)
        SetCompressedPubKey();
    return true;
}

CSecret CKey::GetSecret(bool &fCompressed) const
{
    CSecret vchRet;
    vchRet.resize(32);
    const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
    int nBytes = BN_num_bytes(bn);
    if (bn == NULL)
        throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed");
    int n=BN_bn2bin(bn,&vchRet[32 - nBytes]);
    if (n != nBytes)
        throw key_error("CKey::GetSecret(): BN_bn2bin failed");
    fCompressed = fCompressedPubKey;
    return vchRet;
}

CPrivKey CKey::GetPrivKey() const
{
    int nSize = i2d_ECPrivateKey(pkey, NULL);
    if (!nSize)
        throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed");
    CPrivKey vchPrivKey(nSize, 0);
    unsigned char* pbegin = &vchPrivKey[0];
    if (i2d_ECPrivateKey(pkey, &pbegin) != nSize)
        throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size");
    return vchPrivKey;
}

bool CKey::SetPubKey(const CPubKey& vchPubKey)
{
    const unsigned char* pbegin = &vchPubKey.vchPubKey[0];
    if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.vchPubKey.size()))
        return false;
    fSet = true;
    if (vchPubKey.vchPubKey.size() == 33)
        SetCompressedPubKey();
    return true;
}

CPubKey CKey::GetPubKey() const
{
    int nSize = i2o_ECPublicKey(pkey, NULL);
    if (!nSize)
        throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed");
    std::vector<unsigned char> vchPubKey(nSize, 0);
    unsigned char* pbegin = &vchPubKey[0];
    if (i2o_ECPublicKey(pkey, &pbegin) != nSize)
        throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size");
    return CPubKey(vchPubKey);
}

bool CKey::Sign(uint256 hash, std::vector<unsigned char>& vchSig)
{
    unsigned int nSize = ECDSA_size(pkey);
    vchSig.resize(nSize); // Make sure it is big enough
    if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey))
    {
        vchSig.clear();
        return false;
    }
    vchSig.resize(nSize); // Shrink to fit actual size
    return true;
}

// create a compact signature (65 bytes), which allows reconstructing the used public key
// The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
//                  0x1D = second key with even y, 0x1E = second key with odd y
bool CKey::SignCompact(uint256 hash, std::vector<unsigned char>& vchSig)
{
    bool fOk = false;
    ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
    if (sig==NULL)
        return false;
    vchSig.clear();
    vchSig.resize(65,0);
    int nBitsR = BN_num_bits(sig->r);
    int nBitsS = BN_num_bits(sig->s);
    if (nBitsR <= 256 && nBitsS <= 256)
    {
        int nRecId = -1;
        for (int i=0; i<4; i++)
        {
            CKey keyRec;
            keyRec.fSet = true;
            if (fCompressedPubKey)
                keyRec.SetCompressedPubKey();
            if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1)
                if (keyRec.GetPubKey() == this->GetPubKey())
                {
                    nRecId = i;
                    break;
                }
        }

        if (nRecId == -1)
            throw key_error("CKey::SignCompact() : unable to construct recoverable key");

        vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0);
        BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]);
        BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]);
        fOk = true;
    }
    ECDSA_SIG_free(sig);
    return fOk;
}

// reconstruct public key from a compact signature
// This is only slightly more CPU intensive than just verifying it.
// If this function succeeds, the recovered public key is guaranteed to be valid
// (the signature is a valid signature of the given data for that key)
bool CKey::SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig)
{
    if (vchSig.size() != 65)
        return false;
    int nV = vchSig[0];
    if (nV<27 || nV>=35)
        return false;
    ECDSA_SIG *sig = ECDSA_SIG_new();
    BN_bin2bn(&vchSig[1],32,sig->r);
    BN_bin2bn(&vchSig[33],32,sig->s);

    EC_KEY_free(pkey);
    pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
    if (nV >= 31)
    {
        SetCompressedPubKey();
        nV -= 4;
    }
    if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) == 1)
    {
        fSet = true;
        ECDSA_SIG_free(sig);
        return true;
    }
    return false;
}

bool CKey::Verify(uint256 hash, const std::vector<unsigned char>& vchSig)
{
    // -1 = error, 0 = bad sig, 1 = good
    if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)
        return false;

    return true;
}

bool CKey::VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig)
{
    CKey key;
    if (!key.SetCompactSignature(hash, vchSig))
        return false;
    if (GetPubKey() != key.GetPubKey())
        return false;

    return true;
}

bool CKey::IsValid()
{
    if (!fSet)
        return false;

    bool fCompr;
    CSecret secret = GetSecret(fCompr);
    CKey key2;
    key2.SetSecret(secret, fCompr);
    return GetPubKey() == key2.GetPubKey();
}
<commit_msg>fix a memory leak in key.cpp<commit_after>// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <map>

#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>

#include "key.h"

// Generate a private key from just the secret parameter
int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
{
    int ok = 0;
    BN_CTX *ctx = NULL;
    EC_POINT *pub_key = NULL;

    if (!eckey) return 0;

    const EC_GROUP *group = EC_KEY_get0_group(eckey);

    if ((ctx = BN_CTX_new()) == NULL)
        goto err;

    pub_key = EC_POINT_new(group);

    if (pub_key == NULL)
        goto err;

    if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx))
        goto err;

    EC_KEY_set_private_key(eckey,priv_key);
    EC_KEY_set_public_key(eckey,pub_key);

    ok = 1;

err:

    if (pub_key)
        EC_POINT_free(pub_key);
    if (ctx != NULL)
        BN_CTX_free(ctx);

    return(ok);
}

// Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields
// recid selects which key is recovered
// if check is nonzero, additional checks are performed
int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check)
{
    if (!eckey) return 0;

    int ret = 0;
    BN_CTX *ctx = NULL;

    BIGNUM *x = NULL;
    BIGNUM *e = NULL;
    BIGNUM *order = NULL;
    BIGNUM *sor = NULL;
    BIGNUM *eor = NULL;
    BIGNUM *field = NULL;
    EC_POINT *R = NULL;
    EC_POINT *O = NULL;
    EC_POINT *Q = NULL;
    BIGNUM *rr = NULL;
    BIGNUM *zero = NULL;
    int n = 0;
    int i = recid / 2;

    const EC_GROUP *group = EC_KEY_get0_group(eckey);
    if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; }
    BN_CTX_start(ctx);
    order = BN_CTX_get(ctx);
    if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; }
    x = BN_CTX_get(ctx);
    if (!BN_copy(x, order)) { ret=-1; goto err; }
    if (!BN_mul_word(x, i)) { ret=-1; goto err; }
    if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; }
    field = BN_CTX_get(ctx);
    if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; }
    if (BN_cmp(x, field) >= 0) { ret=0; goto err; }
    if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
    if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; }
    if (check)
    {
        if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
        if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; }
        if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; }
    }
    if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
    n = EC_GROUP_get_degree(group);
    e = BN_CTX_get(ctx);
    if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; }
    if (8*msglen > n) BN_rshift(e, e, 8-(n & 7));
    zero = BN_CTX_get(ctx);
    if (!BN_zero(zero)) { ret=-1; goto err; }
    if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; }
    rr = BN_CTX_get(ctx);
    if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; }
    sor = BN_CTX_get(ctx);
    if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; }
    eor = BN_CTX_get(ctx);
    if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; }
    if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; }
    if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; }

    ret = 1;

err:
    if (ctx) {
        BN_CTX_end(ctx);
        BN_CTX_free(ctx);
    }
    if (R != NULL) EC_POINT_free(R);
    if (O != NULL) EC_POINT_free(O);
    if (Q != NULL) EC_POINT_free(Q);
    return ret;
}

void CKey::SetCompressedPubKey()
{
    EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED);
    fCompressedPubKey = true;
}

void CKey::Reset()
{
    fCompressedPubKey = false;
    if (pkey != NULL)
        EC_KEY_free(pkey);
    pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
    if (pkey == NULL)
        throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed");
    fSet = false;
}

CKey::CKey()
{
    pkey = NULL;
    Reset();
}

CKey::CKey(const CKey& b)
{
    pkey = EC_KEY_dup(b.pkey);
    if (pkey == NULL)
        throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed");
    fSet = b.fSet;
}

CKey& CKey::operator=(const CKey& b)
{
    if (!EC_KEY_copy(pkey, b.pkey))
        throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed");
    fSet = b.fSet;
    return (*this);
}

CKey::~CKey()
{
    EC_KEY_free(pkey);
}

bool CKey::IsNull() const
{
    return !fSet;
}

bool CKey::IsCompressed() const
{
    return fCompressedPubKey;
}

void CKey::MakeNewKey(bool fCompressed)
{
    if (!EC_KEY_generate_key(pkey))
        throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
    if (fCompressed)
        SetCompressedPubKey();
    fSet = true;
}

bool CKey::SetPrivKey(const CPrivKey& vchPrivKey)
{
    const unsigned char* pbegin = &vchPrivKey[0];
    if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size()))
        return false;
    fSet = true;
    return true;
}

bool CKey::SetSecret(const CSecret& vchSecret, bool fCompressed)
{
    EC_KEY_free(pkey);
    pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
    if (pkey == NULL)
        throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed");
    if (vchSecret.size() != 32)
        throw key_error("CKey::SetSecret() : secret must be 32 bytes");
    BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new());
    if (bn == NULL)
        throw key_error("CKey::SetSecret() : BN_bin2bn failed");
    if (!EC_KEY_regenerate_key(pkey,bn))
    {
        BN_clear_free(bn);
        throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed");
    }
    BN_clear_free(bn);
    fSet = true;
    if (fCompressed || fCompressedPubKey)
        SetCompressedPubKey();
    return true;
}

CSecret CKey::GetSecret(bool &fCompressed) const
{
    CSecret vchRet;
    vchRet.resize(32);
    const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
    int nBytes = BN_num_bytes(bn);
    if (bn == NULL)
        throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed");
    int n=BN_bn2bin(bn,&vchRet[32 - nBytes]);
    if (n != nBytes)
        throw key_error("CKey::GetSecret(): BN_bn2bin failed");
    fCompressed = fCompressedPubKey;
    return vchRet;
}

CPrivKey CKey::GetPrivKey() const
{
    int nSize = i2d_ECPrivateKey(pkey, NULL);
    if (!nSize)
        throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed");
    CPrivKey vchPrivKey(nSize, 0);
    unsigned char* pbegin = &vchPrivKey[0];
    if (i2d_ECPrivateKey(pkey, &pbegin) != nSize)
        throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size");
    return vchPrivKey;
}

bool CKey::SetPubKey(const CPubKey& vchPubKey)
{
    const unsigned char* pbegin = &vchPubKey.vchPubKey[0];
    if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.vchPubKey.size()))
        return false;
    fSet = true;
    if (vchPubKey.vchPubKey.size() == 33)
        SetCompressedPubKey();
    return true;
}

CPubKey CKey::GetPubKey() const
{
    int nSize = i2o_ECPublicKey(pkey, NULL);
    if (!nSize)
        throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed");
    std::vector<unsigned char> vchPubKey(nSize, 0);
    unsigned char* pbegin = &vchPubKey[0];
    if (i2o_ECPublicKey(pkey, &pbegin) != nSize)
        throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size");
    return CPubKey(vchPubKey);
}

bool CKey::Sign(uint256 hash, std::vector<unsigned char>& vchSig)
{
    unsigned int nSize = ECDSA_size(pkey);
    vchSig.resize(nSize); // Make sure it is big enough
    if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey))
    {
        vchSig.clear();
        return false;
    }
    vchSig.resize(nSize); // Shrink to fit actual size
    return true;
}

// create a compact signature (65 bytes), which allows reconstructing the used public key
// The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
// The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
//                  0x1D = second key with even y, 0x1E = second key with odd y
bool CKey::SignCompact(uint256 hash, std::vector<unsigned char>& vchSig)
{
    bool fOk = false;
    ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
    if (sig==NULL)
        return false;
    vchSig.clear();
    vchSig.resize(65,0);
    int nBitsR = BN_num_bits(sig->r);
    int nBitsS = BN_num_bits(sig->s);
    if (nBitsR <= 256 && nBitsS <= 256)
    {
        int nRecId = -1;
        for (int i=0; i<4; i++)
        {
            CKey keyRec;
            keyRec.fSet = true;
            if (fCompressedPubKey)
                keyRec.SetCompressedPubKey();
            if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1)
                if (keyRec.GetPubKey() == this->GetPubKey())
                {
                    nRecId = i;
                    break;
                }
        }

        if (nRecId == -1)
            throw key_error("CKey::SignCompact() : unable to construct recoverable key");

        vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0);
        BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]);
        BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]);
        fOk = true;
    }
    ECDSA_SIG_free(sig);
    return fOk;
}

// reconstruct public key from a compact signature
// This is only slightly more CPU intensive than just verifying it.
// If this function succeeds, the recovered public key is guaranteed to be valid
// (the signature is a valid signature of the given data for that key)
bool CKey::SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig)
{
    if (vchSig.size() != 65)
        return false;
    int nV = vchSig[0];
    if (nV<27 || nV>=35)
        return false;
    ECDSA_SIG *sig = ECDSA_SIG_new();
    BN_bin2bn(&vchSig[1],32,sig->r);
    BN_bin2bn(&vchSig[33],32,sig->s);

    EC_KEY_free(pkey);
    pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
    if (nV >= 31)
    {
        SetCompressedPubKey();
        nV -= 4;
    }
    if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) == 1)
    {
        fSet = true;
        ECDSA_SIG_free(sig);
        return true;
    }
    return false;
}

bool CKey::Verify(uint256 hash, const std::vector<unsigned char>& vchSig)
{
    // -1 = error, 0 = bad sig, 1 = good
    if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)
        return false;

    return true;
}

bool CKey::VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig)
{
    CKey key;
    if (!key.SetCompactSignature(hash, vchSig))
        return false;
    if (GetPubKey() != key.GetPubKey())
        return false;

    return true;
}

bool CKey::IsValid()
{
    if (!fSet)
        return false;

    bool fCompr;
    CSecret secret = GetSecret(fCompr);
    CKey key2;
    key2.SetSecret(secret, fCompr);
    return GetPubKey() == key2.GetPubKey();
}
<|endoftext|>


<commit_before>/**
 * This file is part of Slideshow.
 * Copyright (C) 2008-2012 David Sveningsson <ext@sidvind.com>
 *
 * Slideshow is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * Slideshow is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Slideshow.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifdef HAVE_CONFIG_H
#	include "config.h"
#endif

#include "log.hpp"
#include "ptr.h"
#include "exception.h"
#include <stdarg.h>
#include <cstdlib>
#include <cstring>
#include <memory> /* for auto_ptr */
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <portable/asprintf.h>
#include <portable/file.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#ifdef WIN32
#	include "win32.h"
#endif

#ifdef HAVE_SYSLOG
#	include <syslog.h>
int syslog_severity[5] = {
	LOG_DEBUG,
	LOG_INFO,
	LOG_NOTICE,
	LOG_WARNING,
	LOG_ERR
};
#endif /* HAVE_SYSLOG */

typedef std::vector<std::pair<Destination*, Severity>> vector;
typedef vector::iterator iterator;

static vector destinations;

FileDestination::FileDestination(const char* filename)
	: _fp(NULL)
	, _autoclose(true) {

	FILE* fp = fopen(filename, "a");
	if ( !fp ){
		fprintf(stderr, "Failed to open logfile '%s' ! Fatal error!\n", filename);
		exit(1);
	}
}
FileDestination::FileDestination(FILE* fp)
	: _fp(fp)
	, _autoclose(false) {

	if ( !fp ){
		fprintf(stderr, "Failed to read fp! Fatal error!\n");
		exit(1);
	}
}

FileDestination::~FileDestination(){
	if ( _autoclose ){
		fclose(_fp);
	}
}
void FileDestination::write(const char* content, const char* decorated) const {
	fputs(decorated, _fp);
	fflush(_fp);
}

FIFODestination::FIFODestination(const char* filename)
	: _filename(NULL)
	, _fp(NULL) {

	_filename = strdup(filename);
	mkfifo(filename, 0600);

	FILE* fp = fopen(filename, "w");
	if ( !fp ){
		fprintf(stderr, "Failed to open logfile '%s' ! Fatal error!\n", filename);
		exit(1);
	}
}

FIFODestination::~FIFODestination(){
	fclose(_fp);
	unlink(_filename);
	free(_filename);
}
void FIFODestination::write(const char* content, const char* decorated) const {
	fputs(decorated, _fp);
	fflush(_fp);
}

SocketDestination::SocketDestination(int socket)
	: _socket(socket) {

}

SocketDestination::~SocketDestination(){
	close(_socket);
}

void SocketDestination::write(const char* content, const char* decorated) const {
	send(_socket, decorated, strlen(decorated), 0);
}

#ifdef HAVE_SYSLOG
SyslogDestination::SyslogDestination(){
	/* @todo only a single instance of syslog may be opened */
	openlog(PACKAGE, 0, LOG_DAEMON);
}
SyslogDestination::~SyslogDestination(){
	closelog();
}
void SyslogDestination::write(const char* content, const char* decorated) const {
	syslog(syslog_severity[severity], content);
}
#endif /* HAVE_SYSLOG */

UDSServer::UDSServer(const char* filename)
	: _filename(NULL)
	, _socket(-1) {

	_filename = strdup(filename);

	struct sockaddr_un address;
	socklen_t address_length;

	_socket = socket(PF_UNIX, SOCK_STREAM, 0);

	unlink(filename);
	address.sun_family = AF_UNIX;
	address_length = (socklen_t)sizeof(address.sun_family) +
		(socklen_t)sprintf(address.sun_path, "%s", filename);

	bind(_socket, (struct sockaddr *) &address, address_length);
	listen(_socket, 5);
}

UDSServer::~UDSServer(){
	unlink(_filename);
	free(_filename);
}

bool UDSServer::accept(struct timeval *timeout) const {
	fd_set rfds;
	FD_ZERO(&rfds);
	FD_SET(_socket, &rfds);

	if ( select(_socket+1, &rfds, NULL, NULL, timeout) <= 0 ){
		return false;
	}

	int client = ::accept(_socket, NULL, NULL);
	Log::add_destination(new SocketDestination(client));

	return true;
}

namespace Log {

	static char *timestring(char *buffer, int bufferlen);
	static const char* severity_string(Severity severity);

	void initialize(){

	}

	void cleanup(){
		for ( iterator it = destinations.begin(); it != destinations.end(); ++it ){
			delete it->first;
		}
		destinations.clear();
	}

	void add_destination(Destination* dst, Severity severity){
		destinations.push_back(std::pair<Destination*, Severity>(dst, severity));
	}

	void message(Severity severity, const char* fmt, ...){
		va_list ap;
		va_start(ap, fmt);
		vmessage(severity, fmt, ap);
		va_end(ap);
	}

	void vmessage(Severity severity, const char* fmt, va_list ap){
		static char buf[255]; /* this isn't thread-safe anyway, might as well make it static */
		char* tmp;

		vasprintf(&tmp, fmt, ap);
		Ptr<char> content(tmp);

		asprintf(&tmp, "(%s) [%s] %s", severity_string(severity), timestring(buf, 255), content.get());
		Ptr<char> decorated(tmp);

		for ( iterator it = destinations.begin(); it != destinations.end(); ++it ){
			if ( severity < it->second ) continue;
			Destination* dst = it->first;
			dst->write(content.get(), decorated.get());
		}
	}

	char* timestring(char *buffer, int bufferlen) {
		time_t t = time(NULL);
		struct tm* nt;
#ifdef WIN32
		nt = new struct tm;
		localtime_s(nt, &t);
#else
		nt = localtime(&t);
#endif
		strftime(buffer, bufferlen, "%Y-%m-%d %H:%M:%S", nt);
#ifdef WIN32
		delete nt;
#endif
		return buffer;
	}

	const char* severity_string(Severity severity){
		switch ( severity ){
		case Log_Debug: return "DD";
		case Log_Verbose: return "--";
		case Log_Info: return "  ";
		case Log_Warning: return "WW";
		case Log_Fatal: return "!!";
		}
		return NULL;
	}

	void debug(const char* fmt, ...){
		va_list ap;
		va_start(ap, fmt);
		vmessage(Log_Debug, fmt, ap);
		va_end(ap);
	}

	void verbose(const char* fmt, ...){
		va_list ap;
		va_start(ap, fmt);
		vmessage(Log_Verbose, fmt, ap);
		va_end(ap);

	}

	void info(const char* fmt, ...){
		va_list ap;
		va_start(ap, fmt);
		vmessage(Log_Info, fmt, ap);
		va_end(ap);

	}

	void warning(const char* fmt, ...){
		va_list ap;
		va_start(ap, fmt);
		vmessage(Log_Warning, fmt, ap);
		va_end(ap);

	}

	void fatal(const char* fmt, ...){
		va_list ap;
		va_start(ap, fmt);
		vmessage(Log_Fatal, fmt, ap);
		va_end(ap);

	}

}

extern "C" void log_message(enum Severity severity, const char* fmt, ...){
	va_list ap;
	va_start(ap, fmt);
	log_vmessage(severity, fmt, ap);
	va_end(ap);
}

extern "C" void log_vmessage(enum Severity severity, const char* fmt, va_list ap){
	Log::vmessage(severity, fmt, ap);
}
<commit_msg>daemon: use a delegating constructor<commit_after>/**
 * This file is part of Slideshow.
 * Copyright (C) 2008-2012 David Sveningsson <ext@sidvind.com>
 *
 * Slideshow is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * Slideshow is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Slideshow.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifdef HAVE_CONFIG_H
#	include "config.h"
#endif

#include "log.hpp"
#include "ptr.h"
#include "exception.h"
#include <stdarg.h>
#include <cstdlib>
#include <cstring>
#include <memory> /* for auto_ptr */
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <portable/asprintf.h>
#include <portable/file.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#ifdef WIN32
#	include "win32.h"
#endif

#ifdef HAVE_SYSLOG
#	include <syslog.h>
int syslog_severity[5] = {
	LOG_DEBUG,
	LOG_INFO,
	LOG_NOTICE,
	LOG_WARNING,
	LOG_ERR
};
#endif /* HAVE_SYSLOG */

typedef std::vector<std::pair<Destination*, Severity>> vector;
typedef vector::iterator iterator;

static vector destinations;

FileDestination::FileDestination(const char* filename)
	: FileDestination(fopen(filename, "a")){

}

FileDestination::FileDestination(FILE* fp)
	: _fp(fp)
	, _autoclose(false) {

	if ( !fp ){
		fprintf(stderr, "Failed to read fp! Fatal error!\n");
		exit(1);
	}
}

FileDestination::~FileDestination(){
	if ( _autoclose ){
		fclose(_fp);
	}
}
void FileDestination::write(const char* content, const char* decorated) const {
	fputs(decorated, _fp);
	fflush(_fp);
}

FIFODestination::FIFODestination(const char* filename)
	: _filename(NULL)
	, _fp(NULL) {

	_filename = strdup(filename);
	mkfifo(filename, 0600);

	FILE* fp = fopen(filename, "w");
	if ( !fp ){
		fprintf(stderr, "Failed to open logfile '%s' ! Fatal error!\n", filename);
		exit(1);
	}
}

FIFODestination::~FIFODestination(){
	fclose(_fp);
	unlink(_filename);
	free(_filename);
}
void FIFODestination::write(const char* content, const char* decorated) const {
	fputs(decorated, _fp);
	fflush(_fp);
}

SocketDestination::SocketDestination(int socket)
	: _socket(socket) {

}

SocketDestination::~SocketDestination(){
	close(_socket);
}

void SocketDestination::write(const char* content, const char* decorated) const {
	send(_socket, decorated, strlen(decorated), 0);
}

#ifdef HAVE_SYSLOG
SyslogDestination::SyslogDestination(){
	/* @todo only a single instance of syslog may be opened */
	openlog(PACKAGE, 0, LOG_DAEMON);
}
SyslogDestination::~SyslogDestination(){
	closelog();
}
void SyslogDestination::write(const char* content, const char* decorated) const {
	syslog(syslog_severity[severity], content);
}
#endif /* HAVE_SYSLOG */

UDSServer::UDSServer(const char* filename)
	: _filename(NULL)
	, _socket(-1) {

	_filename = strdup(filename);

	struct sockaddr_un address;
	socklen_t address_length;

	_socket = socket(PF_UNIX, SOCK_STREAM, 0);

	unlink(filename);
	address.sun_family = AF_UNIX;
	address_length = (socklen_t)sizeof(address.sun_family) +
		(socklen_t)sprintf(address.sun_path, "%s", filename);

	bind(_socket, (struct sockaddr *) &address, address_length);
	listen(_socket, 5);
}

UDSServer::~UDSServer(){
	unlink(_filename);
	free(_filename);
}

bool UDSServer::accept(struct timeval *timeout) const {
	fd_set rfds;
	FD_ZERO(&rfds);
	FD_SET(_socket, &rfds);

	if ( select(_socket+1, &rfds, NULL, NULL, timeout) <= 0 ){
		return false;
	}

	int client = ::accept(_socket, NULL, NULL);
	Log::add_destination(new SocketDestination(client));

	return true;
}

namespace Log {

	static char *timestring(char *buffer, int bufferlen);
	static const char* severity_string(Severity severity);

	void initialize(){

	}

	void cleanup(){
		for ( iterator it = destinations.begin(); it != destinations.end(); ++it ){
			delete it->first;
		}
		destinations.clear();
	}

	void add_destination(Destination* dst, Severity severity){
		destinations.push_back(std::pair<Destination*, Severity>(dst, severity));
	}

	void message(Severity severity, const char* fmt, ...){
		va_list ap;
		va_start(ap, fmt);
		vmessage(severity, fmt, ap);
		va_end(ap);
	}

	void vmessage(Severity severity, const char* fmt, va_list ap){
		static char buf[255]; /* this isn't thread-safe anyway, might as well make it static */
		char* tmp;

		vasprintf(&tmp, fmt, ap);
		Ptr<char> content(tmp);

		asprintf(&tmp, "(%s) [%s] %s", severity_string(severity), timestring(buf, 255), content.get());
		Ptr<char> decorated(tmp);

		for ( iterator it = destinations.begin(); it != destinations.end(); ++it ){
			if ( severity < it->second ) continue;
			Destination* dst = it->first;
			dst->write(content.get(), decorated.get());
		}
	}

	char* timestring(char *buffer, int bufferlen) {
		time_t t = time(NULL);
		struct tm* nt;
#ifdef WIN32
		nt = new struct tm;
		localtime_s(nt, &t);
#else
		nt = localtime(&t);
#endif
		strftime(buffer, bufferlen, "%Y-%m-%d %H:%M:%S", nt);
#ifdef WIN32
		delete nt;
#endif
		return buffer;
	}

	const char* severity_string(Severity severity){
		switch ( severity ){
		case Log_Debug: return "DD";
		case Log_Verbose: return "--";
		case Log_Info: return "  ";
		case Log_Warning: return "WW";
		case Log_Fatal: return "!!";
		}
		return NULL;
	}

	void debug(const char* fmt, ...){
		va_list ap;
		va_start(ap, fmt);
		vmessage(Log_Debug, fmt, ap);
		va_end(ap);
	}

	void verbose(const char* fmt, ...){
		va_list ap;
		va_start(ap, fmt);
		vmessage(Log_Verbose, fmt, ap);
		va_end(ap);

	}

	void info(const char* fmt, ...){
		va_list ap;
		va_start(ap, fmt);
		vmessage(Log_Info, fmt, ap);
		va_end(ap);

	}

	void warning(const char* fmt, ...){
		va_list ap;
		va_start(ap, fmt);
		vmessage(Log_Warning, fmt, ap);
		va_end(ap);

	}

	void fatal(const char* fmt, ...){
		va_list ap;
		va_start(ap, fmt);
		vmessage(Log_Fatal, fmt, ap);
		va_end(ap);

	}

}

extern "C" void log_message(enum Severity severity, const char* fmt, ...){
	va_list ap;
	va_start(ap, fmt);
	log_vmessage(severity, fmt, ap);
	va_end(ap);
}

extern "C" void log_vmessage(enum Severity severity, const char* fmt, va_list ap){
	Log::vmessage(severity, fmt, ap);
}
<|endoftext|>


<commit_before>/*
 *  Project:    CommonLib
 *
 *  Version:    1.0.0
 *  History:    V1.0    07/12/2013  SP - created
 *
 *  Copyright (C) 2013 Stefan Paproth <pappi-@gmx.de>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program. If not, see <http://www.gnu.org/licenses/agpl.txt>.
 *
 */
#include "log.h"

/*
#define DEFAULT                  "\e[39m"
#define BLACK                    "\e[30m"
#define RED                      "\e[31m"
#define GREEN                    "\e[32m"
#define YELLOW                   "\e[33m"
#define BLUE                     "\e[34m"
#define MAGENTA                  "\e[35m"
#define CYAN                     "\e[36m"
#define LIGHT_GRAY               "\e[37m"
#define DARK_GRAY                "\e[90m"
#define LIGHT_RED                "\e[91m"
#define LIGHT_GREEN              "\e[92m"
#define LIGHT_YELLOW             "\e[93m"
#define LIGHT_BLUE               "\e[94m"
#define LIGHT_MAGENTA            "\e[95m"
#define LIGHT_CYAN               "\e[96m"
#define WHITE                    "\e[97m"

#define BOLD_BRIGHT "\e[1m"
#define DIM         "\e[2m"
#define UNDERLINED  "\e[4m"
#define BLINK       "\e[5m"
#define REVERSE     "\e[7m"
#define HIDDEN      "\e[8m"

#define RESET_ALL        "\e[0m"
#define RESET_BOLD       "\e[21m"
#define RESET_DIM        "\e[22m"
#define RESET_UNDERLINDE "\e[24m"
#define RESET_BLINK      "\e[25m"
#define RESET_REVERSE    "\e[27m"
#define RESET_HIDDEN     "\e[28m"
*/

namespace tlog {
    CLogEntry::~CLogEntry() {
        log_.write(buffer.str(), this->szFile_, this->iLine_, this->logLevel_ );
    }

    CLog& CLog::theLogger() {
        static CLog instance;
        return instance;
    }

    void CLog::write(
        const std::string &strLogText, const char *szFile,
        const int &iLine, const enuLogLevel &logLevel
    ) {
        struct timeb sTimeB;
        char buffer[25] = "";

        ftime(&sTimeB);

        strftime(buffer, 21, "%d.%m.%Y %H:%M:%S.", localtime(&sTimeB.time));

        std::cerr <<
            buffer << std::setw(3) << std::setfill('0') << sTimeB.millitm <<
            " " << std::setw(12) << std::setfill(' ') << szFile <<
            ":" << std::setw(4) << std::setfill('0') << iLine;

        switch(logLevel) {
            case Emerg:
                std::cerr << " Emerg.:  ";
                break;

            case Alert:
                std::cerr << " Alert:   ";
                break;

            case Error:
                std::cerr << " Error:   ";
                break;

            case Warning:
                std::cerr << " Warning: ";
                break;

            case Info:
                std::cerr << " Info:    ";
                break;

            case Notice:
                std::cerr << " Debug:   ";
                break;
        }
        std::cerr << strLogText << std::endl;
    }
}
<commit_msg>typo fixed<commit_after>/*
 *  Project:    CommonLib
 *
 *  Version:    1.0.0
 *  History:    V1.0    07/12/2013  SP - created
 *
 *  Copyright (C) 2013 Stefan Paproth <pappi-@gmx.de>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program. If not, see <http://www.gnu.org/licenses/agpl.txt>.
 *
 */
#include "log.h"

/*
#define DEFAULT                  "\e[39m"
#define BLACK                    "\e[30m"
#define RED                      "\e[31m"
#define GREEN                    "\e[32m"
#define YELLOW                   "\e[33m"
#define BLUE                     "\e[34m"
#define MAGENTA                  "\e[35m"
#define CYAN                     "\e[36m"
#define LIGHT_GRAY               "\e[37m"
#define DARK_GRAY                "\e[90m"
#define LIGHT_RED                "\e[91m"
#define LIGHT_GREEN              "\e[92m"
#define LIGHT_YELLOW             "\e[93m"
#define LIGHT_BLUE               "\e[94m"
#define LIGHT_MAGENTA            "\e[95m"
#define LIGHT_CYAN               "\e[96m"
#define WHITE                    "\e[97m"

#define BOLD_BRIGHT "\e[1m"
#define DIM         "\e[2m"
#define UNDERLINED  "\e[4m"
#define BLINK       "\e[5m"
#define REVERSE     "\e[7m"
#define HIDDEN      "\e[8m"

#define RESET_ALL        "\e[0m"
#define RESET_BOLD       "\e[21m"
#define RESET_DIM        "\e[22m"
#define RESET_UNDERLINDE "\e[24m"
#define RESET_BLINK      "\e[25m"
#define RESET_REVERSE    "\e[27m"
#define RESET_HIDDEN     "\e[28m"
*/

namespace tlog {
    CLogEntry::~CLogEntry() {
        log_.write(buffer.str(), this->szFile_, this->iLine_, this->logLevel_ );
    }

    CLog& CLog::theLogger() {
        static CLog instance;
        return instance;
    }

    void CLog::write(
        const std::string &strLogText, const char *szFile,
        const int &iLine, const enuLogLevel &logLevel
    ) {
        struct timeb sTimeB;
        char buffer[25] = "";

        ftime(&sTimeB);

        strftime(buffer, 21, "%d.%m.%Y %H:%M:%S.", localtime(&sTimeB.time));

        std::cerr <<
            buffer << std::setw(3) << std::setfill('0') << sTimeB.millitm <<
            " " << std::setw(12) << std::setfill(' ') << szFile <<
            ":" << std::setw(4) << std::setfill('0') << iLine;

        switch(logLevel) {
            case Emerg:
                std::cerr << " Emerg.:  ";
                break;

            case Alert:
                std::cerr << " Alert:   ";
                break;

            case Error:
                std::cerr << " Error:   ";
                break;

            case Warning:
                std::cerr << " Warning: ";
                break;

            case Info:
                std::cerr << " Info:    ";
                break;

            case Notice:
                std::cerr << " Notice:  ";
                break;
        }
        std::cerr << strLogText << std::endl;
    }
}
<|endoftext|>


<commit_before>/*
This file is part of the ORK library.
Full copyright and license terms can be found in the LICENSE.txt file.
*/
#include"ork/ork.hpp"
#define ORK_STL_INC_FILE <fstream>
#include"ork/core/stl_include.inl"
#define ORK_STL_INC_FILE <iostream>
#include"ork/core/stl_include.inl"
#define ORK_STL_INC_FILE <mutex>
#include"ork/core/stl_include.inl"
#define ORK_STL_INC_FILE <sstream>
#include"ork/core/stl_include.inl"

#include"ork/memory.hpp"

namespace ork {

const ork::string debug_trace(ORK("debug_trace"));
const ork::string output_data(ORK("output_data"));

const ork::string&to_string(const log_channel val) {
	switch(val) {
	case log_channel::debug_trace:
		return debug_trace;
	case log_channel::output_data:
		return output_data;
	};
	ORK_UNREACHABLE
}
log_channel string2log_channel(const ork::string&str) {
	if(str == output_data) {
		return log_channel::output_data;
	}
	if(str == output_data) {
		return log_channel::output_data;
	}
	ORK_THROW(ORK("Invalid log_channel: ") << str);
}

const ork::string trace(ORK("trace"));
const ork::string debug(ORK("debug"));
const ork::string info(ORK("info"));
const ork::string warning(ORK("warning"));
const ork::string error(ORK("error"));
const ork::string fatal(ORK("fatal"));

const ork::string&to_string(const severity_level val) {
	switch(val) {
	case severity_level::trace:
		return trace;
	case severity_level::debug:
		return debug;
	case severity_level::info:
		return info;
	case severity_level::warning:
		return warning;
	case severity_level::error:
		return error;
	case severity_level::fatal:
		return fatal;
	};
	ORK_UNREACHABLE
}
severity_level string2severity_level(const ork::string&str) {
	if(str == trace) {
		return severity_level::trace;
	}
	if(str == debug) {
		return severity_level::debug;
	}
	if(str == info) {
		return severity_level::info;
	}
	if(str == warning) {
		return severity_level::warning;
	}
	if(str == error) {
		return severity_level::error;
	}
	if(str == fatal) {
		return severity_level::fatal;
	}
	ORK_THROW(ORK("Invalid severity_level: ") << str);
}

//This is little more than a synchronous wrapper around an o_stream
class log_stream {
public:
	using stream_ptr = std::shared_ptr<o_stream>;
private:
	stream_ptr _stream;
	std::mutex _mutex;
public:
	explicit log_stream(stream_ptr stream_) : _stream{stream_}, _mutex{} {}
	~log_stream() {
		flush();
	}
	ORK_NON_COPYABLE(log_stream)
public:
	void log(const string&message) {
		std::lock_guard<std::mutex>lock(_mutex);
		*_stream << message << ORK('\n');
	}
	void flush() {
		_stream->flush();
	}
};

class log_sink {
public:
	using stream_ptr = std::shared_ptr<log_stream>;
private:
	std::vector<stream_ptr>_streams = {};
	bool _auto_flush = false;
public:
	log_sink() {}
	log_sink(const bool auto_flush) : _auto_flush{auto_flush} {}
	ORK_NON_COPYABLE(log_sink)
public:
	void insert(const stream_ptr&ptr) {
		_streams.push_back(ptr);
	}
	void log(const string&message) {
		for(auto&stream : _streams) {
			stream->log(message);
			if(_auto_flush) {
				stream->flush();
			}
		}
	}
	void set_auto_flush(const bool auto_flush) {
		_auto_flush = auto_flush;
	}
	void flush() {
		for(auto&stream : _streams) {
			stream->flush();
		}
	}
};

std::shared_ptr<log_stream>open_file_log_stream(const file::path&file_name) {
	if(!file::ensure_directory(file_name)) {
		ORK_THROW(ORK("Could not create directory : ") << file_name.ORK_GEN_STR())
	}
	of_stream* p_stream = new of_stream();
	p_stream->open(file_name);//std::ios::app | std::ios::ate
	if(p_stream->fail()) {
		ORK_THROW(ORK("Error opening log : ") << file_name)
	}
	//p_stream->rdbuf()->pubsetbuf(0, 0);//Less performance, more likely to catch error messages
	return std::shared_ptr<log_stream>(new log_stream(log_stream::stream_ptr(p_stream)));
}

//This is where our logging system falls short of a generic filter system; try to hide it somewhat in one place
class log_multiplexer {
private:
	using sink_ptr = std::unique_ptr<log_sink>;
private:
	std::vector<sink_ptr> _severity_sinks = {};
	log_sink _data_sink = {};
public:
	log_multiplexer(const file::path&root_directory){
		auto lout = log_sink::stream_ptr{new log_stream{log_stream::stream_ptr{&ORK_CLOG, singleton_deleter<o_stream>()}}};
		auto lerr = log_sink::stream_ptr{new log_stream{log_stream::stream_ptr{&ORK_CERR, singleton_deleter<o_stream>()}}};
		auto flog = open_file_log_stream(root_directory / ORK("trace.log"));
		auto fdata = open_file_log_stream(root_directory / ORK("output.log"));

		for(const auto sv : severity_levels) {
			sink_ptr sink{};
			if(sv < severity_level::error) {
				sink.reset(new log_sink{false});
				sink->insert(lout);
			}
			else {
				sink.reset(new log_sink{true});
				sink->insert(lerr);
			}
			sink->insert(flog);
			_severity_sinks.emplace_back(std::move(sink));
		}
		_data_sink.insert(lout);
		_data_sink.insert(fdata);
	}
	ORK_NON_COPYABLE(log_multiplexer)
public:
	void log(const log_channel channel, const severity_level severity, const o_string_stream&stream) {
		const string message = stream.str();
		switch(channel) {
		case log_channel::debug_trace:
			log_severity(severity, message);
			break;
		case log_channel::output_data:
			_data_sink.log(stream.str());
			break;
		default:
			ORK_UNREACHABLE
		};
	}
	void flush_all() {
		for(auto&sink : _severity_sinks) {
			sink->flush();
		}
		_data_sink.flush();
	}
private:
	void log_severity(const severity_level severity, const string&message) {
		const bool do_it = ORK_DEBUG || severity > severity_level::debug;
		if ORK_CONSTEXPR(do_it || true) {
			_severity_sinks[static_cast<size_t>(severity)]->log(message);
		}
	}
};

class message_guard {
private:
	ork::string _message = {};
	int _stage = 0;
	mutable std::mutex _mutex = {};
public:
	ORK_NON_COPYABLE(message_guard)
public:
	// This should be called to check if the message is ready to be cleared
	bool done() const {
		std::scoped_lock<std::mutex> lock(_mutex);
		return _stage > 0;
	}
	// This should be called once to complete the message
	void log(const o_string_stream&stream) {
		std::scoped_lock<std::mutex> lock(_mutex);
		if(_stage != 0) {
			ORK_THROW(ORK("Message pump called in wrong order"));
		}
		_message = stream.str();
		_stage = 1;
	}
	// This should be called once after completion
	std::string clear_message() {
		std::scoped_lock<std::mutex> lock(_mutex);
		if(_stage != 1) {
			ORK_THROW(ORK("Message pump called in wrong order"));
		}
		_stage = 2;
		return std::move(_message);
	}
};

struct log_scope::impl {
public:
	std::shared_ptr<log_multiplexer>multiplexer;
	log_channel channel;
	severity_level severity;
	o_string_stream stream;
public:
	impl(std::shared_ptr<log_multiplexer>&mp, const log_channel lc, const severity_level sv)
		: multiplexer{mp}
		, channel{lc}
		, severity{sv}
		, stream{}
	{}
	~impl() {
		multiplexer->log(channel, severity, stream);
	}
	ORK_MOVE_ONLY(impl)
};

log_scope::log_scope(std::unique_ptr<impl>&&ptr) : _pimpl{ std::move(ptr) } {}
log_scope::~log_scope() {}

#define LOG_STREAM_OPERATOR(TYPE) \
log_scope& log_scope::operator<< (const TYPE val) {\
	_pimpl->stream << val;\
	return *this;\
}
LOG_STREAM_OPERATOR(bool)
LOG_STREAM_OPERATOR(short)
LOG_STREAM_OPERATOR(unsigned short)
LOG_STREAM_OPERATOR(int)
LOG_STREAM_OPERATOR(unsigned)
LOG_STREAM_OPERATOR(long)
LOG_STREAM_OPERATOR(unsigned long)
LOG_STREAM_OPERATOR(long long)
LOG_STREAM_OPERATOR(unsigned long long)
LOG_STREAM_OPERATOR(float)
LOG_STREAM_OPERATOR(double)
LOG_STREAM_OPERATOR(long double)

#undef LOG_STREAM_OPERATOR
#define LOG_STREAM_OPERATOR(TYPE) \
log_scope& log_scope::operator<< (const TYPE val) {\
	_pimpl->stream << ORK_BYTE_2_STR(val);\
	return *this;\
}

LOG_STREAM_OPERATOR(char)
LOG_STREAM_OPERATOR(char*)
LOG_STREAM_OPERATOR(bstring&)

#undef LOG_STREAM_OPERATOR
#define LOG_STREAM_OPERATOR(TYPE) \
log_scope& log_scope::operator<< (const TYPE val) {\
	_pimpl->stream << ORK_WIDE_2_STR(val);\
	return *this;\
}

LOG_STREAM_OPERATOR(wchar_t)
LOG_STREAM_OPERATOR(wchar_t*)
LOG_STREAM_OPERATOR(wstring&)

log_scope& log_scope::operator<< (const void* val) {
	_pimpl->stream << val;
	return *this;
}
log_scope& log_scope::operator<< (const std::streambuf* sb) {
	_pimpl->stream << sb;
	return *this;
}
log_scope& log_scope::operator<< (std::ostream& (*pf)(std::ostream&)) {
	_pimpl->stream << pf;
	return *this;
}
log_scope& log_scope::operator<< (std::ios& (*pf)(std::ios&)) {
	_pimpl->stream << pf;
	return *this;
}
log_scope& log_scope::operator<< (std::ios_base& (*pf)(std::ios_base&)) {
	_pimpl->stream << pf;
	return *this;
}

const string&to_formatted_string(const severity_level sv) {
	static const std::array<const string, severity_levels.size()>strings = {{
		  ORK("TRACE")
		, ORK("DEBUG")
		, ORK("INFO ")
		, ORK("WARN ")
		, ORK("ERROR")
		, ORK("FATAL")
	}};
	return strings[static_cast<size_t>(sv)];
}

struct logger::impl {
public:
	file::path root_directory;
	std::shared_ptr<log_multiplexer>multiplexer;
public:
	impl(const file::path&directory)
		: root_directory(directory)
		, multiplexer{new log_multiplexer(directory)}
	{}
	void flush_all() {
		multiplexer->flush_all();
	}
};

logger::logger(const file::path&log_directory) : _pimpl(new impl(log_directory)) {}
logger::~logger() {}

const file::path& logger::root_directory() {
	return _pimpl->root_directory;
}

log_scope logger::get_log_scope(
	  const string&file_
	, const string&line_
	, const string&function_
	, const log_channel channel
	, const severity_level severity)
{
	const file::path fullpath(file_);
	string file(fullpath.filename().ORK_GEN_STR());
	file.resize(24, ORK(' '));

	string line(line_);
	line.resize(4, ORK(' '));

	string function(function_);
	function.resize(48, ORK(' '));

	std::unique_ptr<log_scope::impl> ls_impl(new log_scope::impl(_pimpl->multiplexer, channel, severity));
	log_scope scope(std::move(ls_impl));
	//Output formatted context first
	scope << ORK("[") << to_formatted_string(severity) << ORK("]:") << file << ORK("(") << line << ORK("):") << function << ORK("-- ");

	//Finally, return the stream to the client
	return std::move(scope);
}

void logger::flush_all() {
	_pimpl->flush_all();
}

logger*_g_log = nullptr;
int make_global_log(const string&directory) {
	static logger log(directory);
	_g_log = &log;
	return 0;
}
logger& get_global_log() {
	return *_g_log;
}

}//namespace ork
<commit_msg>Now using message guards to order messages<commit_after>/*
This file is part of the ORK library.
Full copyright and license terms can be found in the LICENSE.txt file.
*/
#include"ork/ork.hpp"
#define ORK_STL_INC_FILE <fstream>
#include"ork/core/stl_include.inl"
#define ORK_STL_INC_FILE <iostream>
#include"ork/core/stl_include.inl"
#define ORK_STL_INC_FILE <mutex>
#include"ork/core/stl_include.inl"
#define ORK_STL_INC_FILE <sstream>
#include"ork/core/stl_include.inl"

#include"ork/memory.hpp"

namespace ork {

const ork::string debug_trace(ORK("debug_trace"));
const ork::string output_data(ORK("output_data"));

const ork::string&to_string(const log_channel val) {
	switch(val) {
	case log_channel::debug_trace:
		return debug_trace;
	case log_channel::output_data:
		return output_data;
	};
	ORK_UNREACHABLE
}
log_channel string2log_channel(const ork::string&str) {
	if(str == output_data) {
		return log_channel::output_data;
	}
	if(str == output_data) {
		return log_channel::output_data;
	}
	ORK_THROW(ORK("Invalid log_channel: ") << str);
}

const ork::string trace(ORK("trace"));
const ork::string debug(ORK("debug"));
const ork::string info(ORK("info"));
const ork::string warning(ORK("warning"));
const ork::string error(ORK("error"));
const ork::string fatal(ORK("fatal"));

const ork::string&to_string(const severity_level val) {
	switch(val) {
	case severity_level::trace:
		return trace;
	case severity_level::debug:
		return debug;
	case severity_level::info:
		return info;
	case severity_level::warning:
		return warning;
	case severity_level::error:
		return error;
	case severity_level::fatal:
		return fatal;
	};
	ORK_UNREACHABLE
}
severity_level string2severity_level(const ork::string&str) {
	if(str == trace) {
		return severity_level::trace;
	}
	if(str == debug) {
		return severity_level::debug;
	}
	if(str == info) {
		return severity_level::info;
	}
	if(str == warning) {
		return severity_level::warning;
	}
	if(str == error) {
		return severity_level::error;
	}
	if(str == fatal) {
		return severity_level::fatal;
	}
	ORK_THROW(ORK("Invalid severity_level: ") << str);
}

//This is little more than a synchronous wrapper around an o_stream
class log_stream {
public:
	using stream_ptr = std::shared_ptr<o_stream>;
private:
	stream_ptr _stream;
	std::mutex _mutex;
public:
	explicit log_stream(stream_ptr stream_) : _stream{stream_}, _mutex{} {}
	~log_stream() {
		flush();
	}
	ORK_NON_COPYABLE(log_stream)
public:
	void log(const string&message) {
		std::lock_guard<std::mutex>lock(_mutex);
		*_stream << message << ORK('\n');
	}
	void flush() {
		_stream->flush();
	}
};

class log_sink {
public:
	using stream_ptr = std::shared_ptr<log_stream>;
private:
	std::vector<stream_ptr>_streams = {};
	bool _auto_flush = false;
public:
	log_sink() {}
	log_sink(const bool auto_flush) : _auto_flush{auto_flush} {}
	ORK_NON_COPYABLE(log_sink)
public:
	void insert(const stream_ptr&ptr) {
		_streams.push_back(ptr);
	}
	void log(const string&message) {
		for(auto&stream : _streams) {
			stream->log(message);
			if(_auto_flush) {
				stream->flush();
			}
		}
	}
	void set_auto_flush(const bool auto_flush) {
		_auto_flush = auto_flush;
	}
	void flush() {
		for(auto&stream : _streams) {
			stream->flush();
		}
	}
};

std::shared_ptr<log_stream>open_file_log_stream(const file::path&file_name) {
	if(!file::ensure_directory(file_name)) {
		ORK_THROW(ORK("Could not create directory : ") << file_name.ORK_GEN_STR())
	}
	of_stream* p_stream = new of_stream();
	p_stream->open(file_name);//std::ios::app | std::ios::ate
	if(p_stream->fail()) {
		ORK_THROW(ORK("Error opening log : ") << file_name)
	}
	//p_stream->rdbuf()->pubsetbuf(0, 0);//Less performance, more likely to catch error messages
	return std::shared_ptr<log_stream>(new log_stream(log_stream::stream_ptr(p_stream)));
}

class message_guard {
private:
	ork::string _message = {};
	int _stage = 0;
	mutable std::mutex _mutex = {};
	log_channel _channel;
	severity_level _severity;
public:
	message_guard(
		const log_channel lc,
		const severity_level sv)
		: _channel{lc}
		, _severity{sv} {}
	ORK_NON_COPYABLE(message_guard)
public:
	log_channel channel() const {
		return _channel;
	}
	severity_level severity() const {
		return _severity;
	}

	// This should be called to check if the message is ready to be cleared
	bool done() const {
		std::scoped_lock<std::mutex> lock(_mutex);
		return _stage > 0;
	}
	// This should be called once to complete the message
	void log(const o_string_stream&stream) {
		std::scoped_lock<std::mutex> lock(_mutex);
		if(_stage != 0) {
			ORK_THROW(ORK("Message pump called in wrong order"));
		}
		_message = stream.str();
		_stage = 1;
	}
	// This should be called once after completion
	std::string clear_message() {
		std::scoped_lock<std::mutex> lock(_mutex);
		if(_stage != 1) {
			ORK_THROW(ORK("Message pump called in wrong order"));
		}
		_stage = 2;
		return std::move(_message);
	}
};
using guard_ptr = std::shared_ptr<message_guard>;

//This is where our logging system falls short of a generic filter system; try to hide it somewhat in one place
class log_multiplexer {
private:
	using sink_ptr = std::unique_ptr<log_sink>;
private:
	std::vector<sink_ptr> _severity_sinks = {};
	log_sink _data_sink = {};
	std::vector<guard_ptr>_messages = {};
	size_t _message_index = 0;
	std::mutex _mutex = {};
public:
	log_multiplexer(const file::path&root_directory) {
		auto lout = log_sink::stream_ptr{new log_stream{log_stream::stream_ptr{&ORK_CLOG, singleton_deleter<o_stream>()}}};
		auto lerr = log_sink::stream_ptr{new log_stream{log_stream::stream_ptr{&ORK_CERR, singleton_deleter<o_stream>()}}};
		auto flog = open_file_log_stream(root_directory / ORK("trace.log"));
		auto fdata = open_file_log_stream(root_directory / ORK("output.log"));

		for(const auto sv : severity_levels) {
			sink_ptr sink{};
			if(sv < severity_level::error) {
				sink.reset(new log_sink{false});
				sink->insert(lout);
			}
			else {
				sink.reset(new log_sink{true});
				sink->insert(lerr);
			}
			sink->insert(flog);
			_severity_sinks.emplace_back(std::move(sink));
		}
		_data_sink.insert(lout);
		_data_sink.insert(fdata);
	}
	ORK_NON_COPYABLE(log_multiplexer)
public:
	guard_ptr get_message_guard(
		const log_channel lc,
		const severity_level sv
	) {
		std::scoped_lock<std::mutex> lock{_mutex};
		_messages.emplace_back(new message_guard{lc, sv});
		return _messages.back();
	}
	void on_scope_exit() {
		std::scoped_lock<std::mutex> lock{_mutex};
		while(_message_index < _messages.size() - 1 && _messages[_message_index]->done()) {
			log(*_messages[_message_index]);
			++_message_index;
		}
	}
	void flush_all() {
		std::scoped_lock<std::mutex> lock{_mutex};
		for(auto&sink : _severity_sinks) {
			sink->flush();
		}
		_data_sink.flush();
	}
private:
	void log(message_guard& message) {
		const string msg{message.clear_message()};
		switch(message.channel()) {
			case log_channel::debug_trace:
				log_severity(message.severity(), msg);
				break;
			case log_channel::output_data:
				_data_sink.log(msg);
				break;
			default:
				ORK_UNREACHABLE
		};
	}
	void log_severity(
		const severity_level severity,
		const string&message
	) {
		const bool do_it = ORK_DEBUG || severity > severity_level::debug;
		if ORK_CONSTEXPR(do_it || true) {
			_severity_sinks[static_cast<size_t>(severity)]->log(message);
		}
	}
};

struct log_scope::impl {
public:
	std::shared_ptr<message_guard>guard;
	std::shared_ptr<log_multiplexer>multiplexer;
	o_string_stream stream;
public:
	impl(
		const std::shared_ptr<message_guard>&mg,
		const std::shared_ptr<log_multiplexer>&mp
	)
		: guard{mg}
		, multiplexer{mp}
		, stream{}
	{}
	~impl() {
		guard->log(stream);
		multiplexer->on_scope_exit();
	}
	ORK_MOVE_ONLY(impl)
};

log_scope::log_scope(std::unique_ptr<impl>&&ptr) : _pimpl{ std::move(ptr) } {}
log_scope::~log_scope() {}

#define LOG_STREAM_OPERATOR(TYPE) \
log_scope& log_scope::operator<< (const TYPE val) {\
	_pimpl->stream << val;\
	return *this;\
}
LOG_STREAM_OPERATOR(bool)
LOG_STREAM_OPERATOR(short)
LOG_STREAM_OPERATOR(unsigned short)
LOG_STREAM_OPERATOR(int)
LOG_STREAM_OPERATOR(unsigned)
LOG_STREAM_OPERATOR(long)
LOG_STREAM_OPERATOR(unsigned long)
LOG_STREAM_OPERATOR(long long)
LOG_STREAM_OPERATOR(unsigned long long)
LOG_STREAM_OPERATOR(float)
LOG_STREAM_OPERATOR(double)
LOG_STREAM_OPERATOR(long double)

#undef LOG_STREAM_OPERATOR
#define LOG_STREAM_OPERATOR(TYPE) \
log_scope& log_scope::operator<< (const TYPE val) {\
	_pimpl->stream << ORK_BYTE_2_STR(val);\
	return *this;\
}

LOG_STREAM_OPERATOR(char)
LOG_STREAM_OPERATOR(char*)
LOG_STREAM_OPERATOR(bstring&)

#undef LOG_STREAM_OPERATOR
#define LOG_STREAM_OPERATOR(TYPE) \
log_scope& log_scope::operator<< (const TYPE val) {\
	_pimpl->stream << ORK_WIDE_2_STR(val);\
	return *this;\
}

LOG_STREAM_OPERATOR(wchar_t)
LOG_STREAM_OPERATOR(wchar_t*)
LOG_STREAM_OPERATOR(wstring&)

log_scope& log_scope::operator<< (const void* val) {
	_pimpl->stream << val;
	return *this;
}
log_scope& log_scope::operator<< (const std::streambuf* sb) {
	_pimpl->stream << sb;
	return *this;
}
log_scope& log_scope::operator<< (std::ostream& (*pf)(std::ostream&)) {
	_pimpl->stream << pf;
	return *this;
}
log_scope& log_scope::operator<< (std::ios& (*pf)(std::ios&)) {
	_pimpl->stream << pf;
	return *this;
}
log_scope& log_scope::operator<< (std::ios_base& (*pf)(std::ios_base&)) {
	_pimpl->stream << pf;
	return *this;
}

const string&to_formatted_string(const severity_level sv) {
	static const std::array<const string, severity_levels.size()>strings = {{
		  ORK("TRACE")
		, ORK("DEBUG")
		, ORK("INFO ")
		, ORK("WARN ")
		, ORK("ERROR")
		, ORK("FATAL")
	}};
	return strings[static_cast<size_t>(sv)];
}

struct logger::impl {
public:
	file::path root_directory;
	std::shared_ptr<log_multiplexer>multiplexer;
public:
	impl(const file::path&directory)
		: root_directory(directory)
		, multiplexer{new log_multiplexer(directory)}
	{}
	void flush_all() {
		multiplexer->flush_all();
	}
};

logger::logger(const file::path&log_directory) : _pimpl(new impl(log_directory)) {}
logger::~logger() {}

const file::path& logger::root_directory() {
	return _pimpl->root_directory;
}

log_scope logger::get_log_scope(
	  const string&file_
	, const string&line_
	, const string&function_
	, const log_channel channel
	, const severity_level severity)
{
	const file::path fullpath(file_);
	string file(fullpath.filename().ORK_GEN_STR());
	file.resize(24, ORK(' '));

	string line(line_);
	line.resize(4, ORK(' '));

	string function(function_);
	function.resize(48, ORK(' '));

	guard_ptr guard{_pimpl->multiplexer->get_message_guard(channel, severity)};
	std::unique_ptr<log_scope::impl> ls_impl(new log_scope::impl(guard, _pimpl->multiplexer));
	log_scope scope(std::move(ls_impl));
	//Output formatted context first
	scope << ORK("[") << to_formatted_string(severity) << ORK("]:") << file << ORK("(") << line << ORK("):") << function << ORK("-- ");

	//Finally, return the stream to the client
	return std::move(scope);
}

void logger::flush_all() {
	_pimpl->flush_all();
}

logger*_g_log = nullptr;
int make_global_log(const string&directory) {
	static logger log(directory);
	_g_log = &log;
	return 0;
}
logger& get_global_log() {
	return *_g_log;
}

}//namespace ork
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <cstdarg>
#include <uv.h>

#include "log.h"

using std::endl;
using std::ostream;
using std::ofstream;

class NullLogger : public Logger {
public:
  virtual Logger* prefix(const char *file, int line) override
  {
    return this;
  }

  virtual ostream& stream() override
  {
    return unopened;
  }

private:
  ofstream unopened;
};

class FileLogger : public Logger {
public:
  FileLogger(const char *filename) :
    logStream{filename, std::ios::out | std::ios::app}
  {
    prefix(__FILE__, __LINE__);
    logStream << "FileLogger opened." << endl;
  }

  virtual Logger* prefix(const char *file, int line) override
  {
    logStream << "[" << file << ":" << line << "] ";
    return this;
  }

  virtual ostream& stream() override
  {
    return logStream;
  }

private:
  ofstream logStream;
};

static uv_key_t current_logger_key;
static const NullLogger theNullLogger;
static uv_once_t make_key_once = UV_ONCE_INIT;

static void make_key()
{
  uv_key_create(&current_logger_key);
}

Logger* Logger::current()
{
  uv_once(&make_key_once, &make_key);

  Logger* logger = (Logger*) uv_key_get(&current_logger_key);

  if (logger == nullptr) {
    uv_key_set(&current_logger_key, (void*) &theNullLogger);
  }

  return logger;
}

static void replaceLogger(const Logger *newLogger)
{
  Logger *prior = Logger::current();
  if (prior != &theNullLogger) {
    delete prior;
  }

  uv_key_set(&current_logger_key, (void*) newLogger);
}

void Logger::toFile(const char *filename)
{
  replaceLogger(new FileLogger(filename));
}

void Logger::disable()
{
  replaceLogger(&theNullLogger);
}
<commit_msg>User-provided default constructor for NullLogger<commit_after>#include <iostream>
#include <fstream>
#include <cstdarg>
#include <uv.h>

#include "log.h"

using std::endl;
using std::ostream;
using std::ofstream;

class NullLogger : public Logger {
public:
  NullLogger()
  {
    //
  }

  virtual Logger* prefix(const char *file, int line) override
  {
    return this;
  }

  virtual ostream& stream() override
  {
    return unopened;
  }

private:
  ofstream unopened;
};

class FileLogger : public Logger {
public:
  FileLogger(const char *filename) :
    logStream{filename, std::ios::out | std::ios::app}
  {
    prefix(__FILE__, __LINE__);
    logStream << "FileLogger opened." << endl;
  }

  virtual Logger* prefix(const char *file, int line) override
  {
    logStream << "[" << file << ":" << line << "] ";
    return this;
  }

  virtual ostream& stream() override
  {
    return logStream;
  }

private:
  ofstream logStream;
};

static uv_key_t current_logger_key;
static const NullLogger theNullLogger;
static uv_once_t make_key_once = UV_ONCE_INIT;

static void make_key()
{
  uv_key_create(&current_logger_key);
}

Logger* Logger::current()
{
  uv_once(&make_key_once, &make_key);

  Logger* logger = (Logger*) uv_key_get(&current_logger_key);

  if (logger == nullptr) {
    uv_key_set(&current_logger_key, (void*) &theNullLogger);
  }

  return logger;
}

static void replaceLogger(const Logger *newLogger)
{
  Logger *prior = Logger::current();
  if (prior != &theNullLogger) {
    delete prior;
  }

  uv_key_set(&current_logger_key, (void*) newLogger);
}

void Logger::toFile(const char *filename)
{
  replaceLogger(new FileLogger(filename));
}

void Logger::disable()
{
  replaceLogger(&theNullLogger);
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

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

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

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

*/

#include "libtorrent/pch.hpp"

#include "libtorrent/lsd.hpp"
#include "libtorrent/io.hpp"
#include "libtorrent/http_tracker_connection.hpp"
#include "libtorrent/buffer.hpp"
#include "libtorrent/http_parser.hpp"

#include <boost/bind.hpp>
#include <boost/ref.hpp>
#if BOOST_VERSION < 103500
#include <asio/ip/host_name.hpp>
#include <asio/ip/multicast.hpp>
#else
#include <boost/asio/ip/host_name.hpp>
#include <boost/asio/ip/multicast.hpp>
#endif
#include <boost/thread/mutex.hpp>
#include <cstdlib>
#include <boost/config.hpp>

using boost::bind;
using namespace libtorrent;

namespace libtorrent
{
	// defined in broadcast_socket.cpp
	address guess_local_address(io_service&);
}

static error_code ec;

lsd::lsd(io_service& ios, address const& listen_interface
	, peer_callback_t const& cb)
	: m_callback(cb)
	, m_retry_count(1)
	, m_socket(ios, udp::endpoint(address_v4::from_string("239.192.152.143", ec), 6771)
		, bind(&lsd::on_announce, self(), _1, _2, _3))
	, m_broadcast_timer(ios)
	, m_disabled(false)
{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log.open("lsd.log", std::ios::in | std::ios::out | std::ios::trunc);
#endif
}

lsd::~lsd() {}

void lsd::announce(sha1_hash const& ih, int listen_port)
{
	if (m_disabled) return;

	std::stringstream btsearch;
	btsearch << "BT-SEARCH * HTTP/1.1\r\n"
		"Host: 239.192.152.143:6771\r\n"
		"Port: " << listen_port << "\r\n"
		"Infohash: " << ih << "\r\n"
		"\r\n\r\n";
	std::string const& msg = btsearch.str();

	m_retry_count = 1;
	error_code ec;
	m_socket.send(msg.c_str(), int(msg.size()), ec);
	if (ec)
	{
		m_disabled = true;
		return;
	}

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " ==> announce: ih: " << ih << " port: " << listen_port << std::endl;
#endif

	m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count), ec);
	m_broadcast_timer.async_wait(bind(&lsd::resend_announce, self(), _1, msg));
}

void lsd::resend_announce(error_code const& e, std::string msg)
{
	if (e) return;

	error_code ec;
	m_socket.send(msg.c_str(), int(msg.size()), ec);

	++m_retry_count;
	if (m_retry_count >= 5)
		return;

	m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count), ec);
	m_broadcast_timer.async_wait(bind(&lsd::resend_announce, self(), _1, msg));
}

void lsd::on_announce(udp::endpoint const& from, char* buffer
	, std::size_t bytes_transferred)
{
	using namespace libtorrent::detail;

	http_parser p;

	bool error = false;
	p.incoming(buffer::const_interval(buffer, buffer + bytes_transferred)
		, error);

	if (!p.header_finished() || error)
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: incomplete HTTP message\n";
#endif
		return;
	}

	if (p.method() != "bt-search")
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: invalid HTTP method: " << p.method() << std::endl;
#endif
		return;
	}

	std::string const& port_str = p.header("port");
	if (port_str.empty())
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: invalid BT-SEARCH, missing port" << std::endl;
#endif
		return;
	}

	std::string const& ih_str = p.header("infohash");
	if (ih_str.empty())
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: invalid BT-SEARCH, missing infohash" << std::endl;
#endif
		return;
	}

	sha1_hash ih(0);
	std::istringstream ih_sstr(ih_str);
	ih_sstr >> ih;
	int port = std::atoi(port_str.c_str());

	if (!ih.is_all_zeros() && port != 0)
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		m_log << time_now_string()
			<< " *** incoming local announce " << from.address()
			<< ":" << port << " ih: " << ih << std::endl;
#endif
		// we got an announce, pass it on through the callback
#ifndef BOOST_NO_EXCEPTIONS
		try {
#endif
			m_callback(tcp::endpoint(from.address(), port), ih);
#ifndef BOOST_NO_EXCEPTIONS
		}
		catch (std::exception&) {}
#endif
	}
}

void lsd::close()
{
	m_socket.close();
	error_code ec;
	m_broadcast_timer.cancel(ec);
	m_disabled = true;
	m_callback.clear();
}

<commit_msg>fixed locale dependence in lsd.cpp<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

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

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

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

*/

#include "libtorrent/pch.hpp"

#include "libtorrent/lsd.hpp"
#include "libtorrent/io.hpp"
#include "libtorrent/http_tracker_connection.hpp"
#include "libtorrent/buffer.hpp"
#include "libtorrent/http_parser.hpp"
#include "libtorrent/escape_string.hpp"

#include <boost/bind.hpp>
#include <boost/ref.hpp>
#if BOOST_VERSION < 103500
#include <asio/ip/host_name.hpp>
#include <asio/ip/multicast.hpp>
#else
#include <boost/asio/ip/host_name.hpp>
#include <boost/asio/ip/multicast.hpp>
#endif
#include <boost/thread/mutex.hpp>
#include <cstdlib>
#include <boost/config.hpp>

using boost::bind;
using namespace libtorrent;

namespace libtorrent
{
	// defined in broadcast_socket.cpp
	address guess_local_address(io_service&);
}

static error_code ec;

lsd::lsd(io_service& ios, address const& listen_interface
	, peer_callback_t const& cb)
	: m_callback(cb)
	, m_retry_count(1)
	, m_socket(ios, udp::endpoint(address_v4::from_string("239.192.152.143", ec), 6771)
		, bind(&lsd::on_announce, self(), _1, _2, _3))
	, m_broadcast_timer(ios)
	, m_disabled(false)
{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log.open("lsd.log", std::ios::in | std::ios::out | std::ios::trunc);
#endif
}

lsd::~lsd() {}

void lsd::announce(sha1_hash const& ih, int listen_port)
{
	if (m_disabled) return;

	std::stringstream btsearch;
	btsearch << "BT-SEARCH * HTTP/1.1\r\n"
		"Host: 239.192.152.143:6771\r\n"
		"Port: " << to_string(listen_port).elems << "\r\n"
		"Infohash: " << ih << "\r\n"
		"\r\n\r\n";
	std::string const& msg = btsearch.str();

	m_retry_count = 1;
	error_code ec;
	m_socket.send(msg.c_str(), int(msg.size()), ec);
	if (ec)
	{
		m_disabled = true;
		return;
	}

#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " ==> announce: ih: " << ih << " port: " << to_string(listen_port).elems << std::endl;
#endif

	m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count), ec);
	m_broadcast_timer.async_wait(bind(&lsd::resend_announce, self(), _1, msg));
}

void lsd::resend_announce(error_code const& e, std::string msg)
{
	if (e) return;

	error_code ec;
	m_socket.send(msg.c_str(), int(msg.size()), ec);

	++m_retry_count;
	if (m_retry_count >= 5)
		return;

	m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count), ec);
	m_broadcast_timer.async_wait(bind(&lsd::resend_announce, self(), _1, msg));
}

void lsd::on_announce(udp::endpoint const& from, char* buffer
	, std::size_t bytes_transferred)
{
	using namespace libtorrent::detail;

	http_parser p;

	bool error = false;
	p.incoming(buffer::const_interval(buffer, buffer + bytes_transferred)
		, error);

	if (!p.header_finished() || error)
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: incomplete HTTP message\n";
#endif
		return;
	}

	if (p.method() != "bt-search")
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: invalid HTTP method: " << p.method() << std::endl;
#endif
		return;
	}

	std::string const& port_str = p.header("port");
	if (port_str.empty())
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: invalid BT-SEARCH, missing port" << std::endl;
#endif
		return;
	}

	std::string const& ih_str = p.header("infohash");
	if (ih_str.empty())
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
	m_log << time_now_string()
		<< " <== announce: invalid BT-SEARCH, missing infohash" << std::endl;
#endif
		return;
	}

	sha1_hash ih(0);
	std::istringstream ih_sstr(ih_str);
	ih_sstr >> ih;
	int port = std::atoi(port_str.c_str());

	if (!ih.is_all_zeros() && port != 0)
	{
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
		m_log << time_now_string()
			<< " *** incoming local announce " << from.address()
			<< ":" << to_string(port).elems << " ih: " << ih << std::endl;
#endif
		// we got an announce, pass it on through the callback
#ifndef BOOST_NO_EXCEPTIONS
		try {
#endif
			m_callback(tcp::endpoint(from.address(), port), ih);
#ifndef BOOST_NO_EXCEPTIONS
		}
		catch (std::exception&) {}
#endif
	}
}

void lsd::close()
{
	m_socket.close();
	error_code ec;
	m_broadcast_timer.cancel(ec);
	m_disabled = true;
	m_callback.clear();
}

<|endoftext|>


<commit_before>#include "opencv2/video/tracking.hpp"
#include "opencv2/highgui/highgui.hpp"

#include <stdio.h>

using namespace cv;

static inline Point calcPoint(Point2f center, double R, double angle)
{
    return center + Point2f((float)cos(angle), (float)-sin(angle))*(float)R;
}

static void help()
{
    printf( "\nExamle of c calls to OpenCV's Kalman filter.\n"
"   Tracking of rotating point.\n"
"   Rotation speed is constant.\n"
"   Both state and measurements vectors are 1D (a point angle),\n"
"   Measurement is the real point angle + gaussian noise.\n"
"   The real and the estimated points are connected with yellow line segment,\n"
"   the real and the measured points are connected with red line segment.\n"
"   (if Kalman filter works correctly,\n"
"    the yellow segment should be shorter than the red one).\n"
            "\n"
"   Pressing any key (except ESC) will reset the tracking with a different speed.\n"
"   Pressing ESC will stop the program.\n"
            );
}

int main(int, char**)
{
    help();
    Mat img(500, 500, CV_8UC3);
    KalmanFilter KF(2, 1, 0);
    Mat state(2, 1, CV_32F); /* (phi, delta_phi) */
    Mat processNoise(2, 1, CV_32F);
    Mat measurement = Mat::zeros(1, 1, CV_32F);
    char code = (char)-1;

    for(;;)
    {
        randn( state, Scalar::all(0), Scalar::all(0.1) );
        KF.transitionMatrix = *(Mat_<float>(2, 2) << 1, 1, 0, 1);

        setIdentity(KF.measurementMatrix);
        setIdentity(KF.processNoiseCov, Scalar::all(1e-5));
        setIdentity(KF.measurementNoiseCov, Scalar::all(1e-1));
        setIdentity(KF.errorCovPost, Scalar::all(1));

        randn(KF.statePost, Scalar::all(0), Scalar::all(0.1));

        for(;;)
        {
            Point2f center(img.cols*0.5f, img.rows*0.5f);
            float R = img.cols/3.f;
            double stateAngle = state.at<float>(0);
            Point statePt = calcPoint(center, R, stateAngle);

            Mat prediction = KF.predict();
            double predictAngle = prediction.at<float>(0);
            Point predictPt = calcPoint(center, R, predictAngle);

            randn( measurement, Scalar::all(0), Scalar::all(KF.measurementNoiseCov.at<float>(0)));

            // generate measurement
            measurement += KF.measurementMatrix*state;

            double measAngle = measurement.at<float>(0);
            Point measPt = calcPoint(center, R, measAngle);

            // plot points
            #define drawCross( center, color, d )                                 \
                line( img, Point( center.x - d, center.y - d ),                \
                             Point( center.x + d, center.y + d ), color, 1, CV_AA, 0); \
                line( img, Point( center.x + d, center.y - d ),                \
                             Point( center.x - d, center.y + d ), color, 1, CV_AA, 0 )

            img = Scalar::all(0);
            drawCross( statePt, Scalar(255,255,255), 3 );
            drawCross( measPt, Scalar(0,0,255), 3 );
            drawCross( predictPt, Scalar(0,255,0), 3 );
            line( img, statePt, measPt, Scalar(0,0,255), 3, CV_AA, 0 );
            line( img, statePt, predictPt, Scalar(0,255,255), 3, CV_AA, 0 );

            if(theRNG().uniform(0,4) != 0)
                KF.correct(measurement);

            randn( processNoise, Scalar(0), Scalar::all(sqrt(KF.processNoiseCov.at<float>(0, 0))));
            state = KF.transitionMatrix*state + processNoise;

            imshow( "Kalman", img );
            code = (char)waitKey(100);

            if( code > 0 )
                break;
        }
        if( code == 27 || code == 'q' || code == 'Q' )
            break;
    }

    return 0;
}
<commit_msg>Fixed typo<commit_after>#include "opencv2/video/tracking.hpp"
#include "opencv2/highgui/highgui.hpp"

#include <stdio.h>

using namespace cv;

static inline Point calcPoint(Point2f center, double R, double angle)
{
    return center + Point2f((float)cos(angle), (float)-sin(angle))*(float)R;
}

static void help()
{
    printf( "\nExample of c calls to OpenCV's Kalman filter.\n"
"   Tracking of rotating point.\n"
"   Rotation speed is constant.\n"
"   Both state and measurements vectors are 1D (a point angle),\n"
"   Measurement is the real point angle + gaussian noise.\n"
"   The real and the estimated points are connected with yellow line segment,\n"
"   the real and the measured points are connected with red line segment.\n"
"   (if Kalman filter works correctly,\n"
"    the yellow segment should be shorter than the red one).\n"
            "\n"
"   Pressing any key (except ESC) will reset the tracking with a different speed.\n"
"   Pressing ESC will stop the program.\n"
            );
}

int main(int, char**)
{
    help();
    Mat img(500, 500, CV_8UC3);
    KalmanFilter KF(2, 1, 0);
    Mat state(2, 1, CV_32F); /* (phi, delta_phi) */
    Mat processNoise(2, 1, CV_32F);
    Mat measurement = Mat::zeros(1, 1, CV_32F);
    char code = (char)-1;

    for(;;)
    {
        randn( state, Scalar::all(0), Scalar::all(0.1) );
        KF.transitionMatrix = *(Mat_<float>(2, 2) << 1, 1, 0, 1);

        setIdentity(KF.measurementMatrix);
        setIdentity(KF.processNoiseCov, Scalar::all(1e-5));
        setIdentity(KF.measurementNoiseCov, Scalar::all(1e-1));
        setIdentity(KF.errorCovPost, Scalar::all(1));

        randn(KF.statePost, Scalar::all(0), Scalar::all(0.1));

        for(;;)
        {
            Point2f center(img.cols*0.5f, img.rows*0.5f);
            float R = img.cols/3.f;
            double stateAngle = state.at<float>(0);
            Point statePt = calcPoint(center, R, stateAngle);

            Mat prediction = KF.predict();
            double predictAngle = prediction.at<float>(0);
            Point predictPt = calcPoint(center, R, predictAngle);

            randn( measurement, Scalar::all(0), Scalar::all(KF.measurementNoiseCov.at<float>(0)));

            // generate measurement
            measurement += KF.measurementMatrix*state;

            double measAngle = measurement.at<float>(0);
            Point measPt = calcPoint(center, R, measAngle);

            // plot points
            #define drawCross( center, color, d )                                 \
                line( img, Point( center.x - d, center.y - d ),                \
                             Point( center.x + d, center.y + d ), color, 1, CV_AA, 0); \
                line( img, Point( center.x + d, center.y - d ),                \
                             Point( center.x - d, center.y + d ), color, 1, CV_AA, 0 )

            img = Scalar::all(0);
            drawCross( statePt, Scalar(255,255,255), 3 );
            drawCross( measPt, Scalar(0,0,255), 3 );
            drawCross( predictPt, Scalar(0,255,0), 3 );
            line( img, statePt, measPt, Scalar(0,0,255), 3, CV_AA, 0 );
            line( img, statePt, predictPt, Scalar(0,255,255), 3, CV_AA, 0 );

            if(theRNG().uniform(0,4) != 0)
                KF.correct(measurement);

            randn( processNoise, Scalar(0), Scalar::all(sqrt(KF.processNoiseCov.at<float>(0, 0))));
            state = KF.transitionMatrix*state + processNoise;

            imshow( "Kalman", img );
            code = (char)waitKey(100);

            if( code > 0 )
                break;
        }
        if( code == 27 || code == 'q' || code == 'Q' )
            break;
    }

    return 0;
}
<|endoftext|>


<commit_before>
#include <ugdk/system/engine.h>
#include <ugdk/action/3D/camera.h>
#include <ugdk/input/events.h>
#include <ugdk/input/module.h>
#include <bulletworks/object.h>
#include <bulletworks/physicscene.h>
#include <bulletworks/manager.h>
#include <BtOgreGP.h>
#include <memory>

#include <OgreCamera.h>
#include <OgreEntity.h>
#include <OgreLogManager.h>
#include <OgreRoot.h>
#include <OgreViewport.h>
#include <OgreSceneManager.h>
#include <OgreRenderWindow.h>
#include <OgreConfigFile.h>
#include <OgreMeshManager.h>

#define AREA_RANGE 200.0

using std::unique_ptr;

bulletworks::PhysicScene *ourscene;

#define BIT(x) (1<<(x))
enum CollisionGroup {
    HEADS = BIT(6),
    WALLS = BIT(7),
    WAT2 = BIT(8),
    WAT3 = BIT(9),
    WAT4 = BIT(10)
};

bulletworks::Object* createOgreHead(const std::string& name, bool useBox=false) {
    Ogre::SceneManager *mSceneMgr = ourscene->manager();
    bulletworks::Object::PhysicsData headData;
    auto headEnt = mSceneMgr->createEntity(name, "Cube.mesh");
    auto meshShapeConv = BtOgre::StaticMeshToShapeConverter(headEnt);
    if (useBox)
        headData.shape = meshShapeConv.createBox();
    else
        headData.shape = meshShapeConv.createSphere();
    headData.mass = 80;
    headData.collision_group = CollisionGroup::HEADS;
    headData.collides_with = CollisionGroup::WALLS | CollisionGroup::HEADS;
    auto head = new bulletworks::Object(*ourscene, headEnt, headData);
    head->AddToScene(ourscene);
    head->body()->setDamping(.4, .4);
    return head;
}

bulletworks::Object* createWall(const std::string& name, const Ogre::Vector3& dir, double dist,
                                double width = AREA_RANGE, double height = AREA_RANGE) {
    Ogre::SceneManager *mSceneMgr = ourscene->manager();
    Ogre::Plane plane(dir, dist);

    Ogre::MeshManager::getSingleton().createPlane(
                name, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane, width, height,
                5, 5, true, 1, 5, 5, dir.perpendicular());

    const std::string wat = name + "Entity";
    Ogre::Entity* wallEnt = mSceneMgr->createEntity(wat, name);
    wallEnt->setMaterialName("Ogre/Tusks");

    bulletworks::Object::PhysicsData wallData;
    wallData.shape = new btStaticPlaneShape(btVector3(dir.x, dir.y, dir.z), dist);
    wallData.mass = 0;
    wallData.collision_group = CollisionGroup::WALLS;
    wallData.collides_with = CollisionGroup::HEADS;

    auto wall = new bulletworks::Object(*ourscene, wallEnt, wallData);
    wall->AddToScene(ourscene);
    wall->body()->setFriction(1.7);
    return wall;
}

int main(int argc, char* argv[]) {
    ugdk::system::Configuration config;
    config.base_path = "assets/";
    ugdk::system::Initialize(config);
    ourscene = new bulletworks::PhysicScene(btVector3(0, -10, 0));

    ourscene->physics_manager()->set_debug_draw_enabled(true);
    ourscene->ShowFrameStats();

    auto head1 = createOgreHead("Head");
    auto head2 = createOgreHead("Head2", true);
    head2->Translate(0, 0, 80);
    head2->body()->setAngularFactor(btVector3(0.0, 0.0, 0.0));

    ourscene->camera()->AttachTo(*head2);
    ourscene->camera()->SetParameters(Ogre::Vector3::ZERO, 5000);
    ourscene->camera()->SetDistance(10);

    createWall("ground", Ogre::Vector3::UNIT_Y, -(AREA_RANGE / 2));

    ourscene->AddTask(ugdk::system::Task(
    [head2](double dt) {
        auto& keyboard = ugdk::input::manager()->keyboard();
        Ogre::Vector3 move = Ogre::Vector3::ZERO;
        if (keyboard.IsDown(ugdk::input::Scancode::D))
            move.x += 1.0;
        else if (keyboard.IsDown(ugdk::input::Scancode::A))
            move.x += -1.0;
        if (keyboard.IsDown(ugdk::input::Scancode::W))
            move.z += -1.0;
        else if (keyboard.IsDown(ugdk::input::Scancode::S))
            move.z += 1.0;

        move.normalise();
        move = ourscene->camera()->actual_orientation() * move;
        move.y = 0.0;
        move.normalise();
        head2->Move( move * 20 );
    }
    ));

    ourscene->event_handler().AddListener<ugdk::input::KeyPressedEvent>(
        [head2] (const ugdk::input::KeyPressedEvent& ev) -> void {
            if (ev.scancode == ugdk::input::Scancode::ESCAPE)
                ourscene->Finish();
        });
    ourscene->event_handler().AddListener<ugdk::input::MouseMotionEvent>(
        [](const ugdk::input::MouseMotionEvent& ev) -> void {
            ourscene->camera()->Rotate(-ev.motion.x, -ev.motion.y);
        });

    ourscene->manager()->setAmbientLight(Ogre::ColourValue(.4, .4, .4));

    ugdk::system::PushScene(unique_ptr<ugdk::action::Scene>(ourscene));
    ugdk::system::Run();
    ugdk::system::Release();
    return 0;
}
<commit_msg>Following ugdk-3d's<commit_after>
#include <ugdk/system/engine.h>
#include <ugdk/action/3D/camera.h>
#include <ugdk/input/events.h>
#include <ugdk/input/module.h>
#include <bulletworks/object.h>
#include <bulletworks/physicscene.h>
#include <bulletworks/manager.h>
#include <bulletworks/component/physicsbody.h>
#include <BtOgreGP.h>
#include <memory>

#include <OgreCamera.h>
#include <OgreEntity.h>
#include <OgreLogManager.h>
#include <OgreRoot.h>
#include <OgreViewport.h>
#include <OgreSceneManager.h>
#include <OgreRenderWindow.h>
#include <OgreConfigFile.h>
#include <OgreMeshManager.h>

#define AREA_RANGE 200.0

using std::unique_ptr;
using std::shared_ptr;
using std::make_shared;
using bulletworks::component::PhysicsBody;
using bulletworks::component::Body;

bulletworks::PhysicScene *ourscene;

#define BIT(x) (1<<(x))
enum CollisionGroup {
    HEADS = BIT(6),
    WALLS = BIT(7),
    WAT2 = BIT(8),
    WAT3 = BIT(9),
    WAT4 = BIT(10)
};

bulletworks::Object* createOgreHead(const std::string& name, bool useBox=false) {
    Ogre::SceneManager *mSceneMgr = ourscene->manager();
    bulletworks::component::PhysicsBody::PhysicsData headData;
    auto headEnt = mSceneMgr->createEntity(name, "Cube.mesh");
    auto meshShapeConv = BtOgre::StaticMeshToShapeConverter(headEnt);
    if (useBox)
        headData.shape = meshShapeConv.createBox();
    else
        headData.shape = meshShapeConv.createSphere();
    headData.mass = 80;
    headData.collision_group = CollisionGroup::HEADS;
    headData.collides_with = CollisionGroup::WALLS | CollisionGroup::HEADS;
    auto head = new bulletworks::Object(*ourscene, headEnt);
    head->AddComponent(make_shared<PhysicsBody>(ourscene->physics_manager(), headData));
    head->AddToScene(ourscene);
    head->body()->setDamping(.4, .4);
    return head;
}

bulletworks::Object* createWall(const std::string& name, const Ogre::Vector3& dir, double dist,
                                double width = AREA_RANGE, double height = AREA_RANGE) {
    Ogre::SceneManager *mSceneMgr = ourscene->manager();
    Ogre::Plane plane(dir, dist);

    Ogre::MeshManager::getSingleton().createPlane(
                name, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane, width, height,
                5, 5, true, 1, 5, 5, dir.perpendicular());

    const std::string wat = name + "Entity";
    Ogre::Entity* wallEnt = mSceneMgr->createEntity(wat, name);
    wallEnt->setMaterialName("Ogre/Tusks");

    bulletworks::component::PhysicsBody::PhysicsData wallData;
    wallData.shape = new btStaticPlaneShape(btVector3(dir.x, dir.y, dir.z), dist);
    wallData.mass = 0;
    wallData.collision_group = CollisionGroup::WALLS;
    wallData.collides_with = CollisionGroup::HEADS;
    auto wall = new bulletworks::Object(*ourscene, wallEnt);
    wall->AddComponent(make_shared<PhysicsBody>(ourscene->physics_manager(), wallData));
    wall->AddToScene(ourscene);
    wall->body()->setFriction(1.7);
    return wall;
}

int main(int argc, char* argv[]) {
    ugdk::system::Configuration config;
    config.base_path = "assets/";
    ugdk::system::Initialize(config);
    ourscene = new bulletworks::PhysicScene(btVector3(0, -10, 0));

    ourscene->physics_manager().set_debug_draw_enabled(true);
    ourscene->ShowFrameStats();

    auto head1 = createOgreHead("Head");
    auto head2 = createOgreHead("Head2", true);
    auto body2 = head2->GetComponent<PhysicsBody>();
    body2->Translate(0, 0, 80);
    body2->set_angular_factor(0.0, 0.0, 0.0);

    ourscene->camera()->AttachTo(*head2);
    ourscene->camera()->SetParameters(Ogre::Vector3::ZERO, 5000);
    ourscene->camera()->SetDistance(10);

    createWall("ground", Ogre::Vector3::UNIT_Y, -(AREA_RANGE / 2));

    ourscene->AddTask(ugdk::system::Task(
    [body2](double dt) {
        auto& keyboard = ugdk::input::manager()->keyboard();
        Ogre::Vector3 move = Ogre::Vector3::ZERO;
        if (keyboard.IsDown(ugdk::input::Scancode::D))
            move.x += 1.0;
        else if (keyboard.IsDown(ugdk::input::Scancode::A))
            move.x += -1.0;
        if (keyboard.IsDown(ugdk::input::Scancode::W))
            move.z += -1.0;
        else if (keyboard.IsDown(ugdk::input::Scancode::S))
            move.z += 1.0;

        move.normalise();
        move = ourscene->camera()->actual_orientation() * move;
        move.y = 0.0;
        move.normalise();
        body2->bulletworks::component::Body::Move((move * 10));
    }
    ));

    ourscene->event_handler().AddListener<ugdk::input::KeyPressedEvent>(
        [head2] (const ugdk::input::KeyPressedEvent& ev) -> void {
            if (ev.scancode == ugdk::input::Scancode::ESCAPE)
                ourscene->Finish();
        });
    ourscene->event_handler().AddListener<ugdk::input::MouseMotionEvent>(
        [](const ugdk::input::MouseMotionEvent& ev) -> void {
            ourscene->camera()->Rotate(-ev.motion.x, -ev.motion.y);
        });

    ourscene->manager()->setAmbientLight(Ogre::ColourValue(.4, .4, .4));

    ugdk::system::PushScene(unique_ptr<ugdk::action::Scene>(ourscene));
    ugdk::system::Run();
    ugdk::system::Release();
    return 0;
}
<|endoftext|>