<commit_before>// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 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 "base58.h"
#include "init.h"
#include "main.h"
#include "net.h"
#include "netbase.h"
#include "rpcserver.h"
#include "util.h"
#ifdef ENABLE_WALLET
#include "wallet.h"
#include "walletdb.h"
#endif

#include <stdint.h>

#include <boost/assign/list_of.hpp>
#include "json/json_spirit_utils.h"
#include "json/json_spirit_value.h"

using namespace std;
using namespace boost;
using namespace boost::assign;
using namespace json_spirit;

Value getinfo(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getinfo\n"
            "Returns an object containing various state info.\n"
            "\nResult:\n"
            "{\n"
            "  \"version\": xxxxx,           (numeric) the server version\n"
            "  \"protocolversion\": xxxxx,   (numeric) the protocol version\n"
            "  \"walletversion\": xxxxx,     (numeric) the wallet version\n"
            "  \"balance\": xxxxxxx,         (numeric) the total bitcoin balance of the wallet\n"
            "  \"blocks\": xxxxxx,           (numeric) the current number of blocks processed in the server\n"
            "  \"timeoffset\": xxxxx,        (numeric) the time offset\n"
            "  \"connections\": xxxxx,       (numeric) the number of connections\n"
            "  \"proxy\": \"host:port\",     (string, optional) the proxy used by the server\n"
            "  \"difficulty\": xxxxxx,       (numeric) the current difficulty\n"
            "  \"testnet\": true|false,      (boolean) if the server is using testnet or not\n"
            "  \"keypoololdest\": xxxxxx,    (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
            "  \"keypoolsize\": xxxx,        (numeric) how many new keys are pre-generated\n"
            "  \"unlocked_until\": ttt,      (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
            "  \"paytxfee\": x.xxxx,         (numeric) the transaction fee set in btc/kb\n"
            "  \"relayfee\": x.xxxx,         (numeric) minimum relay fee for non-free transactions in btc/kb\n"
            "  \"errors\": \"...\"           (string) any error messages\n"
            "}\n"
            "\nExamples:\n"
            + HelpExampleCli("getinfo", "")
            + HelpExampleRpc("getinfo", "")
        );

    proxyType proxy;
    GetProxy(NET_IPV4, proxy);

    Object obj;
    obj.push_back(Pair("mastercoreversion",  (int)1091008));  // strip the initial '10' : for tagged release go to 10007, etc.
    obj.push_back(Pair("version",       (int)CLIENT_VERSION));
    obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
#ifdef ENABLE_WALLET
    if (pwalletMain) {
        obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
        obj.push_back(Pair("balance",       ValueFromAmount(pwalletMain->GetBalance())));
    }
#endif
    obj.push_back(Pair("blocks",        (int)chainActive.Height()));
    obj.push_back(Pair("timeoffset",    GetTimeOffset()));
    obj.push_back(Pair("connections",   (int)vNodes.size()));
    obj.push_back(Pair("proxy",         (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
    obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
    obj.push_back(Pair("testnet",       TestNet()));
#ifdef ENABLE_WALLET
    if (pwalletMain) {
        obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
        obj.push_back(Pair("keypoolsize",   (int)pwalletMain->GetKeyPoolSize()));
    }
    if (pwalletMain && pwalletMain->IsCrypted())
        obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
    obj.push_back(Pair("paytxfee",      ValueFromAmount(nTransactionFee)));
#endif
    obj.push_back(Pair("relayfee",      ValueFromAmount(CTransaction::nMinRelayTxFee)));
    obj.push_back(Pair("errors",        GetWarnings("statusbar")));
    return obj;
}

#ifdef ENABLE_WALLET
class DescribeAddressVisitor : public boost::static_visitor<Object>
{
public:
    Object operator()(const CNoDestination &dest) const { return Object(); }

    Object operator()(const CKeyID &keyID) const {
        Object obj;
        CPubKey vchPubKey;
        pwalletMain->GetPubKey(keyID, vchPubKey);
        obj.push_back(Pair("isscript", false));
        obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
        obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
        return obj;
    }

    Object operator()(const CScriptID &scriptID) const {
        Object obj;
        obj.push_back(Pair("isscript", true));
        CScript subscript;
        pwalletMain->GetCScript(scriptID, subscript);
        std::vector<CTxDestination> addresses;
        txnouttype whichType;
        int nRequired;
        ExtractDestinations(subscript, whichType, addresses, nRequired);
        obj.push_back(Pair("script", GetTxnOutputType(whichType)));
        obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
        Array a;
        BOOST_FOREACH(const CTxDestination& addr, addresses)
            a.push_back(CBitcoinAddress(addr).ToString());
        obj.push_back(Pair("addresses", a));
        if (whichType == TX_MULTISIG)
            obj.push_back(Pair("sigsrequired", nRequired));
        return obj;
    }
};
#endif

Value validateaddress(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw runtime_error(
            "validateaddress \"bitcoinaddress\"\n"
            "\nReturn information about the given bitcoin address.\n"
            "\nArguments:\n"
            "1. \"bitcoinaddress\"     (string, required) The bitcoin address to validate\n"
            "\nResult:\n"
            "{\n"
            "  \"isvalid\" : true|false,         (boolean) If the address is valid or not. If not, this is the only property returned.\n"
            "  \"address\" : \"bitcoinaddress\", (string) The bitcoin address validated\n"
            "  \"ismine\" : true|false,          (boolean) If the address is yours or not\n"
            "  \"isscript\" : true|false,        (boolean) If the key is a script\n"
            "  \"pubkey\" : \"publickeyhex\",    (string) The hex value of the raw public key\n"
            "  \"iscompressed\" : true|false,    (boolean) If the address is compressed\n"
            "  \"account\" : \"account\"         (string) The account associated with the address, \"\" is the default account\n"
            "}\n"
            "\nExamples:\n"
            + HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
            + HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
        );

    CBitcoinAddress address(params[0].get_str());
    bool isValid = address.IsValid();

    Object ret;
    ret.push_back(Pair("isvalid", isValid));
    if (isValid)
    {
        CTxDestination dest = address.Get();
        string currentAddress = address.ToString();
        ret.push_back(Pair("address", currentAddress));
#ifdef ENABLE_WALLET
        bool fMine = pwalletMain ? IsMine(*pwalletMain, dest) : false;
        ret.push_back(Pair("ismine", fMine));
        if (fMine) {
            Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
            ret.insert(ret.end(), detail.begin(), detail.end());
        }
        if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
            ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name));
#endif
    }
    return ret;
}

//
// Used by addmultisigaddress / createmultisig:
//
CScript _createmultisig_redeemScript(const Array& params)
{
    int nRequired = params[0].get_int();
    const Array& keys = params[1].get_array();

    // Gather public keys
    if (nRequired < 1)
        throw runtime_error("a multisignature address must require at least one key to redeem");
    if ((int)keys.size() < nRequired)
        throw runtime_error(
            strprintf("not enough keys supplied "
                      "(got %u keys, but need at least %d to redeem)", keys.size(), nRequired));
    std::vector<CPubKey> pubkeys;
    pubkeys.resize(keys.size());
    for (unsigned int i = 0; i < keys.size(); i++)
    {
        const std::string& ks = keys[i].get_str();
#ifdef ENABLE_WALLET
        // Case 1: Bitcoin address and we have full public key:
        CBitcoinAddress address(ks);
        if (pwalletMain && address.IsValid())
        {
            CKeyID keyID;
            if (!address.GetKeyID(keyID))
                throw runtime_error(
                    strprintf("%s does not refer to a key",ks));
            CPubKey vchPubKey;
            if (!pwalletMain->GetPubKey(keyID, vchPubKey))
                throw runtime_error(
                    strprintf("no full public key for address %s",ks));
            if (!vchPubKey.IsFullyValid())
                throw runtime_error(" Invalid public key: "+ks);
            pubkeys[i] = vchPubKey;
        }

        // Case 2: hex public key
        else
#endif
        if (IsHex(ks))
        {
            CPubKey vchPubKey(ParseHex(ks));
            if (!vchPubKey.IsFullyValid())
                throw runtime_error(" Invalid public key: "+ks);
            pubkeys[i] = vchPubKey;
        }
        else
        {
            throw runtime_error(" Invalid public key: "+ks);
        }
    }
    CScript result;
    result.SetMultisig(nRequired, pubkeys);

    if (result.size() > MAX_SCRIPT_ELEMENT_SIZE)
        throw runtime_error(
                strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE));

    return result;
}

Value createmultisig(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 2 || params.size() > 2)
    {
        string msg = "createmultisig nrequired [\"key\",...]\n"
            "\nCreates a multi-signature address with n signature of m keys required.\n"
            "It returns a json object with the address and redeemScript.\n"

            "\nArguments:\n"
            "1. nrequired      (numeric, required) The number of required signatures out of the n keys or addresses.\n"
            "2. \"keys\"       (string, required) A json array of keys which are bitcoin addresses or hex-encoded public keys\n"
            "     [\n"
            "       \"key\"    (string) bitcoin address or hex-encoded public key\n"
            "       ,...\n"
            "     ]\n"

            "\nResult:\n"
            "{\n"
            "  \"address\":\"multisigaddress\",  (string) The value of the new multisig address.\n"
            "  \"redeemScript\":\"script\"       (string) The string value of the hex-encoded redemption script.\n"
            "}\n"

            "\nExamples:\n"
            "\nCreate a multisig address from 2 addresses\n"
            + HelpExampleCli("createmultisig", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
            "\nAs a json rpc call\n"
            + HelpExampleRpc("createmultisig", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
        ;
        throw runtime_error(msg);
    }

    // Construct using pay-to-script-hash:
    CScript inner = _createmultisig_redeemScript(params);
    CScriptID innerID = inner.GetID();
    CBitcoinAddress address(innerID);

    Object result;
    result.push_back(Pair("address", address.ToString()));
    result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));

    return result;
}

Value verifymessage(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 3)
        throw runtime_error(
            "verifymessage \"bitcoinaddress\" \"signature\" \"message\"\n"
            "\nVerify a signed message\n"
            "\nArguments:\n"
            "1. \"bitcoinaddress\"  (string, required) The bitcoin address to use for the signature.\n"
            "2. \"signature\"       (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n"
            "3. \"message\"         (string, required) The message that was signed.\n"
            "\nResult:\n"
            "true|false   (boolean) If the signature is verified or not.\n"
            "\nExamples:\n"
            "\nUnlock the wallet for 30 seconds\n"
            + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
            "\nCreate the signature\n"
            + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"my message\"") +
            "\nVerify the signature\n"
            + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
            "\nAs json rpc\n"
            + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"signature\", \"my message\"")
        );

    string strAddress  = params[0].get_str();
    string strSign     = params[1].get_str();
    string strMessage  = params[2].get_str();

    CBitcoinAddress addr(strAddress);
    if (!addr.IsValid())
        throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");

    CKeyID keyID;
    if (!addr.GetKeyID(keyID))
        throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");

    bool fInvalid = false;
    vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);

    if (fInvalid)
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");

    CHashWriter ss(SER_GETHASH, 0);
    ss << strMessageMagic;
    ss << strMessage;

    CPubKey pubkey;
    if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))
        return false;

    return (pubkey.GetID() == keyID);
}
<commit_msg>version bump<commit_after>// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 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 "base58.h"
#include "init.h"
#include "main.h"
#include "net.h"
#include "netbase.h"
#include "rpcserver.h"
#include "util.h"
#ifdef ENABLE_WALLET
#include "wallet.h"
#include "walletdb.h"
#endif

#include <stdint.h>

#include <boost/assign/list_of.hpp>
#include "json/json_spirit_utils.h"
#include "json/json_spirit_value.h"

using namespace std;
using namespace boost;
using namespace boost::assign;
using namespace json_spirit;

Value getinfo(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 0)
        throw runtime_error(
            "getinfo\n"
            "Returns an object containing various state info.\n"
            "\nResult:\n"
            "{\n"
            "  \"version\": xxxxx,           (numeric) the server version\n"
            "  \"protocolversion\": xxxxx,   (numeric) the protocol version\n"
            "  \"walletversion\": xxxxx,     (numeric) the wallet version\n"
            "  \"balance\": xxxxxxx,         (numeric) the total bitcoin balance of the wallet\n"
            "  \"blocks\": xxxxxx,           (numeric) the current number of blocks processed in the server\n"
            "  \"timeoffset\": xxxxx,        (numeric) the time offset\n"
            "  \"connections\": xxxxx,       (numeric) the number of connections\n"
            "  \"proxy\": \"host:port\",     (string, optional) the proxy used by the server\n"
            "  \"difficulty\": xxxxxx,       (numeric) the current difficulty\n"
            "  \"testnet\": true|false,      (boolean) if the server is using testnet or not\n"
            "  \"keypoololdest\": xxxxxx,    (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
            "  \"keypoolsize\": xxxx,        (numeric) how many new keys are pre-generated\n"
            "  \"unlocked_until\": ttt,      (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
            "  \"paytxfee\": x.xxxx,         (numeric) the transaction fee set in btc/kb\n"
            "  \"relayfee\": x.xxxx,         (numeric) minimum relay fee for non-free transactions in btc/kb\n"
            "  \"errors\": \"...\"           (string) any error messages\n"
            "}\n"
            "\nExamples:\n"
            + HelpExampleCli("getinfo", "")
            + HelpExampleRpc("getinfo", "")
        );

    proxyType proxy;
    GetProxy(NET_IPV4, proxy);

    Object obj;
    obj.push_back(Pair("mastercoreversion",  (int)1101008));  // strip the initial '10' : for tagged release go to 10007, etc.
    obj.push_back(Pair("version",       (int)CLIENT_VERSION));
    obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
#ifdef ENABLE_WALLET
    if (pwalletMain) {
        obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
        obj.push_back(Pair("balance",       ValueFromAmount(pwalletMain->GetBalance())));
    }
#endif
    obj.push_back(Pair("blocks",        (int)chainActive.Height()));
    obj.push_back(Pair("timeoffset",    GetTimeOffset()));
    obj.push_back(Pair("connections",   (int)vNodes.size()));
    obj.push_back(Pair("proxy",         (proxy.first.IsValid() ? proxy.first.ToStringIPPort() : string())));
    obj.push_back(Pair("difficulty",    (double)GetDifficulty()));
    obj.push_back(Pair("testnet",       TestNet()));
#ifdef ENABLE_WALLET
    if (pwalletMain) {
        obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
        obj.push_back(Pair("keypoolsize",   (int)pwalletMain->GetKeyPoolSize()));
    }
    if (pwalletMain && pwalletMain->IsCrypted())
        obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
    obj.push_back(Pair("paytxfee",      ValueFromAmount(nTransactionFee)));
#endif
    obj.push_back(Pair("relayfee",      ValueFromAmount(CTransaction::nMinRelayTxFee)));
    obj.push_back(Pair("errors",        GetWarnings("statusbar")));
    return obj;
}

#ifdef ENABLE_WALLET
class DescribeAddressVisitor : public boost::static_visitor<Object>
{
public:
    Object operator()(const CNoDestination &dest) const { return Object(); }

    Object operator()(const CKeyID &keyID) const {
        Object obj;
        CPubKey vchPubKey;
        pwalletMain->GetPubKey(keyID, vchPubKey);
        obj.push_back(Pair("isscript", false));
        obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
        obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
        return obj;
    }

    Object operator()(const CScriptID &scriptID) const {
        Object obj;
        obj.push_back(Pair("isscript", true));
        CScript subscript;
        pwalletMain->GetCScript(scriptID, subscript);
        std::vector<CTxDestination> addresses;
        txnouttype whichType;
        int nRequired;
        ExtractDestinations(subscript, whichType, addresses, nRequired);
        obj.push_back(Pair("script", GetTxnOutputType(whichType)));
        obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
        Array a;
        BOOST_FOREACH(const CTxDestination& addr, addresses)
            a.push_back(CBitcoinAddress(addr).ToString());
        obj.push_back(Pair("addresses", a));
        if (whichType == TX_MULTISIG)
            obj.push_back(Pair("sigsrequired", nRequired));
        return obj;
    }
};
#endif

Value validateaddress(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 1)
        throw runtime_error(
            "validateaddress \"bitcoinaddress\"\n"
            "\nReturn information about the given bitcoin address.\n"
            "\nArguments:\n"
            "1. \"bitcoinaddress\"     (string, required) The bitcoin address to validate\n"
            "\nResult:\n"
            "{\n"
            "  \"isvalid\" : true|false,         (boolean) If the address is valid or not. If not, this is the only property returned.\n"
            "  \"address\" : \"bitcoinaddress\", (string) The bitcoin address validated\n"
            "  \"ismine\" : true|false,          (boolean) If the address is yours or not\n"
            "  \"isscript\" : true|false,        (boolean) If the key is a script\n"
            "  \"pubkey\" : \"publickeyhex\",    (string) The hex value of the raw public key\n"
            "  \"iscompressed\" : true|false,    (boolean) If the address is compressed\n"
            "  \"account\" : \"account\"         (string) The account associated with the address, \"\" is the default account\n"
            "}\n"
            "\nExamples:\n"
            + HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
            + HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
        );

    CBitcoinAddress address(params[0].get_str());
    bool isValid = address.IsValid();

    Object ret;
    ret.push_back(Pair("isvalid", isValid));
    if (isValid)
    {
        CTxDestination dest = address.Get();
        string currentAddress = address.ToString();
        ret.push_back(Pair("address", currentAddress));
#ifdef ENABLE_WALLET
        bool fMine = pwalletMain ? IsMine(*pwalletMain, dest) : false;
        ret.push_back(Pair("ismine", fMine));
        if (fMine) {
            Object detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
            ret.insert(ret.end(), detail.begin(), detail.end());
        }
        if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
            ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name));
#endif
    }
    return ret;
}

//
// Used by addmultisigaddress / createmultisig:
//
CScript _createmultisig_redeemScript(const Array& params)
{
    int nRequired = params[0].get_int();
    const Array& keys = params[1].get_array();

    // Gather public keys
    if (nRequired < 1)
        throw runtime_error("a multisignature address must require at least one key to redeem");
    if ((int)keys.size() < nRequired)
        throw runtime_error(
            strprintf("not enough keys supplied "
                      "(got %u keys, but need at least %d to redeem)", keys.size(), nRequired));
    std::vector<CPubKey> pubkeys;
    pubkeys.resize(keys.size());
    for (unsigned int i = 0; i < keys.size(); i++)
    {
        const std::string& ks = keys[i].get_str();
#ifdef ENABLE_WALLET
        // Case 1: Bitcoin address and we have full public key:
        CBitcoinAddress address(ks);
        if (pwalletMain && address.IsValid())
        {
            CKeyID keyID;
            if (!address.GetKeyID(keyID))
                throw runtime_error(
                    strprintf("%s does not refer to a key",ks));
            CPubKey vchPubKey;
            if (!pwalletMain->GetPubKey(keyID, vchPubKey))
                throw runtime_error(
                    strprintf("no full public key for address %s",ks));
            if (!vchPubKey.IsFullyValid())
                throw runtime_error(" Invalid public key: "+ks);
            pubkeys[i] = vchPubKey;
        }

        // Case 2: hex public key
        else
#endif
        if (IsHex(ks))
        {
            CPubKey vchPubKey(ParseHex(ks));
            if (!vchPubKey.IsFullyValid())
                throw runtime_error(" Invalid public key: "+ks);
            pubkeys[i] = vchPubKey;
        }
        else
        {
            throw runtime_error(" Invalid public key: "+ks);
        }
    }
    CScript result;
    result.SetMultisig(nRequired, pubkeys);

    if (result.size() > MAX_SCRIPT_ELEMENT_SIZE)
        throw runtime_error(
                strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE));

    return result;
}

Value createmultisig(const Array& params, bool fHelp)
{
    if (fHelp || params.size() < 2 || params.size() > 2)
    {
        string msg = "createmultisig nrequired [\"key\",...]\n"
            "\nCreates a multi-signature address with n signature of m keys required.\n"
            "It returns a json object with the address and redeemScript.\n"

            "\nArguments:\n"
            "1. nrequired      (numeric, required) The number of required signatures out of the n keys or addresses.\n"
            "2. \"keys\"       (string, required) A json array of keys which are bitcoin addresses or hex-encoded public keys\n"
            "     [\n"
            "       \"key\"    (string) bitcoin address or hex-encoded public key\n"
            "       ,...\n"
            "     ]\n"

            "\nResult:\n"
            "{\n"
            "  \"address\":\"multisigaddress\",  (string) The value of the new multisig address.\n"
            "  \"redeemScript\":\"script\"       (string) The string value of the hex-encoded redemption script.\n"
            "}\n"

            "\nExamples:\n"
            "\nCreate a multisig address from 2 addresses\n"
            + HelpExampleCli("createmultisig", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
            "\nAs a json rpc call\n"
            + HelpExampleRpc("createmultisig", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")
        ;
        throw runtime_error(msg);
    }

    // Construct using pay-to-script-hash:
    CScript inner = _createmultisig_redeemScript(params);
    CScriptID innerID = inner.GetID();
    CBitcoinAddress address(innerID);

    Object result;
    result.push_back(Pair("address", address.ToString()));
    result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));

    return result;
}

Value verifymessage(const Array& params, bool fHelp)
{
    if (fHelp || params.size() != 3)
        throw runtime_error(
            "verifymessage \"bitcoinaddress\" \"signature\" \"message\"\n"
            "\nVerify a signed message\n"
            "\nArguments:\n"
            "1. \"bitcoinaddress\"  (string, required) The bitcoin address to use for the signature.\n"
            "2. \"signature\"       (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n"
            "3. \"message\"         (string, required) The message that was signed.\n"
            "\nResult:\n"
            "true|false   (boolean) If the signature is verified or not.\n"
            "\nExamples:\n"
            "\nUnlock the wallet for 30 seconds\n"
            + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
            "\nCreate the signature\n"
            + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"my message\"") +
            "\nVerify the signature\n"
            + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
            "\nAs json rpc\n"
            + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"signature\", \"my message\"")
        );

    string strAddress  = params[0].get_str();
    string strSign     = params[1].get_str();
    string strMessage  = params[2].get_str();

    CBitcoinAddress addr(strAddress);
    if (!addr.IsValid())
        throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");

    CKeyID keyID;
    if (!addr.GetKeyID(keyID))
        throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");

    bool fInvalid = false;
    vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);

    if (fInvalid)
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");

    CHashWriter ss(SER_GETHASH, 0);
    ss << strMessageMagic;
    ss << strMessage;

    CPubKey pubkey;
    if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))
        return false;

    return (pubkey.GetID() == keyID);
}
<|endoftext|>


<commit_before>#include "array_view.hh"
#include "vector.hh"

namespace Kakoune
{

template<typename T>
struct MirroredArray : public ArrayView<T>
{
    MirroredArray(ArrayView<T> data, int size)
        : ArrayView<T>(data), size(size)
    {
        kak_assert(2 * size + 1 <= data.size());
    }

    T& operator[](int n) { return ArrayView<T>::operator[](n + size); }
    const T& operator[](int n) const { return ArrayView<T>::operator[](n + size); }
private:
    int size;
};

struct Snake{ int x, y, u, v; bool add; };

template<typename Iterator>
Snake find_end_snake_of_further_reaching_dpath(Iterator a, int N, Iterator b, int M,
                                               const MirroredArray<int>& V,
                                               const int D, const int k)
{
    int x; // our position along a

    const bool add = k == -D or (k != D and V[k-1] < V[k+1]);

    // if diagonal on the right goes further along x than diagonal on the left,
    // then we take a vertical edge from it to this diagonal, hence x = V[k+1]
    if (add)
        x = V[k+1];
    // else, we take an horizontal edge from our left diagonal,x = V[k-1]+1
    else
        x = V[k-1]+1;

    int y = x - k; // we are by construction on diagonal k, so our position along
                   // b (y) is x - k.

    int u = x, v = y;
    // follow end snake along diagonal k
    while (u < N and v < M and a[u] == b[v])
        ++u, ++v;

    return { x, y, u, v, add };
}

struct SnakeLen : Snake
{
    SnakeLen(Snake s, int d) : Snake(s), d(d) {}
    int d;
};

template<typename Iterator>
SnakeLen find_middle_snake(Iterator a, int N, Iterator b, int M,
                           ArrayView<int> data1, ArrayView<int> data2)
{
    const int delta = N - M;
    MirroredArray<int> V1{data1, N + M};
    MirroredArray<int> V2{data2, N + M};

    std::reverse_iterator<Iterator> ra{a + N}, rb{b + M};

    for (int D = 0; D <= (M + N + 1) / 2; ++D)
    {
        for (int k1 = -D; k1 <= D; k1 += 2)
        {
            auto p = find_end_snake_of_further_reaching_dpath(a, N, b, M, V1, D, k1);
            V1[k1] = p.u;

            const int k2 = -(k1 - delta);
            if ((delta % 2 != 0) and -(D-1) <= k2 and k2 <= (D-1))
            {
                if (V1[k1] + V2[k2] >= N)
                    return { p, 2 * D - 1 };// return last snake on forward path
            }
        }

        for (int k2 = -D; k2 <= D; k2 += 2)
        {
            auto p = find_end_snake_of_further_reaching_dpath(ra, N, rb, M, V2, D, k2);
            V2[k2] = p.u;

            const int k1 = -(k2 - delta);
            if ((delta % 2 == 0) and -D <= k1 and k1 <= D)
            {
                if (V1[k1] + V2[k2] >= N)
                    return { { N - p.u, M - p.v, N - p.x , M - p.y } , 2 * D };// return last snake on reverse path
            }
        }
    }

    kak_assert(false);
}

template<typename Iterator>
struct Diff
{
    bool add;
    Iterator begin;
    Iterator end;
};

template<typename Iterator>
void find_diff_rec(Iterator a, size_t N, Iterator b, size_t M,
                   ArrayView<int> data1, ArrayView<int> data2,
                   Vector<Diff<Iterator>>& diffs)
{
    if (N > 0 and M > 0)
    {
        auto middle_snake = find_middle_snake(a, N, b, M, data1, data2);
        if (middle_snake.d > 1)
        {
            find_diff_rec(a, middle_snake.x, b, middle_snake.y,
                          data1, data2, diffs);

            find_diff_rec(a + middle_snake.u, N - middle_snake.u,
                          b + middle_snake.v, M - middle_snake.v,
                          data1, data2, diffs);
        }
        else if (middle_snake.d == 1)
        {
            int diag = 0;
            while (a[diag] == b[diag])
                ++diag;

            if (middle_snake.add)
                diffs.push_back({true, b + middle_snake.y, b + middle_snake.y + 1});
            else
                diffs.push_back({false, a + middle_snake.x-1, a + middle_snake.x});
        }
    }
    else if (M > 0)
        diffs.push_back({true, b, b + M});
    else if (N > 0)
        diffs.push_back({false, a, a + N});
}

template<typename Iterator>
void compact_diffs(Vector<Diff<Iterator>>& diffs)
{
    if (diffs.size() < 2)
        return;

    auto out_it = diffs.begin();
    for (auto it = out_it + 1; it != diffs.end(); ++it)
    {
        if (it->add == out_it->add and it->begin == out_it->end)
            out_it->end = it->end;
        else if (++out_it != it)
            *out_it = *it;
    }
}

template<typename Iterator>
Vector<Diff<Iterator>> find_diff(Iterator a, size_t N, Iterator b, size_t M)
{
    Vector<int> data(4 * (N+M));
    Vector<Diff<Iterator>> diffs;
    const size_t max_D_size = 2 * (N + M) + 1;
    find_diff_rec(a, N, b, M,
                  {data.data(), max_D_size},
                  {data.data() + max_D_size, max_D_size},
                  diffs);

    // compact_diffs(diffs);

    return diffs;
}

}
<commit_msg>Fix diff implementation and change the Diff struct format<commit_after>#include "array_view.hh"
#include "vector.hh"

#include <functional>
#include <iterator>

namespace Kakoune
{

template<typename T>
struct MirroredArray : public ArrayView<T>
{
    MirroredArray(ArrayView<T> data, int size)
        : ArrayView<T>(data), size(size)
    {
        kak_assert(2 * size + 1 <= data.size());
    }

    T& operator[](int n) { return ArrayView<T>::operator[](n + size); }
    const T& operator[](int n) const { return ArrayView<T>::operator[](n + size); }
private:
    int size;
};

struct Snake{ int x, y, u, v; bool add; };

template<typename Iterator, typename Equal>
Snake find_end_snake_of_further_reaching_dpath(Iterator a, int N, Iterator b, int M,
                                               const MirroredArray<int>& V,
                                               const int D, const int k, Equal eq)
{
    int x; // our position along a

    const bool add = k == -D or (k != D and V[k-1] < V[k+1]);

    // if diagonal on the right goes further along x than diagonal on the left,
    // then we take a vertical edge from it to this diagonal, hence x = V[k+1]
    if (add)
        x = V[k+1];
    // else, we take an horizontal edge from our left diagonal,x = V[k-1]+1
    else
        x = V[k-1]+1;

    int y = x - k; // we are by construction on diagonal k, so our position along
                   // b (y) is x - k.

    int u = x, v = y;
    // follow end snake along diagonal k
    while (u < N and v < M and eq(a[u], b[v]))
        ++u, ++v;

    return { x, y, u, v, add };
}

struct SnakeLen : Snake
{
    SnakeLen(Snake s, int d) : Snake(s), d(d) {}
    int d;
};

template<typename Iterator, typename Equal>
SnakeLen find_middle_snake(Iterator a, int N, Iterator b, int M,
                           ArrayView<int> data1, ArrayView<int> data2,
                           Equal eq)
{
    const int delta = N - M;
    MirroredArray<int> V1{data1, N + M};
    MirroredArray<int> V2{data2, N + M};

    std::reverse_iterator<Iterator> ra{a + N}, rb{b + M};

    for (int D = 0; D <= (M + N + 1) / 2; ++D)
    {
        for (int k1 = -D; k1 <= D; k1 += 2)
        {
            auto p = find_end_snake_of_further_reaching_dpath(a, N, b, M, V1, D, k1, eq);
            V1[k1] = p.u;

            const int k2 = -(k1 - delta);
            if ((delta % 2 != 0) and -(D-1) <= k2 and k2 <= (D-1))
            {
                if (V1[k1] + V2[k2] >= N)
                    return { p, 2 * D - 1 };// return last snake on forward path
            }
        }

        for (int k2 = -D; k2 <= D; k2 += 2)
        {
            auto p = find_end_snake_of_further_reaching_dpath(ra, N, rb, M, V2, D, k2, eq);
            V2[k2] = p.u;

            const int k1 = -(k2 - delta);
            if ((delta % 2 == 0) and -D <= k1 and k1 <= D)
            {
                if (V1[k1] + V2[k2] >= N)
                    return { { N - p.u, M - p.v, N - p.x , M - p.y } , 2 * D };// return last snake on reverse path
            }
        }
    }

    kak_assert(false);
    return { {}, 0 };
}

struct Diff
{
    enum { Keep, Add, Remove } mode;
    int len;
    int posB;
};

template<typename Iterator, typename Equal>
void find_diff_rec(Iterator a, int offA, int lenA,
                   Iterator b, int offB, int lenB,
                   ArrayView<int> data1, ArrayView<int> data2,
                   Equal eq, Vector<Diff>& diffs)
{
    if (lenA > 0 and lenB > 0)
    {
        auto middle_snake = find_middle_snake(a + offA, lenA, b + offB, lenB, data1, data2, eq);
        if (middle_snake.d > 1)
        {
            find_diff_rec(a, offA, middle_snake.x,
                          b, offB, middle_snake.y,
                          data1, data2, eq, diffs);

            if (int len = middle_snake.u - middle_snake.x)
                diffs.push_back({Diff::Keep, len, 0});

            find_diff_rec(a, offA + middle_snake.u, lenA - middle_snake.u,
                          b, offB + middle_snake.v, lenB - middle_snake.v,
                          data1, data2, eq, diffs);
        }
        else if (middle_snake.d == 1)
        {
            int diag = 0;
            while (eq(a[offA + diag], b[offB + diag]))
                ++diag;

            if (diag != 0)
                diffs.push_back({Diff::Keep, diag, 0});

            if (middle_snake.add)
                diffs.push_back({Diff::Add, 1, offB + middle_snake.y-1});
            else
                diffs.push_back({Diff::Remove, 1, 0});
        }
    }
    else if (lenB > 0)
        diffs.push_back({Diff::Add, lenB, offB});
    else if (lenA > 0)
        diffs.push_back({Diff::Remove, lenA, 0});
}

inline void compact_diffs(Vector<Diff>& diffs)
{
    if (diffs.size() < 2)
        return;

    auto out_it = diffs.begin();
    for (auto it = out_it + 1; it != diffs.end(); ++it)
    {
        if (it->mode == out_it->mode and
            (it->mode != Diff::Add or
             it->posB == out_it->posB + out_it->len))
            out_it->len += it->len;
        else if (++out_it != it)
            *out_it = *it;
    }
    diffs.erase(out_it+1, diffs.end());
}

template<typename Iterator, typename Equal = std::equal_to<typename std::iterator_traits<Iterator>::value_type>>
Vector<Diff> find_diff(Iterator a, int N, Iterator b, int M,
                                 Equal eq = Equal{})
{
    const int max = 2 * (N + M) + 1;
    Vector<int> data(2*max);
    Vector<Diff> diffs;
    find_diff_rec(a, 0, N, b, 0, M,
                  {data.data(), (size_t)max}, {data.data() + max, (size_t)max},
                  eq, diffs);

    compact_diffs(diffs);

    return diffs;
}

}
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2018.  All rights reserved
 */
#ifndef _Stroika_Foundation_Execution_SharedStaticData_inl_
#define _Stroika_Foundation_Execution_SharedStaticData_inl_ 1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#include "../Debug/Assertions.h"
#include "Common.h"

namespace Stroika {
    namespace Foundation {
        namespace Execution {

            namespace Private_ {
                // hack to avoid #include of Thread.h for Thread::SuppressInterruptionInContext
                bool SharedStaticData_DTORHelper_ (
#if qStroika_Foundation_Execution_SpinLock_IsFasterThan_mutex
                    SpinLock* m,
#else
                    mutex* m,
#endif
                    unsigned int* cu);
            }

            /*
            ********************************************************************************
            ******************************** SharedStaticData<T> ***************************
            ********************************************************************************
            */
            template <typename T>
            T* SharedStaticData<T>::sOnceObj_;

            template <typename T>
#if qStroika_Foundation_Execution_SpinLock_IsFasterThan_mutex
            SpinLock SharedStaticData<T>::sMutex_;
#else
            mutex SharedStaticData<T>::sMutex_;
#endif

            template <typename T>
            unsigned int SharedStaticData<T>::sCountUses_ = 0;

            template <typename T>
            SharedStaticData<T>::SharedStaticData ()
            {
#if qCompilerAndStdLib_make_unique_lock_IsSlow
                MACRO_LOCK_GUARD_CONTEXT (sMutex_);
#else
                auto critSec{make_unique_lock (sMutex_)};
#endif
                ++sCountUses_;
                if (sCountUses_ == 1) {
                    sOnceObj_ = new T{};
                }
#if qDebug
                Stroika_Foundation_Debug_ValgrindDisableHelgrind (sCountUses_); // beacuse use in asserts - read there - safe/OK even without lock
                Stroika_Foundation_Debug_ValgrindDisableHelgrind (sOnceObj_);   // maybe not non-const get, but count on other later to provide interlock/checking
#endif
            }
            template <typename T>
            SharedStaticData<T>::~SharedStaticData ()
            {
                if (Private_::SharedStaticData_DTORHelper_ (&sMutex_, &sCountUses_)) {
                    Assert (sCountUses_ == 0);
                    delete sOnceObj_;
                    sOnceObj_ = nullptr;
                }
            }
            template <typename T>
            inline T& SharedStaticData<T>::Get ()
            {
                // no need to lock since no way to destroy value while 'this' object still exists
                Ensure (sCountUses_ >= 1);
                EnsureNotNull (sOnceObj_);
                return *sOnceObj_;
            }
            template <typename T>
            inline const T& SharedStaticData<T>::Get () const
            {
                // no need to lock since no way to destroy value while 'this' object still exists
                Ensure (sCountUses_ >= 1);
                EnsureNotNull (sOnceObj_);
                return *sOnceObj_;
            }
        }
    }
}
#endif /*_Stroika_Foundation_Execution_SharedStaticData_inl_*/
<commit_msg>silence another warning<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2018.  All rights reserved
 */
#ifndef _Stroika_Foundation_Execution_SharedStaticData_inl_
#define _Stroika_Foundation_Execution_SharedStaticData_inl_ 1

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#include "../Debug/Assertions.h"
#include "Common.h"

namespace Stroika {
    namespace Foundation {
        namespace Execution {

            DISABLE_COMPILER_GCC_WARNING_START ("GCC diagnostic ignored \"-Wdeprecated-declarations\"");
            namespace Private_ {
                // hack to avoid #include of Thread.h for Thread::SuppressInterruptionInContext
                bool SharedStaticData_DTORHelper_ (
#if qStroika_Foundation_Execution_SpinLock_IsFasterThan_mutex
                    SpinLock* m,
#else
                    mutex* m,
#endif
                    unsigned int* cu);
            }

            /*
            ********************************************************************************
            ******************************** SharedStaticData<T> ***************************
            ********************************************************************************
            */
            template <typename T>
            T* SharedStaticData<T>::sOnceObj_;

            template <typename T>
#if qStroika_Foundation_Execution_SpinLock_IsFasterThan_mutex
            SpinLock SharedStaticData<T>::sMutex_;
#else
            mutex SharedStaticData<T>::sMutex_;
#endif

            template <typename T>
            unsigned int SharedStaticData<T>::sCountUses_ = 0;

            template <typename T>
            SharedStaticData<T>::SharedStaticData ()
            {
#if qCompilerAndStdLib_make_unique_lock_IsSlow
                MACRO_LOCK_GUARD_CONTEXT (sMutex_);
#else
                auto critSec{make_unique_lock (sMutex_)};
#endif
                ++sCountUses_;
                if (sCountUses_ == 1) {
                    sOnceObj_ = new T{};
                }
#if qDebug
                Stroika_Foundation_Debug_ValgrindDisableHelgrind (sCountUses_); // beacuse use in asserts - read there - safe/OK even without lock
                Stroika_Foundation_Debug_ValgrindDisableHelgrind (sOnceObj_);   // maybe not non-const get, but count on other later to provide interlock/checking
#endif
            }
            template <typename T>
            SharedStaticData<T>::~SharedStaticData ()
            {
                if (Private_::SharedStaticData_DTORHelper_ (&sMutex_, &sCountUses_)) {
                    Assert (sCountUses_ == 0);
                    delete sOnceObj_;
                    sOnceObj_ = nullptr;
                }
            }
            template <typename T>
            inline T& SharedStaticData<T>::Get ()
            {
                // no need to lock since no way to destroy value while 'this' object still exists
                Ensure (sCountUses_ >= 1);
                EnsureNotNull (sOnceObj_);
                return *sOnceObj_;
            }
            template <typename T>
            inline const T& SharedStaticData<T>::Get () const
            {
                // no need to lock since no way to destroy value while 'this' object still exists
                Ensure (sCountUses_ >= 1);
                EnsureNotNull (sOnceObj_);
                return *sOnceObj_;
            }
            DISABLE_COMPILER_GCC_WARNING_END ("GCC diagnostic ignored \"-Wdeprecated-declarations\"");
        }
    }
}
#endif /*_Stroika_Foundation_Execution_SharedStaticData_inl_*/
<|endoftext|>


<commit_before>// (c) ZaKlaus 2016; Apache 2 Licensed, see LICENSE;;

#if !defined(DZM_H)

#define _CRT_SECURE_NO_WARNINGS

#include <stdint.h>
#include <stddef.h>
#include <limits.h>
#include <float.h>

#define __STDC_FORMAT_MACROS
#include <inttypes.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#if defined(__linux)
#include <readline/readline.h>
#include <readline/history.h>

static inline FILE *
read_input(FILE *Stream)
{

    char *Buffer = readline("");
    FILE *NewStream = Stream;

    if(Buffer[0] != 0)
    {
        add_history(Buffer);
        NewStream = fmemopen((void *)Buffer, strlen(Buffer), "r");
    }

    return(NewStream);
}
#else
static inline FILE *
read_input(FILE *Stream)
{
    return(Stream);
}
#endif

typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef int32 bool32;

typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;

typedef intptr_t intptr;
typedef uintptr_t uintptr;

typedef size_t memory_index;
typedef size_t mi;

typedef float real32;
typedef double real64;

typedef int8 s8;
typedef int8 s08;
typedef int16 s16;
typedef int32 s32;
typedef int64 s64;
typedef bool32 b32;

typedef uint8 u8;
typedef uint8 u08;
typedef uint16 u16;
typedef uint32 u32;
typedef uint64 u64;

typedef real32 r32;
typedef real64 r64;

typedef uintptr_t umm;

#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif

#if !defined(COMPILER_MSVC)
#define COMPILER_MSVC 0
#endif

#if !defined(COMPILER_LLVM)
#define COMPILER_LLVM 0
#endif

#include "../dzm_ver.hpp"

#define MAKE(Type, Value) make_object(Type, (void *)&Value)
#define MAKE1(Type, Value, Value1) make_object(Type, (void *)&Value, (void *)&Value1)
#define MAKE2(Type, Value, Value1, Value2) make_object(Type, (void *)&Value, (void *)&Value1, (void *)&Value2)
#define MAKE3(Type, Value, Value1, Value2, Value3) make_object(Type, (void *)&Value, (void *)&Value1, (void *)&Value2, (void *)&Value3)

#if defined(COMPILER_MSVC)
#define TRAP() *(int *)0 = 0
#elif defined(COMPILER_LLVM) || defined(__APPLE__)
#define TRAP() __builtin_trap()
#else
#define TRAP() volatile *(int *)0 = 0
#endif

#define IGNORE(x) x

#ifdef DZM_SLOW
#define zassert(Expression) if(!(Expression)) {TRAP();}
#else
#define zassert(Expression)
#endif

#define InvalidCodePath zassert(!"InvalidCodePath")
#define InvalidDefaultCase default: {InvalidCodePath;} break
#define Unreachable(Statement) return(Statement)

#define Kilobytes(Value) ((Value)*1024LL)
#define Megabytes(Value) (Kilobytes(Value)*1024LL)
#define Gigabytes(Value) (Megabytes(Value)*1024LL)
#define Terabytes(Value) (Gigabytes(Value)*1024LL)

#define AlignPow2(Value, Alignment) ((Value + ((Alignment) - 1)) & ~((Alignment) - 1))
#define Align4(Value) ((Value + 3) & ~3)
#define Align8(Value) ((Value + 7) & ~7)
#define Align16(Value) ((Value + 15) & ~15)

#define STRINGIFY(X) #X
#define CONCAT(X,Y) X##Y
#define SQUOTE(X, I, C) char __s_quote__I; sprintf(__s_quote__I, "'%s'", X); C =
#define UL_ (u8 *)
#define L_  (s8 *)

#define MAX_VM_SIZE     4096 * 1024 * 32

static inline void
zero_size(memory_index Size, void *Ptr)
{
    uint8 *Byte = (uint8 *)Ptr;
    while(Size--)
    {
        *Byte++ = 0;
    }
}

#define ArrayCount(Array) (sizeof(Array) / sizeof((Array)[0]))

#ifdef DZM_ELEVATED
#undef _ELEVATED
#define _ELEVATED 1
#else
#undef _ELEVATED
#define _ELEVATED 0
#endif

// == Memory Manager
#include "dzm_mem.hpp"

// == Util
#include "dzm_utl.hpp"
#include "dzm_log.hpp"

// == Interpreter
#include "lang/dzm_mdl.hpp"
#include "lang/dzm_lex.hpp"
#include "lang/dzm_evl.hpp"
#include "lang/dzm_prt.hpp"
#include "lang/dzm_rep.hpp"

#define DZM_H
#endif<commit_msg>Another fixes.<commit_after>// (c) ZaKlaus 2016; Apache 2 Licensed, see LICENSE;;

#if !defined(DZM_H)

#define _CRT_SECURE_NO_WARNINGS

#include <stdint.h>
#include <stddef.h>
#include <limits.h>
#include <float.h>

#define __STDC_FORMAT_MACROS
#include <inttypes.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#if defined(__linux)
#include <readline/readline.h>
#include <readline/history.h>

static inline FILE *
read_input(FILE *Stream)
{

    char *Buffer = readline("");
    FILE *NewStream = Stream;

    if(Buffer[0] != 0)
    {
        add_history(Buffer);
        NewStream = fmemopen((void *)Buffer, strlen(Buffer), "r");
    }

    return(NewStream);
}
#else
static inline FILE *
read_input(FILE *Stream)
{
    return(Stream);
}
#endif

typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef int32 bool32;

typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;

typedef intptr_t intptr;
typedef uintptr_t uintptr;

typedef size_t memory_index;
typedef size_t mi;

typedef float real32;
typedef double real64;

typedef int8 s8;
typedef int8 s08;
typedef int16 s16;
typedef int32 s32;
typedef int64 s64;
typedef bool32 b32;

typedef uint8 u8;
typedef uint8 u08;
typedef uint16 u16;
typedef uint32 u32;
typedef uint64 u64;

typedef real32 r32;
typedef real64 r64;

typedef uintptr_t umm;

#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif

#if !defined(COMPILER_MSVC)
#define COMPILER_MSVC 0
#endif

#if !defined(COMPILER_LLVM)
#define COMPILER_LLVM 0
#endif

#include "../dzm_ver.hpp"

#define MAKE(Type, Value) make_object(Type, (void *)&Value)
#define MAKE1(Type, Value, Value1) make_object(Type, (void *)&Value, (void *)&Value1)
#define MAKE2(Type, Value, Value1, Value2) make_object(Type, (void *)&Value, (void *)&Value1, (void *)&Value2)
#define MAKE3(Type, Value, Value1, Value2, Value3) make_object(Type, (void *)&Value, (void *)&Value1, (void *)&Value2, (void *)&Value3)

#if defined(COMPILER_MSVC) && defined(_WIN32)
#define TRAP() *(int *)0 = 0
#elif defined(COMPILER_LLVM) || defined(__APPLE__)
#define TRAP() __builtin_trap()
#else
#define TRAP() volatile *(int *)0 = 0
#endif

#define IGNORE(x) x

#ifdef DZM_SLOW
#define zassert(Expression) if(!(Expression)) {TRAP();}
#else
#define zassert(Expression)
#endif

#define InvalidCodePath zassert(!"InvalidCodePath")
#define InvalidDefaultCase default: {InvalidCodePath;} break
#define Unreachable(Statement) return(Statement)

#define Kilobytes(Value) ((Value)*1024LL)
#define Megabytes(Value) (Kilobytes(Value)*1024LL)
#define Gigabytes(Value) (Megabytes(Value)*1024LL)
#define Terabytes(Value) (Gigabytes(Value)*1024LL)

#define AlignPow2(Value, Alignment) ((Value + ((Alignment) - 1)) & ~((Alignment) - 1))
#define Align4(Value) ((Value + 3) & ~3)
#define Align8(Value) ((Value + 7) & ~7)
#define Align16(Value) ((Value + 15) & ~15)

#define STRINGIFY(X) #X
#define CONCAT(X,Y) X##Y
#define SQUOTE(X, I, C) char __s_quote__I; sprintf(__s_quote__I, "'%s'", X); C =
#define UL_ (u8 *)
#define L_  (s8 *)

#define MAX_VM_SIZE     4096 * 1024 * 32

static inline void
zero_size(memory_index Size, void *Ptr)
{
    uint8 *Byte = (uint8 *)Ptr;
    while(Size--)
    {
        *Byte++ = 0;
    }
}

#define ArrayCount(Array) (sizeof(Array) / sizeof((Array)[0]))

#ifdef DZM_ELEVATED
#undef _ELEVATED
#define _ELEVATED 1
#else
#undef _ELEVATED
#define _ELEVATED 0
#endif

// == Memory Manager
#include "dzm_mem.hpp"

// == Util
#include "dzm_utl.hpp"
#include "dzm_log.hpp"

// == Interpreter
#include "lang/dzm_mdl.hpp"
#include "lang/dzm_lex.hpp"
#include "lang/dzm_evl.hpp"
#include "lang/dzm_prt.hpp"
#include "lang/dzm_rep.hpp"

#define DZM_H
#endif<|endoftext|>


<commit_before>// -------------------------------------------------------------
// CUDPP -- CUDA Data Parallel Primitives library
// -------------------------------------------------------------
// $Revision: $
// $Date: $
// -------------------------------------------------------------
// This source code is distributed under the terms of license.txt in
// the root directory of this source distribution.
// -------------------------------------------------------------

/**
 * @file
 * test_sa.cpp
 *
 * @brief Host testrig routines to exercise cudpp's suffix array functionality.
 */

#include <cstring>
#include <iostream>
#include <cuda_runtime_api.h>
#include <time.h>

#include "cudpp.h"
#include "cudpp_testrig_options.h"
#include "cudpp_testrig_utils.h"
#include "cuda_util.h"
#include "stopwatch.h"
#include "commandline.h"
#include "comparearrays.h"

#include "sparse.h"
using namespace cudpp_app;

int suffixArrayTest(int argc, const char **argv,
                    const CUDPPConfiguration &config,
                    const testrigOptions &testOptions)
{
    int retval = 0;

    cudpp_app::StopWatch timer;

    bool quiet = checkCommandLineFlag(argc, (const char**) argv, "quiet");
    unsigned int test[] = {39, 128, 256, 512, 513, 1000, 1024, 1025, 32768,
                           45537, 65536, 131072, 262144, 500001, 524288,
                           1048577, 1048576, 1048581};

    int numTests = sizeof(test) / sizeof(test[0]);
    int numElements;
    size_t freeMem, totalMem;
    CUDA_SAFE_CALL(cudaMemGetInfo(&freeMem, &totalMem));
    unsigned int memNeeded = test[numTests-1] * sizeof(unsigned char);
    while (memNeeded > 0.015 * freeMem) {
         numTests -= 1;
	 memNeeded = test[numTests-1] * sizeof(unsigned char);
         if(numTests == 0) {
	       fprintf(stderr,
                       "suffixArrayTest: Error, not enough memory to run test\n");
               return retval;
	 }
    }

    numElements = test[numTests-1] + numTests; // maximum test size
    if(testOptions.skiplongtests)
    {
          numTests -= 3;
    }

    bool oneTest = false;

    if (commandLineArg(numElements, argc, (const char**) argv, "n"))
    {
        oneTest = true;
        numTests = 1;
        test[0] = numElements;
    }

    // Initialize CUDPP
    CUDPPHandle plan;
    CUDPPResult result = CUDPP_SUCCESS;
    CUDPPHandle theCudpp;
    result = cudppCreate(&theCudpp);

    if (result != CUDPP_SUCCESS)
    {
        if (!quiet)
           fprintf(stderr, "Error initializing CUDPP Library\n");
        retval = (oneTest) ? 1 : numTests;
        return retval;
    }

    result = cudppPlan(theCudpp, &plan, config, numElements, 1, 0);

    if(result != CUDPP_SUCCESS)
    {
        if (!quiet)
           fprintf(stderr, "Error in plan creation\n");
        retval = (oneTest) ? 1 : numTests;
        return retval;
    }

    // allocate host memory to store input data
    unsigned char* i_data = new unsigned char[numElements];
    unsigned int* reference = new unsigned int[numElements+3];

    // allocate device memory input and output arrays
    unsigned char* d_idata = (unsigned char *) NULL;
    unsigned int* d_odata = (unsigned int *) NULL;
    CUDA_SAFE_CALL(cudaMalloc((void**) &d_idata,
                              numElements*sizeof(unsigned char)));
    CUDA_SAFE_CALL(cudaMalloc((void**) &d_odata,
                              (numElements+1)*sizeof(unsigned int)));
    for(int k=0; k<numTests; k++)
    {
        if(!quiet)
        {
            printf("Running a Suffix Array test of %u %s nodes\n",
                    test[k], datatypeToString(config.datatype));
            fflush(stdout);
        }

        // initialize the input data on the host
        srand(95835);
        for(int j=0; j<test[k]; ++j)
            i_data[j] = (unsigned char)(rand()%128+1);

        CUDA_SAFE_CALL(cudaMemcpy(d_idata, i_data,
                                  sizeof(unsigned char) * test[k],
                                  cudaMemcpyHostToDevice));
        CUDA_SAFE_CALL(cudaMemset(d_odata, 0,
                                  sizeof(unsigned int) * (test[k]+1)));

        // allocate host memory to store the output data
        unsigned int* o_data =
                (unsigned int*) malloc(sizeof(unsigned int) * test[k]);
        memset(reference, 0, sizeof(unsigned int) * (test[k]+3));

        computeSaGold(i_data, reference, test[k]);

        // Run the SA
	// run once to avoid timing startup overhead.
        result = cudppSuffixArray(plan, d_idata, d_odata, test[k]);

        if (result != CUDPP_SUCCESS)
	{
	     if(!quiet)
	        printf("Error in cudppSuffixArray call in testSa (make sure your device is at"
		" least compute version 2.0)\n");
	     retval = numTests;
	} else {
        timer.reset();
        timer.start();
        for(int i=0; i<testOptions.numIterations; i++)
            cudppSuffixArray(plan, d_idata, d_odata, test[k]);

        CUDA_SAFE_CALL(cudaThreadSynchronize());
        timer.stop();
        }
        d_odata = d_odata+1;
        CUDA_SAFE_CALL(cudaMemcpy(o_data, d_odata,
                                  sizeof(unsigned int) * test[k],
                                  cudaMemcpyDeviceToHost));
        bool result = compareArrays<unsigned int> (reference, o_data, test[k]);

        free(o_data);

        retval += result ? 0 : 1;
        if(!quiet)
        {
            printf("test %s\n", result ? "PASSED" : "FAILED");
            printf("Average execution time: %f ms\n",
                   timer.getTime() / testOptions.numIterations);
        }
        else
            printf("\t%10d\t%0.4f\n", test[k],
                   timer.getTime() / testOptions.numIterations);
    }

    result = cudppDestroyPlan(plan);
    if (result != CUDPP_SUCCESS)
    {
        if (!quiet)
           printf("Error destroying CUDPPPlan for Suffix Array\n");
    }

    result = cudppDestroy(theCudpp);
    if (result != CUDPP_SUCCESS)
    {
         if(!quiet)
            printf("Error shutting down CUDPP Library.\n");
    }

    delete [] reference;
    delete [] i_data;
    cudaFree(d_odata);
    cudaFree(d_idata);
    return retval;
}

int testSuffixArray(int argc, const char **argv,
                    const CUDPPConfiguration *configPtr)
{
    testrigOptions testOptions;
    setOptions(argc, argv, testOptions);

    CUDPPConfiguration config;
    config.algorithm = CUDPP_SA;
    config.options = 0;

    if (configPtr != NULL)
    {
        config = *configPtr;
    }
    else
    {
        config.datatype = CUDPP_UCHAR;
    }

    return suffixArrayTest(argc, argv, config, testOptions);
}

// Leave this at the end of the file
// Local Variables:
// mode:c++
// c-file-style: "NVIDIA"
// End:

<commit_msg>fixed issue in suffix array tests where the wrong memory address is cudafreed<commit_after>// -------------------------------------------------------------
// CUDPP -- CUDA Data Parallel Primitives library
// -------------------------------------------------------------
// $Revision: $
// $Date: $
// -------------------------------------------------------------
// This source code is distributed under the terms of license.txt in
// the root directory of this source distribution.
// -------------------------------------------------------------

/**
 * @file
 * test_sa.cpp
 *
 * @brief Host testrig routines to exercise cudpp's suffix array functionality.
 */

#include <cstring>
#include <iostream>
#include <cuda_runtime_api.h>
#include <time.h>

#include "cudpp.h"
#include "cudpp_testrig_options.h"
#include "cudpp_testrig_utils.h"
#include "cuda_util.h"
#include "stopwatch.h"
#include "commandline.h"
#include "comparearrays.h"

#include "sparse.h"
using namespace cudpp_app;

int suffixArrayTest(int argc, const char **argv,
                    const CUDPPConfiguration &config,
                    const testrigOptions &testOptions)
{
    int retval = 0;

    cudpp_app::StopWatch timer;

    bool quiet = checkCommandLineFlag(argc, (const char**) argv, "quiet");
    unsigned int test[] = {39, 128, 256, 512, 513, 1000, 1024, 1025, 32768,
                           45537, 65536, 131072, 262144, 500001, 524288,
                           1048577, 1048576, 1048581};

    int numTests = sizeof(test) / sizeof(test[0]);
    int numElements;
    size_t freeMem, totalMem;
    CUDA_SAFE_CALL(cudaMemGetInfo(&freeMem, &totalMem));
    unsigned int memNeeded = test[numTests-1] * sizeof(unsigned char);
    while (memNeeded > 0.015 * freeMem) {
         numTests -= 1;
	 memNeeded = test[numTests-1] * sizeof(unsigned char);
         if(numTests == 0) {
	       fprintf(stderr,
                       "suffixArrayTest: Error, not enough memory to run test\n");
               return retval;
	 }
    }

    numElements = test[numTests-1] + numTests; // maximum test size
    if(testOptions.skiplongtests)
    {
          numTests -= 3;
    }

    bool oneTest = false;

    if (commandLineArg(numElements, argc, (const char**) argv, "n"))
    {
        oneTest = true;
        numTests = 1;
        test[0] = numElements;
    }

    // Initialize CUDPP
    CUDPPHandle plan;
    CUDPPResult result = CUDPP_SUCCESS;
    CUDPPHandle theCudpp;
    result = cudppCreate(&theCudpp);

    if (result != CUDPP_SUCCESS)
    {
        if (!quiet)
           fprintf(stderr, "Error initializing CUDPP Library\n");
        retval = (oneTest) ? 1 : numTests;
        return retval;
    }

    result = cudppPlan(theCudpp, &plan, config, numElements, 1, 0);

    if(result != CUDPP_SUCCESS)
    {
        if (!quiet)
           fprintf(stderr, "Error in plan creation\n");
        retval = (oneTest) ? 1 : numTests;
        return retval;
    }

    // allocate host memory to store input data
    unsigned char* i_data = new unsigned char[numElements];
    unsigned int* reference = new unsigned int[numElements+3];

    // allocate device memory input and output arrays
    unsigned char* d_idata = (unsigned char *) NULL;
    unsigned int* d_odata = (unsigned int *) NULL;
    CUDA_SAFE_CALL(cudaMalloc((void**) &d_idata,
                              numElements*sizeof(unsigned char)));
    CUDA_SAFE_CALL(cudaMalloc((void**) &d_odata,
                              (numElements+1)*sizeof(unsigned int)));
    for(int k=0; k<numTests; k++)
    {
        if(!quiet)
        {
            printf("Running a Suffix Array test of %u %s nodes\n",
                    test[k], datatypeToString(config.datatype));
            fflush(stdout);
        }

        // initialize the input data on the host
        srand(95835);
        for(int j=0; j<test[k]; ++j)
            i_data[j] = (unsigned char)(rand()%128+1);

        CUDA_SAFE_CALL(cudaMemcpy(d_idata, i_data,
                                  sizeof(unsigned char) * test[k],
                                  cudaMemcpyHostToDevice));
        CUDA_SAFE_CALL(cudaMemset(d_odata, 0,
                                  sizeof(unsigned int) * (test[k]+1)));

        // allocate host memory to store the output data
        unsigned int* o_data =
                (unsigned int*) malloc(sizeof(unsigned int) * test[k]);
        memset(reference, 0, sizeof(unsigned int) * (test[k]+3));

        computeSaGold(i_data, reference, test[k]);

        // Run the SA
	// run once to avoid timing startup overhead.
        result = cudppSuffixArray(plan, d_idata, d_odata, test[k]);

        if (result != CUDPP_SUCCESS)
        {
          if(!quiet)
            printf("Error in cudppSuffixArray call in testSa (make sure your device is at"
                " least compute version 2.0)\n");
          retval = numTests;
        } else {
          timer.reset();
          timer.start();
          for(int i=0; i<testOptions.numIterations; i++)
              cudppSuffixArray(plan, d_idata, d_odata, test[k]);

          CUDA_SAFE_CALL(cudaThreadSynchronize());
          timer.stop();
        }

        CUDA_SAFE_CALL(cudaMemcpy(o_data, d_odata + 1,
                                  sizeof(unsigned int) * test[k],
                                  cudaMemcpyDeviceToHost));
        bool result = compareArrays<unsigned int> (reference, o_data, test[k]);

        free(o_data);

        retval += result ? 0 : 1;
        if(!quiet)
        {
            printf("test %s\n", result ? "PASSED" : "FAILED");
            printf("Average execution time: %f ms\n",
                   timer.getTime() / testOptions.numIterations);
        } else
            printf("\t%10d\t%0.4f\n", test[k],
                   timer.getTime() / testOptions.numIterations);
    }

    result = cudppDestroyPlan(plan);
    if (result != CUDPP_SUCCESS)
    {
        if (!quiet)
           printf("Error destroying CUDPPPlan for Suffix Array\n");
    }

    result = cudppDestroy(theCudpp);
    if (result != CUDPP_SUCCESS)
    {
         if(!quiet)
            printf("Error shutting down CUDPP Library.\n");
    }

    delete [] reference;
    delete [] i_data;
    cudaFree(d_odata);
    cudaFree(d_idata);
    return retval;
}

int testSuffixArray(int argc, const char **argv,
                    const CUDPPConfiguration *configPtr)
{
    testrigOptions testOptions;
    setOptions(argc, argv, testOptions);

    CUDPPConfiguration config;
    config.algorithm = CUDPP_SA;
    config.options = 0;

    if (configPtr != NULL)
    {
        config = *configPtr;
    }
    else
    {
        config.datatype = CUDPP_UCHAR;
    }

    return suffixArrayTest(argc, argv, config, testOptions);
}

// Leave this at the end of the file
// Local Variables:
// mode:c++
// c-file-style: "NVIDIA"
// End:

<|endoftext|>


<commit_before>/// Implementation of init_tasks.hpp
///
/// (c) Koheron

#include "init_tasks.hpp"

#include <cstdio>
#include <cstring>

extern "C" {
  #include <sys/socket.h>
  #include <sys/types.h>
  #include <arpa/inet.h>
  #include <ifaddrs.h>
}

#include "../drivers/core/wr_register.hpp"

InitTasks::InitTasks(Klib::DevMem& dev_mem_)
: dev_mem(dev_mem_)
{}

#define LED_ADDR 0x43C00000
#define MAP_SIZE 4096
#define LED_OFFSET 0x0

void InitTasks::show_ip_on_leds()
{
// http://stackoverflow.com/questions/20800319/how-to-get-my-ip-address-in-c-linux

    struct ifaddrs *addrs;
    getifaddrs(&addrs);
    ifaddrs *tmp = addrs;

    // Turn all the leds ON
    Klib::MemMapID dev_num = dev_mem.AddMemoryMap(LED_ADDR, 16*MAP_SIZE);
    Klib::WriteReg32(dev_mem.GetBaseAddr(dev_num) + LED_OFFSET, 255);

    char interface[] = "eth0";

    while(tmp) {
        // Works only for IPv4 address
        if(tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET) {
            struct sockaddr_in *pAddr = (struct sockaddr_in *)tmp->ifa_addr;
            int val = strcmp(tmp->ifa_name,interface);

            if(val != 0) {
                tmp = tmp->ifa_next;
                continue;
            }

            // Interface found
            printf("Interface %s found: %s\n",
                   tmp->ifa_name, inet_ntoa(pAddr->sin_addr));
            uint32_t ip = htonl(pAddr->sin_addr.s_addr);

            // Write IP address in FPGA memory
            // The 8 Least Significant Bits should be connected to the FPGA LEDs
            Klib::WriteReg32(dev_mem.GetBaseAddr(dev_num) + LED_OFFSET, ip);

            break;
        }

        tmp = tmp->ifa_next;
    }

    freeifaddrs(addrs);
    dev_mem.RmMemoryMap(dev_num);
}
<commit_msg>Update init_tasks.cpp<commit_after>/// Implementation of init_tasks.hpp
///
/// (c) Koheron

#include "init_tasks.hpp"

#include <cstdio>
#include <cstring>

extern "C" {
  #include <sys/socket.h>
  #include <sys/types.h>
  #include <arpa/inet.h>
  #include <ifaddrs.h>
}

#include "../drivers/core/wr_register.hpp"

InitTasks::InitTasks(Klib::DevMem& dev_mem_)
: dev_mem(dev_mem_)
{}

#define LED_ADDR 0x60000000
#define MAP_SIZE 4096
#define LED_OFFSET 0x0

void InitTasks::show_ip_on_leds()
{
// http://stackoverflow.com/questions/20800319/how-to-get-my-ip-address-in-c-linux

    struct ifaddrs *addrs;
    getifaddrs(&addrs);
    ifaddrs *tmp = addrs;

    // Turn all the leds ON
    Klib::MemMapID dev_num = dev_mem.AddMemoryMap(LED_ADDR, 16*MAP_SIZE);
    Klib::WriteReg32(dev_mem.GetBaseAddr(dev_num) + LED_OFFSET, 255);

    char interface[] = "eth0";

    while(tmp) {
        // Works only for IPv4 address
        if(tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET) {
            struct sockaddr_in *pAddr = (struct sockaddr_in *)tmp->ifa_addr;
            int val = strcmp(tmp->ifa_name,interface);

            if(val != 0) {
                tmp = tmp->ifa_next;
                continue;
            }

            // Interface found
            printf("Interface %s found: %s\n",
                   tmp->ifa_name, inet_ntoa(pAddr->sin_addr));
            uint32_t ip = htonl(pAddr->sin_addr.s_addr);

            // Write IP address in FPGA memory
            // The 8 Least Significant Bits should be connected to the FPGA LEDs
            Klib::WriteReg32(dev_mem.GetBaseAddr(dev_num) + LED_OFFSET, ip);

            break;
        }

        tmp = tmp->ifa_next;
    }

    freeifaddrs(addrs);
    dev_mem.RmMemoryMap(dev_num);
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "otbWrapperApplication.h"
#include "otbWrapperApplicationFactory.h"

#include "otbChangeLabelImageFilter.h"
#include "otbStandardWriterWatcher.h"
#include "otbStatisticsXMLFileReader.h"
#include "otbShiftScaleVectorImageFilter.h"
#include "otbImageClassificationFilter.h"
#include "otbMultiToMonoChannelExtractROI.h"
#include "otbImageToVectorImageCastFilter.h"
#include "otbMachineLearningModelFactory.h"

namespace otb
{
namespace Wrapper
{

class ImageClassifier : public Application
{
public:
  /** Standard class typedefs. */
  typedef ImageClassifier            Self;
  typedef Application                   Superclass;
  typedef itk::SmartPointer<Self>       Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;

  /** Standard macro */
  itkNewMacro(Self);

  itkTypeMacro(ImageClassifier, otb::Application);

  /** Filters typedef */
  typedef UInt16ImageType                                                                      OutputImageType;
  typedef UInt8ImageType                                                                       MaskImageType;
  typedef itk::VariableLengthVector<FloatVectorImageType::InternalPixelType>                   MeasurementType;
  typedef otb::StatisticsXMLFileReader<MeasurementType>                                        StatisticsReader;
  typedef otb::ShiftScaleVectorImageFilter<FloatVectorImageType, FloatVectorImageType>         RescalerType;
  typedef otb::ImageClassificationFilter<FloatVectorImageType, OutputImageType, MaskImageType> ClassificationFilterType;
  typedef ClassificationFilterType::Pointer                                                    ClassificationFilterPointerType;
  typedef ClassificationFilterType::ModelType                                                  ModelType;
  typedef ModelType::Pointer                                                                   ModelPointerType;
  typedef ClassificationFilterType::ValueType                                                  ValueType;
  typedef ClassificationFilterType::LabelType                                                  LabelType;
  typedef otb::MachineLearningModelFactory<ValueType, LabelType>                               MachineLearningModelFactoryType;
  typedef ClassificationFilterType::ConfidenceImageType                                        ConfidenceImageType;

protected:

  ~ImageClassifier() ITK_OVERRIDE
    {
    MachineLearningModelFactoryType::CleanFactories();
    }

private:
  void DoInit() ITK_OVERRIDE
  {
    SetName("ImageClassifier");
    SetDescription("Performs a classification of the input image according to a model file.");

    // Documentation
    SetDocName("Image Classification");
    SetDocLongDescription("This application performs an image classification based on a model file produced by the TrainImagesClassifier application. Pixels of the output image will contain the class labels decided by the classifier (maximal class label = 65535). The input pixels can be optionally centered and reduced according to the statistics file produced by the ComputeImagesStatistics application. An optional input mask can be provided, in which case only input image pixels whose corresponding mask value is greater than 0 will be classified. The remaining of pixels will be given the label 0 in the output image.");

    SetDocLimitations("The input image must have the same type, order and number of bands than the images used to produce the statistics file and the SVM model file. If a statistics file was used during training by the TrainImagesClassifier, it is mandatory to use the same statistics file for classification. If an input mask is used, its size must match the input image size.");
    SetDocAuthors("OTB-Team");
    SetDocSeeAlso("TrainImagesClassifier, ValidateImagesClassifier, ComputeImagesStatistics");

    AddDocTag(Tags::Learning);

    AddParameter(ParameterType_InputImage, "in",  "Input Image");
    SetParameterDescription( "in", "The input image to classify.");

    AddParameter(ParameterType_InputImage,  "mask",   "Input Mask");
    SetParameterDescription( "mask", "The mask allows restricting classification of the input image to the area where mask pixel values are greater than 0.");
    MandatoryOff("mask");

    AddParameter(ParameterType_InputFilename, "model", "Model file");
    SetParameterDescription("model", "A model file (produced by TrainImagesClassifier application, maximal class label = 65535).");

    AddParameter(ParameterType_InputFilename, "imstat", "Statistics file");
    SetParameterDescription("imstat", "A XML file containing mean and standard deviation to center and reduce samples before classification (produced by ComputeImagesStatistics application).");
    MandatoryOff("imstat");

    AddParameter(ParameterType_OutputImage, "out",  "Output Image");
    SetParameterDescription( "out", "Output image containing class labels");
    SetDefaultOutputPixelType( "out", ImagePixelType_uint8);

    AddParameter(ParameterType_OutputImage, "confmap",  "Confidence map");
    SetParameterDescription( "confmap", "Confidence map of the produced classification. The confidence index depends on the model : \n"
      "  - LibSVM : difference between the two highest probabilities (needs a model with probability estimates, so that classes probabilities can be computed for each sample)\n"
      "  - OpenCV\n"
      "    * Boost : sum of votes\n"
      "    * DecisionTree : (not supported)\n"
      "    * GradientBoostedTree : (not supported)\n"
      "    * KNearestNeighbors : number of neighbors with the same label\n"
      "    * NeuralNetwork : difference between the two highest responses\n"
      "    * NormalBayes : (not supported)\n"
      "    * RandomForest : Confidence (proportion of votes for the majority class). Margin (normalized difference of the votes of the 2 majority classes) is not available for now.\n"
      "    * SVM : distance to margin (only works for 2-class models)\n");
    SetDefaultOutputPixelType( "confmap", ImagePixelType_double);
    MandatoryOff("confmap");

    AddRAMParameter();

   // Doc example parameter settings
    SetDocExampleParameterValue("in", "QB_1_ortho.tif");
    SetDocExampleParameterValue("imstat", "EstimateImageStatisticsQB1.xml");
    SetDocExampleParameterValue("model", "clsvmModelQB1.svm");
    SetDocExampleParameterValue("out", "clLabeledImageQB1.tif");

    SetOfficialDocLink();
  }

  void DoUpdateParameters() ITK_OVERRIDE
  {
    // Nothing to do here : all parameters are independent
  }

  void DoExecute() ITK_OVERRIDE
  {
    // Load input image
    FloatVectorImageType::Pointer inImage = GetParameterImage("in");
    inImage->UpdateOutputInformation();

    // Load svm model
    otbAppLogINFO("Loading model");
    m_Model = MachineLearningModelFactoryType::CreateMachineLearningModel(GetParameterString("model"),
                                                                          MachineLearningModelFactoryType::ReadMode);

    if (m_Model.IsNull())
      {
      otbAppLogFATAL(<< "Error when loading model " << GetParameterString("model") << " : unsupported model type");
      }

    m_Model->Load(GetParameterString("model"));
    otbAppLogINFO("Model loaded");

    // Normalize input image (optional)
    StatisticsReader::Pointer  statisticsReader = StatisticsReader::New();
    MeasurementType  meanMeasurementVector;
    MeasurementType  stddevMeasurementVector;
    m_Rescaler = RescalerType::New();

    // Classify
    m_ClassificationFilter = ClassificationFilterType::New();
    m_ClassificationFilter->SetModel(m_Model);

    // Normalize input image if asked
    if(IsParameterEnabled("imstat")  )
      {
      otbAppLogINFO("Input image normalization activated.");
      // Load input image statistics
      statisticsReader->SetFileName(GetParameterString("imstat"));
      meanMeasurementVector   = statisticsReader->GetStatisticVectorByName("mean");
      stddevMeasurementVector = statisticsReader->GetStatisticVectorByName("stddev");
      otbAppLogINFO( "mean used: " << meanMeasurementVector );
      otbAppLogINFO( "standard deviation used: " << stddevMeasurementVector );
      // Rescale vector image
      m_Rescaler->SetScale(stddevMeasurementVector);
      m_Rescaler->SetShift(meanMeasurementVector);
      m_Rescaler->SetInput(inImage);

      m_ClassificationFilter->SetInput(m_Rescaler->GetOutput());
      }
    else
      {
      otbAppLogINFO("Input image normalization deactivated.");
      m_ClassificationFilter->SetInput(inImage);
      }

    if(IsParameterEnabled("mask"))
      {
      otbAppLogINFO("Using input mask");
      // Load mask image and cast into LabeledImageType
      MaskImageType::Pointer inMask = GetParameterUInt8Image("mask");

      m_ClassificationFilter->SetInputMask(inMask);
      }

    SetParameterOutputImage<OutputImageType>("out", m_ClassificationFilter->GetOutput());

    // output confidence map
    if (IsParameterEnabled("confmap") && HasValue("confmap"))
      {
      m_ClassificationFilter->SetUseConfidenceMap(true);
      if (m_Model->HasConfidenceIndex())
        {
        SetParameterOutputImage<ConfidenceImageType>("confmap",m_ClassificationFilter->GetOutputConfidence());
        }
      else
        {
        otbAppLogWARNING("Confidence map requested but the classifier doesn't support it!");
        this->DisableParameter("confmap");
        }
      }
  }

  ClassificationFilterType::Pointer m_ClassificationFilter;
  ModelPointerType m_Model;
  RescalerType::Pointer m_Rescaler;
};

}
}

OTB_APPLICATION_EXPORT(otb::Wrapper::ImageClassifier)
<commit_msg>ENH: standardize MachineLearningModel output type in ImageClassifier<commit_after>/*
 * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "otbWrapperApplication.h"
#include "otbWrapperApplicationFactory.h"

#include "otbChangeLabelImageFilter.h"
#include "otbStandardWriterWatcher.h"
#include "otbStatisticsXMLFileReader.h"
#include "otbShiftScaleVectorImageFilter.h"
#include "otbImageClassificationFilter.h"
#include "otbMultiToMonoChannelExtractROI.h"
#include "otbImageToVectorImageCastFilter.h"
#include "otbMachineLearningModelFactory.h"

namespace otb
{
namespace Wrapper
{

class ImageClassifier : public Application
{
public:
  /** Standard class typedefs. */
  typedef ImageClassifier            Self;
  typedef Application                   Superclass;
  typedef itk::SmartPointer<Self>       Pointer;
  typedef itk::SmartPointer<const Self> ConstPointer;

  /** Standard macro */
  itkNewMacro(Self);

  itkTypeMacro(ImageClassifier, otb::Application);

  /** Filters typedef */
  //typedef UInt16ImageType                                                                    OutputImageType;
  typedef Int32ImageType                                                                       OutputImageType;
  typedef UInt8ImageType                                                                       MaskImageType;
  typedef itk::VariableLengthVector<FloatVectorImageType::InternalPixelType>                   MeasurementType;
  typedef otb::StatisticsXMLFileReader<MeasurementType>                                        StatisticsReader;
  typedef otb::ShiftScaleVectorImageFilter<FloatVectorImageType, FloatVectorImageType>         RescalerType;
  typedef otb::ImageClassificationFilter<FloatVectorImageType, OutputImageType, MaskImageType> ClassificationFilterType;
  typedef ClassificationFilterType::Pointer                                                    ClassificationFilterPointerType;
  typedef ClassificationFilterType::ModelType                                                  ModelType;
  typedef ModelType::Pointer                                                                   ModelPointerType;
  typedef ClassificationFilterType::ValueType                                                  ValueType;
  typedef ClassificationFilterType::LabelType                                                  LabelType;
  typedef otb::MachineLearningModelFactory<ValueType, LabelType>                               MachineLearningModelFactoryType;
  typedef ClassificationFilterType::ConfidenceImageType                                        ConfidenceImageType;

protected:

  ~ImageClassifier() ITK_OVERRIDE
    {
    MachineLearningModelFactoryType::CleanFactories();
    }

private:
  void DoInit() ITK_OVERRIDE
  {
    SetName("ImageClassifier");
    SetDescription("Performs a classification of the input image according to a model file.");

    // Documentation
    SetDocName("Image Classification");
    SetDocLongDescription("This application performs an image classification based on a model file produced by the TrainImagesClassifier application. Pixels of the output image will contain the class labels decided by the classifier (maximal class label = 65535). The input pixels can be optionally centered and reduced according to the statistics file produced by the ComputeImagesStatistics application. An optional input mask can be provided, in which case only input image pixels whose corresponding mask value is greater than 0 will be classified. The remaining of pixels will be given the label 0 in the output image.");

    SetDocLimitations("The input image must have the same type, order and number of bands than the images used to produce the statistics file and the SVM model file. If a statistics file was used during training by the TrainImagesClassifier, it is mandatory to use the same statistics file for classification. If an input mask is used, its size must match the input image size.");
    SetDocAuthors("OTB-Team");
    SetDocSeeAlso("TrainImagesClassifier, ValidateImagesClassifier, ComputeImagesStatistics");

    AddDocTag(Tags::Learning);

    AddParameter(ParameterType_InputImage, "in",  "Input Image");
    SetParameterDescription( "in", "The input image to classify.");

    AddParameter(ParameterType_InputImage,  "mask",   "Input Mask");
    SetParameterDescription( "mask", "The mask allows restricting classification of the input image to the area where mask pixel values are greater than 0.");
    MandatoryOff("mask");

    AddParameter(ParameterType_InputFilename, "model", "Model file");
    SetParameterDescription("model", "A model file (produced by TrainImagesClassifier application, maximal class label = 65535).");

    AddParameter(ParameterType_InputFilename, "imstat", "Statistics file");
    SetParameterDescription("imstat", "A XML file containing mean and standard deviation to center and reduce samples before classification (produced by ComputeImagesStatistics application).");
    MandatoryOff("imstat");

    AddParameter(ParameterType_OutputImage, "out",  "Output Image");
    SetParameterDescription( "out", "Output image containing class labels");
    SetDefaultOutputPixelType( "out", ImagePixelType_uint8);

    AddParameter(ParameterType_OutputImage, "confmap",  "Confidence map");
    SetParameterDescription( "confmap", "Confidence map of the produced classification. The confidence index depends on the model : \n"
      "  - LibSVM : difference between the two highest probabilities (needs a model with probability estimates, so that classes probabilities can be computed for each sample)\n"
      "  - OpenCV\n"
      "    * Boost : sum of votes\n"
      "    * DecisionTree : (not supported)\n"
      "    * GradientBoostedTree : (not supported)\n"
      "    * KNearestNeighbors : number of neighbors with the same label\n"
      "    * NeuralNetwork : difference between the two highest responses\n"
      "    * NormalBayes : (not supported)\n"
      "    * RandomForest : Confidence (proportion of votes for the majority class). Margin (normalized difference of the votes of the 2 majority classes) is not available for now.\n"
      "    * SVM : distance to margin (only works for 2-class models)\n");
    SetDefaultOutputPixelType( "confmap", ImagePixelType_double);
    MandatoryOff("confmap");

    AddRAMParameter();

   // Doc example parameter settings
    SetDocExampleParameterValue("in", "QB_1_ortho.tif");
    SetDocExampleParameterValue("imstat", "EstimateImageStatisticsQB1.xml");
    SetDocExampleParameterValue("model", "clsvmModelQB1.svm");
    SetDocExampleParameterValue("out", "clLabeledImageQB1.tif");

    SetOfficialDocLink();
  }

  void DoUpdateParameters() ITK_OVERRIDE
  {
    // Nothing to do here : all parameters are independent
  }

  void DoExecute() ITK_OVERRIDE
  {
    // Load input image
    FloatVectorImageType::Pointer inImage = GetParameterImage("in");
    inImage->UpdateOutputInformation();

    // Load svm model
    otbAppLogINFO("Loading model");
    m_Model = MachineLearningModelFactoryType::CreateMachineLearningModel(GetParameterString("model"),
                                                                          MachineLearningModelFactoryType::ReadMode);

    if (m_Model.IsNull())
      {
      otbAppLogFATAL(<< "Error when loading model " << GetParameterString("model") << " : unsupported model type");
      }

    m_Model->Load(GetParameterString("model"));
    otbAppLogINFO("Model loaded");

    // Normalize input image (optional)
    StatisticsReader::Pointer  statisticsReader = StatisticsReader::New();
    MeasurementType  meanMeasurementVector;
    MeasurementType  stddevMeasurementVector;
    m_Rescaler = RescalerType::New();

    // Classify
    m_ClassificationFilter = ClassificationFilterType::New();
    m_ClassificationFilter->SetModel(m_Model);

    // Normalize input image if asked
    if(IsParameterEnabled("imstat")  )
      {
      otbAppLogINFO("Input image normalization activated.");
      // Load input image statistics
      statisticsReader->SetFileName(GetParameterString("imstat"));
      meanMeasurementVector   = statisticsReader->GetStatisticVectorByName("mean");
      stddevMeasurementVector = statisticsReader->GetStatisticVectorByName("stddev");
      otbAppLogINFO( "mean used: " << meanMeasurementVector );
      otbAppLogINFO( "standard deviation used: " << stddevMeasurementVector );
      // Rescale vector image
      m_Rescaler->SetScale(stddevMeasurementVector);
      m_Rescaler->SetShift(meanMeasurementVector);
      m_Rescaler->SetInput(inImage);

      m_ClassificationFilter->SetInput(m_Rescaler->GetOutput());
      }
    else
      {
      otbAppLogINFO("Input image normalization deactivated.");
      m_ClassificationFilter->SetInput(inImage);
      }

    if(IsParameterEnabled("mask"))
      {
      otbAppLogINFO("Using input mask");
      // Load mask image and cast into LabeledImageType
      MaskImageType::Pointer inMask = GetParameterUInt8Image("mask");

      m_ClassificationFilter->SetInputMask(inMask);
      }

    SetParameterOutputImage<OutputImageType>("out", m_ClassificationFilter->GetOutput());

    // output confidence map
    if (IsParameterEnabled("confmap") && HasValue("confmap"))
      {
      m_ClassificationFilter->SetUseConfidenceMap(true);
      if (m_Model->HasConfidenceIndex())
        {
        SetParameterOutputImage<ConfidenceImageType>("confmap",m_ClassificationFilter->GetOutputConfidence());
        }
      else
        {
        otbAppLogWARNING("Confidence map requested but the classifier doesn't support it!");
        this->DisableParameter("confmap");
        }
      }
  }

  ClassificationFilterType::Pointer m_ClassificationFilter;
  ModelPointerType m_Model;
  RescalerType::Pointer m_Rescaler;
};

}
}

OTB_APPLICATION_EXPORT(otb::Wrapper::ImageClassifier)
<|endoftext|>