<commit_before>/** @file
 *
 * @ingroup modularLibrary
 *
 * @brief TTObjectBase to handle any signal output
 *
 * @details
 *
 * @authors Théo de la Hogue
 *
 * @copyright © 2010, Théo de la Hogue @n
 * This code is licensed under the terms of the "New BSD License" @n
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTOutput.h"
#include "TTModular.h"

#define thisTTClass			TTOutput
#define thisTTClassName		"Output"
#define thisTTClassTags		"output"

TT_MODULAR_CONSTRUCTOR,
mType(kTTSymEmpty),
mInputAddress(kTTAdrsEmpty),
mMute(NO),
mMix(100.),
mGain(100.),
mFreeze(NO),
mSignalIn(NULL),
mSignalOut(NULL),
mSignalTemp(NULL),
mSignalZero(NULL),
mMixUnit(NULL),
mGainUnit(NULL),
mRampMixUnit(NULL),
mRampGainUnit(NULL),
mInputObject(NULL),
mReturnSignalCallback(NULL),
mReturnLinkCallback(NULL),
mLast(NULL),
mAddressObserver(NULL),
mSignal(kTTValNONE),
mSignalAttr(NULL)
{
	TT_ASSERT("Correct number of args to create TTOutput", arguments.size() > 0);

    if (arguments.size() > 0)
        mType = arguments[0];

    if (arguments.size() > 1) {
        mReturnSignalCallback = TTCallbackPtr((TTObjectBasePtr)arguments[1]);
        TT_ASSERT("Return Signal Callback passed to TTOutput is not NULL", mReturnSignalCallback);
    }

    if (arguments.size() > 2) {
        mReturnLinkCallback = TTCallbackPtr((TTObjectBasePtr)arguments[2]);
        TT_ASSERT("Return Link Callback passed to TTOutput is not NULL", mReturnLinkCallback);
    }

	if (arguments.size() > 3) {
		mSignalIn = arguments[3];
		mSignalOut = arguments[4];
		mSignalTemp = arguments[5];
		mSignalZero = arguments[6];
	}

	if (arguments.size() > 7) {
		mMixUnit = arguments[7];
		mGainUnit = arguments[8];
		mRampMixUnit = arguments[9];
		mRampGainUnit = arguments[10];
	}

	addAttribute(Type, kTypeSymbol);
	addAttributeProperty(Type, readOnly, YES);

	addAttributeWithSetter(InputAddress, kTypeSymbol);

	addAttributeWithSetter(Mute, kTypeBoolean);
	addAttributeWithSetter(Mix, kTypeFloat64);
	addAttributeWithSetter(Gain, kTypeFloat64);
	addAttribute(Freeze, kTypeBoolean);

	addAttribute(Signal, kTypeLocalValue);
	addAttributeProperty(Signal, hidden, YES);
	addAttributeProperty(Signal, readOnly, YES);

	addMessageWithArguments(Send);
	addMessageProperty(Send, hidden, YES);

	addMessageWithArguments(SendBypassed);
	addMessageProperty(SendBypassed, hidden, YES);

	addMessageWithArguments(Link);
	addMessageProperty(Link, hidden, YES);

	addMessage(Unlink);
	addMessageProperty(Unlink, hidden, YES);

    // only needed because, for Max, the configuration file tells to convert 'mix' into 'Mix')
    addMessageWithArguments(Mix);
	addMessageProperty(Mix, hidden, YES);

	mLast.clear();

	this->findAttribute(TTSymbol("signal"), &mSignalAttr);
}

TTOutput::~TTOutput()
{
	if (mReturnSignalCallback) {
		delete (TTValuePtr)mReturnSignalCallback->getBaton();
		TTObjectBaseRelease(TTObjectBaseHandle(&mReturnSignalCallback));
	}

	if (mReturnLinkCallback) {
		delete (TTValuePtr)mReturnLinkCallback->getBaton();
		TTObjectBaseRelease(TTObjectBaseHandle(&mReturnLinkCallback));
	}

	if (mSignalIn)
		TTObjectBaseRelease(&mSignalIn);

	if (mSignalOut)
		TTObjectBaseRelease(&mSignalOut);

	if (mSignalTemp)
		TTObjectBaseRelease(&mSignalTemp);

	if (mSignalZero)
		TTObjectBaseRelease(&mSignalZero);

	if (mMixUnit)
		TTObjectBaseRelease(&mMixUnit);

	if (mGainUnit)
		TTObjectBaseRelease(&mGainUnit);

	if (mRampMixUnit)
		TTObjectBaseRelease(&mMixUnit);

	if (mRampGainUnit)
		TTObjectBaseRelease(&mGainUnit);

	if (mAddressObserver) {

		if (mInputAddress != kTTSymEmpty)
			getLocalDirectory->removeObserverForNotifications(mInputAddress, mAddressObserver);

		delete (TTValuePtr)mAddressObserver->getBaton();
		TTObjectBaseRelease(TTObjectBaseHandle(&mAddressObserver));
	}
}

TTErr TTOutput::Send(const TTValue& inputValue, TTValue& outputValue)
{
	TTErr err;

    if (!mReturnSignalCallback)
        return kTTErrGeneric;

	if (mMute)
		err = kTTErrNone;

	else if (mFreeze) {

		err = mReturnSignalCallback->deliver(mLast);

		notifySignalObserver(mLast);
	}
	else {

		err = mReturnSignalCallback->deliver(inputValue);

		notifySignalObserver(inputValue);
	}

	// copy
	if (!mFreeze)
		mLast = inputValue;

	return err;
}

TTErr TTOutput::SendBypassed(const TTValue& inputValue, TTValue& outputValue)
{
	TTValue dummy;
	return Send(inputValue, dummy);
}

TTErr TTOutput::Link(const TTValue& inputValue, TTValue& outputValue)
{
	mInputObject = TTInputPtr((TTObjectBasePtr)inputValue[0]);

	if (mReturnLinkCallback)
		return mReturnLinkCallback->deliver(1);
	else
		return kTTErrNone;
}

TTErr TTOutput::Unlink()
{
	mInputObject = NULL;

	if (mReturnLinkCallback)
		return mReturnLinkCallback->deliver(0);
	else
		return kTTErrNone;
}

TTErr TTOutput::setInputAddress(const TTValue& value)
{
	TTValue			args;
	TTValuePtr		newBaton;
	TTAddress       newAddress;
	TTNodePtr		aNode;
	TTObjectBasePtr	o;
	TTValue			none, n = value;		// use new value to protect the attribute

	newAddress = value[0];

	if (!getLocalDirectory->getTTNode(newAddress, &aNode)) {

		o = aNode->getObject();
		if (o)
			if (o->getName() == kTTSym_Input|| o->getName() == kTTSym_InputAudio)
				Link(o, none);
	}

	if (!mAddressObserver) {

		// prepare arguments
		mAddressObserver = NULL; // without this, TTObjectBaseInstantiate try to release an oldObject that doesn't exist ... Is it good ?
		TTObjectBaseInstantiate(TTSymbol("callback"), TTObjectBaseHandle(&mAddressObserver), none);

		newBaton = new TTValue(TTObjectBasePtr(this));
		mAddressObserver->setAttributeValue(kTTSym_baton, TTPtr(newBaton));
		mAddressObserver->setAttributeValue(kTTSym_function, TTPtr(&TTOutputDirectoryCallback));
		mAddressObserver->setAttributeValue(TTSymbol("owner"), TTSymbol("TTOutput"));		// this is usefull only to debug
	}

	if (mAddressObserver) {
		if (mInputAddress != kTTAdrsEmpty)
			getLocalDirectory->removeObserverForNotifications(mInputAddress, mAddressObserver);

		getLocalDirectory->addObserverForNotifications(newAddress, mAddressObserver, 0); // ask for notification only for equal addresses
	}

	mInputAddress = newAddress;

	return kTTErrNone;
}

TTErr TTOutput::setMute(const TTValue& value)
{
	mMute = value;

	if (mGainUnit) {

		if (mMute)
			return mGainUnit->setAttributeValue(TTSymbol("linearGain"), 0.0);
		else
			return mGainUnit->setAttributeValue(TTSymbol("midiGain"), mGain);
	}

	return kTTErrNone;
}

TTErr TTOutput::setMix(const TTValue& value)
{
	mMix = value;

	if (mMixUnit)
		return mMixUnit->setAttributeValue(TTSymbol("position"), mMix * 0.01);

	return kTTErrNone;
}

TTErr TTOutput::Mix(const TTValue& inputValue, TTValue& outputValue)
{
    return setMix(inputValue);
}

TTErr TTOutput::setGain(const TTValue& value)
{
	mGain = value;

	if (mGainUnit)
		return mGainUnit->setAttributeValue(TTSymbol("midiGain"), mGain);

	return kTTErrNone;
}

TTErr TTOutput::notifySignalObserver(const TTValue& value)
{
	mSignal = value;

	mSignalAttr->sendNotification(kTTSym_notify, mSignal);	// we use kTTSym_notify because we know that observers are TTCallback

	return kTTErrNone;
}

#if 0
#pragma mark -
#pragma mark Some Methods
#endif

TTErr TTOutputDirectoryCallback(TTPtr baton, TTValue& data)
{
	TTValuePtr		b;
	TTOutputPtr		anOutput;
	TTSymbol		anAddress;
	TTNodePtr		aNode;
	TTUInt8			flag;
	TTObjectBasePtr		o;

	// unpack baton (an OutputPtr)
	b = (TTValuePtr)baton;
	anOutput = TTOutputPtr((TTObjectBasePtr)(*b)[0]);

	// Unpack data (anAddress, aNode, flag, anObserver)
	anAddress = data[0];
	aNode = TTNodePtr((TTPtr)data[1]);
	flag = data[2];

	o = aNode->getObject();
	if (o) {
		if (o->getName() == kTTSym_Input || o->getName() == kTTSym_InputAudio) {

			switch (flag) {

				case kAddressCreated :
				{
					TTValue unused;
					anOutput->Link(o, unused);
					break;
				}

				case kAddressDestroyed :
				{
					anOutput->Unlink();
					break;
				}

				default:
					break;
			}
		}
	}

	return kTTErrNone;
}
<commit_msg>Setting mType attribute not as a readOnly attribute<commit_after>/** @file
 *
 * @ingroup modularLibrary
 *
 * @brief TTObjectBase to handle any signal output
 *
 * @details
 *
 * @authors Théo de la Hogue
 *
 * @copyright © 2010, Théo de la Hogue @n
 * This code is licensed under the terms of the "New BSD License" @n
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTOutput.h"
#include "TTModular.h"

#define thisTTClass			TTOutput
#define thisTTClassName		"Output"
#define thisTTClassTags		"output"

TT_MODULAR_CONSTRUCTOR,
mType(kTTSymEmpty),
mInputAddress(kTTAdrsEmpty),
mMute(NO),
mMix(100.),
mGain(100.),
mFreeze(NO),
mSignalIn(NULL),
mSignalOut(NULL),
mSignalTemp(NULL),
mSignalZero(NULL),
mMixUnit(NULL),
mGainUnit(NULL),
mRampMixUnit(NULL),
mRampGainUnit(NULL),
mInputObject(NULL),
mReturnSignalCallback(NULL),
mReturnLinkCallback(NULL),
mLast(NULL),
mAddressObserver(NULL),
mSignal(kTTValNONE),
mSignalAttr(NULL)
{
	TT_ASSERT("Correct number of args to create TTOutput", arguments.size() > 0);

    if (arguments.size() > 0)
        mType = arguments[0];

    if (arguments.size() > 1) {
        mReturnSignalCallback = TTCallbackPtr((TTObjectBasePtr)arguments[1]);
        TT_ASSERT("Return Signal Callback passed to TTOutput is not NULL", mReturnSignalCallback);
    }

    if (arguments.size() > 2) {
        mReturnLinkCallback = TTCallbackPtr((TTObjectBasePtr)arguments[2]);
        TT_ASSERT("Return Link Callback passed to TTOutput is not NULL", mReturnLinkCallback);
    }

	if (arguments.size() > 3) {
		mSignalIn = arguments[3];
		mSignalOut = arguments[4];
		mSignalTemp = arguments[5];
		mSignalZero = arguments[6];
	}

	if (arguments.size() > 7) {
		mMixUnit = arguments[7];
		mGainUnit = arguments[8];
		mRampMixUnit = arguments[9];
		mRampGainUnit = arguments[10];
	}

	addAttribute(Type, kTypeSymbol);

	addAttributeWithSetter(InputAddress, kTypeSymbol);

	addAttributeWithSetter(Mute, kTypeBoolean);
	addAttributeWithSetter(Mix, kTypeFloat64);
	addAttributeWithSetter(Gain, kTypeFloat64);
	addAttribute(Freeze, kTypeBoolean);

	addAttribute(Signal, kTypeLocalValue);
	addAttributeProperty(Signal, hidden, YES);
	addAttributeProperty(Signal, readOnly, YES);

	addMessageWithArguments(Send);
	addMessageProperty(Send, hidden, YES);

	addMessageWithArguments(SendBypassed);
	addMessageProperty(SendBypassed, hidden, YES);

	addMessageWithArguments(Link);
	addMessageProperty(Link, hidden, YES);

	addMessage(Unlink);
	addMessageProperty(Unlink, hidden, YES);

    // only needed because, for Max, the configuration file tells to convert 'mix' into 'Mix')
    addMessageWithArguments(Mix);
	addMessageProperty(Mix, hidden, YES);

	mLast.clear();

	this->findAttribute(TTSymbol("signal"), &mSignalAttr);
}

TTOutput::~TTOutput()
{
	if (mReturnSignalCallback) {
		delete (TTValuePtr)mReturnSignalCallback->getBaton();
		TTObjectBaseRelease(TTObjectBaseHandle(&mReturnSignalCallback));
	}

	if (mReturnLinkCallback) {
		delete (TTValuePtr)mReturnLinkCallback->getBaton();
		TTObjectBaseRelease(TTObjectBaseHandle(&mReturnLinkCallback));
	}

	if (mSignalIn)
		TTObjectBaseRelease(&mSignalIn);

	if (mSignalOut)
		TTObjectBaseRelease(&mSignalOut);

	if (mSignalTemp)
		TTObjectBaseRelease(&mSignalTemp);

	if (mSignalZero)
		TTObjectBaseRelease(&mSignalZero);

	if (mMixUnit)
		TTObjectBaseRelease(&mMixUnit);

	if (mGainUnit)
		TTObjectBaseRelease(&mGainUnit);

	if (mRampMixUnit)
		TTObjectBaseRelease(&mMixUnit);

	if (mRampGainUnit)
		TTObjectBaseRelease(&mGainUnit);

	if (mAddressObserver) {

		if (mInputAddress != kTTSymEmpty)
			getLocalDirectory->removeObserverForNotifications(mInputAddress, mAddressObserver);

		delete (TTValuePtr)mAddressObserver->getBaton();
		TTObjectBaseRelease(TTObjectBaseHandle(&mAddressObserver));
	}
}

TTErr TTOutput::Send(const TTValue& inputValue, TTValue& outputValue)
{
	TTErr err;

    if (!mReturnSignalCallback)
        return kTTErrGeneric;

	if (mMute)
		err = kTTErrNone;

	else if (mFreeze) {

		err = mReturnSignalCallback->deliver(mLast);

		notifySignalObserver(mLast);
	}
	else {

		err = mReturnSignalCallback->deliver(inputValue);

		notifySignalObserver(inputValue);
	}

	// copy
	if (!mFreeze)
		mLast = inputValue;

	return err;
}

TTErr TTOutput::SendBypassed(const TTValue& inputValue, TTValue& outputValue)
{
	TTValue dummy;
	return Send(inputValue, dummy);
}

TTErr TTOutput::Link(const TTValue& inputValue, TTValue& outputValue)
{
	mInputObject = TTInputPtr((TTObjectBasePtr)inputValue[0]);

	if (mReturnLinkCallback)
		return mReturnLinkCallback->deliver(1);
	else
		return kTTErrNone;
}

TTErr TTOutput::Unlink()
{
	mInputObject = NULL;

	if (mReturnLinkCallback)
		return mReturnLinkCallback->deliver(0);
	else
		return kTTErrNone;
}

TTErr TTOutput::setInputAddress(const TTValue& value)
{
	TTValue			args;
	TTValuePtr		newBaton;
	TTAddress       newAddress;
	TTNodePtr		aNode;
	TTObjectBasePtr	o;
	TTValue			none, n = value;		// use new value to protect the attribute

	newAddress = value[0];

	if (!getLocalDirectory->getTTNode(newAddress, &aNode)) {

		o = aNode->getObject();
		if (o)
			if (o->getName() == kTTSym_Input|| o->getName() == kTTSym_InputAudio)
				Link(o, none);
	}

	if (!mAddressObserver) {

		// prepare arguments
		mAddressObserver = NULL; // without this, TTObjectBaseInstantiate try to release an oldObject that doesn't exist ... Is it good ?
		TTObjectBaseInstantiate(TTSymbol("callback"), TTObjectBaseHandle(&mAddressObserver), none);

		newBaton = new TTValue(TTObjectBasePtr(this));
		mAddressObserver->setAttributeValue(kTTSym_baton, TTPtr(newBaton));
		mAddressObserver->setAttributeValue(kTTSym_function, TTPtr(&TTOutputDirectoryCallback));
		mAddressObserver->setAttributeValue(TTSymbol("owner"), TTSymbol("TTOutput"));		// this is usefull only to debug
	}

	if (mAddressObserver) {
		if (mInputAddress != kTTAdrsEmpty)
			getLocalDirectory->removeObserverForNotifications(mInputAddress, mAddressObserver);

		getLocalDirectory->addObserverForNotifications(newAddress, mAddressObserver, 0); // ask for notification only for equal addresses
	}

	mInputAddress = newAddress;

	return kTTErrNone;
}

TTErr TTOutput::setMute(const TTValue& value)
{
	mMute = value;

	if (mGainUnit) {

		if (mMute)
			return mGainUnit->setAttributeValue(TTSymbol("linearGain"), 0.0);
		else
			return mGainUnit->setAttributeValue(TTSymbol("midiGain"), mGain);
	}

	return kTTErrNone;
}

TTErr TTOutput::setMix(const TTValue& value)
{
	mMix = value;

	if (mMixUnit)
		return mMixUnit->setAttributeValue(TTSymbol("position"), mMix * 0.01);

	return kTTErrNone;
}

TTErr TTOutput::Mix(const TTValue& inputValue, TTValue& outputValue)
{
    return setMix(inputValue);
}

TTErr TTOutput::setGain(const TTValue& value)
{
	mGain = value;

	if (mGainUnit)
		return mGainUnit->setAttributeValue(TTSymbol("midiGain"), mGain);

	return kTTErrNone;
}

TTErr TTOutput::notifySignalObserver(const TTValue& value)
{
	mSignal = value;

	mSignalAttr->sendNotification(kTTSym_notify, mSignal);	// we use kTTSym_notify because we know that observers are TTCallback

	return kTTErrNone;
}

#if 0
#pragma mark -
#pragma mark Some Methods
#endif

TTErr TTOutputDirectoryCallback(TTPtr baton, TTValue& data)
{
	TTValuePtr		b;
	TTOutputPtr		anOutput;
	TTSymbol		anAddress;
	TTNodePtr		aNode;
	TTUInt8			flag;
	TTObjectBasePtr		o;

	// unpack baton (an OutputPtr)
	b = (TTValuePtr)baton;
	anOutput = TTOutputPtr((TTObjectBasePtr)(*b)[0]);

	// Unpack data (anAddress, aNode, flag, anObserver)
	anAddress = data[0];
	aNode = TTNodePtr((TTPtr)data[1]);
	flag = data[2];

	o = aNode->getObject();
	if (o) {
		if (o->getName() == kTTSym_Input || o->getName() == kTTSym_InputAudio) {

			switch (flag) {

				case kAddressCreated :
				{
					TTValue unused;
					anOutput->Link(o, unused);
					break;
				}

				case kAddressDestroyed :
				{
					anOutput->Unlink();
					break;
				}

				default:
					break;
			}
		}
	}

	return kTTErrNone;
}
<|endoftext|>


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

#include <chainparams.h>
#include <compressor.h>
#include <core_io.h>
#include <core_memusage.h>
#include <policy/policy.h>
#include <pubkey.h>
#include <script/descriptor.h>
#include <script/script.h>
#include <script/sign.h>
#include <script/signingprovider.h>
#include <script/standard.h>
#include <streams.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <univalue.h>
#include <util/memory.h>

void initialize()
{
    // Fuzzers using pubkey must hold an ECCVerifyHandle.
    static const ECCVerifyHandle verify_handle;

    SelectParams(CBaseChainParams::REGTEST);
}

void test_one_input(const std::vector<uint8_t>& buffer)
{
    const CScript script(buffer.begin(), buffer.end());

    std::vector<unsigned char> compressed;
    if (CompressScript(script, compressed)) {
        const unsigned int size = compressed[0];
        compressed.erase(compressed.begin());
        assert(size >= 0 && size <= 5);
        CScript decompressed_script;
        const bool ok = DecompressScript(decompressed_script, size, compressed);
        assert(ok);
        assert(script == decompressed_script);
    }

    CTxDestination address;
    (void)ExtractDestination(script, address);

    txnouttype type_ret;
    std::vector<CTxDestination> addresses;
    int required_ret;
    (void)ExtractDestinations(script, type_ret, addresses, required_ret);

    (void)GetScriptForWitness(script);

    const FlatSigningProvider signing_provider;
    (void)InferDescriptor(script, signing_provider);

    (void)IsSegWitOutput(signing_provider, script);

    (void)IsSolvable(signing_provider, script);

    txnouttype which_type;
    (void)IsStandard(script, which_type);

    (void)RecursiveDynamicUsage(script);

    std::vector<std::vector<unsigned char>> solutions;
    (void)Solver(script, solutions);

    (void)script.HasValidOps();
    (void)script.IsPayToScriptHash();
    (void)script.IsPayToWitnessScriptHash();
    (void)script.IsPushOnly();
    (void)script.IsUnspendable();
    (void)script.GetSigOpCount(/* fAccurate= */ false);

    (void)FormatScript(script);
    (void)ScriptToAsmStr(script, false);
    (void)ScriptToAsmStr(script, true);

    UniValue o1(UniValue::VOBJ);
    ScriptPubKeyToUniv(script, o1, true);
    UniValue o2(UniValue::VOBJ);
    ScriptPubKeyToUniv(script, o2, false);
    UniValue o3(UniValue::VOBJ);
    ScriptToUniv(script, o3, true);
    UniValue o4(UniValue::VOBJ);
    ScriptToUniv(script, o4, false);

    {
        FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
        const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
        // DecompressScript(..., ..., bytes) is not guaranteed to be defined if bytes.size() <= 23.
        if (bytes.size() >= 24) {
            CScript decompressed_script;
            DecompressScript(decompressed_script, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), bytes);
        }
    }
}
<commit_msg>fuzz: Extend script fuzz test<commit_after>// Copyright (c) 2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <chainparams.h>
#include <compressor.h>
#include <core_io.h>
#include <core_memusage.h>
#include <policy/policy.h>
#include <pubkey.h>
#include <script/descriptor.h>
#include <script/interpreter.h>
#include <script/script.h>
#include <script/sign.h>
#include <script/signingprovider.h>
#include <script/standard.h>
#include <streams.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <univalue.h>
#include <util/memory.h>

void initialize()
{
    // Fuzzers using pubkey must hold an ECCVerifyHandle.
    static const ECCVerifyHandle verify_handle;

    SelectParams(CBaseChainParams::REGTEST);
}

void test_one_input(const std::vector<uint8_t>& buffer)
{
    FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
    const Optional<CScript> script_opt = ConsumeDeserializable<CScript>(fuzzed_data_provider);
    if (!script_opt) return;
    const CScript script{*script_opt};

    std::vector<unsigned char> compressed;
    if (CompressScript(script, compressed)) {
        const unsigned int size = compressed[0];
        compressed.erase(compressed.begin());
        assert(size >= 0 && size <= 5);
        CScript decompressed_script;
        const bool ok = DecompressScript(decompressed_script, size, compressed);
        assert(ok);
        assert(script == decompressed_script);
    }

    CTxDestination address;
    (void)ExtractDestination(script, address);

    txnouttype type_ret;
    std::vector<CTxDestination> addresses;
    int required_ret;
    (void)ExtractDestinations(script, type_ret, addresses, required_ret);

    (void)GetScriptForWitness(script);

    const FlatSigningProvider signing_provider;
    (void)InferDescriptor(script, signing_provider);

    (void)IsSegWitOutput(signing_provider, script);

    (void)IsSolvable(signing_provider, script);

    txnouttype which_type;
    (void)IsStandard(script, which_type);

    (void)RecursiveDynamicUsage(script);

    std::vector<std::vector<unsigned char>> solutions;
    (void)Solver(script, solutions);

    (void)script.HasValidOps();
    (void)script.IsPayToScriptHash();
    (void)script.IsPayToWitnessScriptHash();
    (void)script.IsPushOnly();
    (void)script.IsUnspendable();
    (void)script.GetSigOpCount(/* fAccurate= */ false);

    (void)FormatScript(script);
    (void)ScriptToAsmStr(script, false);
    (void)ScriptToAsmStr(script, true);

    UniValue o1(UniValue::VOBJ);
    ScriptPubKeyToUniv(script, o1, true);
    UniValue o2(UniValue::VOBJ);
    ScriptPubKeyToUniv(script, o2, false);
    UniValue o3(UniValue::VOBJ);
    ScriptToUniv(script, o3, true);
    UniValue o4(UniValue::VOBJ);
    ScriptToUniv(script, o4, false);

    {
        const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider);
        // DecompressScript(..., ..., bytes) is not guaranteed to be defined if the bytes vector is too short
        if (bytes.size() >= 32) {
            CScript decompressed_script;
            DecompressScript(decompressed_script, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), bytes);
        }
    }

    const Optional<CScript> other_script = ConsumeDeserializable<CScript>(fuzzed_data_provider);
    if (other_script) {
        {
            CScript script_mut{script};
            (void)FindAndDelete(script_mut, *other_script);
        }
        const std::vector<std::string> random_string_vector = ConsumeRandomLengthStringVector(fuzzed_data_provider);
        const uint32_t u32{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
        const uint32_t flags{u32 | SCRIPT_VERIFY_P2SH};
        {
            CScriptWitness wit;
            for (const auto& s : random_string_vector) {
                wit.stack.emplace_back(s.begin(), s.end());
            }
            (void)CountWitnessSigOps(script, *other_script, &wit, flags);
            wit.SetNull();
        }
    }
}
<|endoftext|>


<commit_before>#include "rgw_os_auth.h"
#include "rgw_rest.h"

#include "common/ceph_crypto.h"
#include "common/Clock.h"

#include "auth/Crypto.h"

using namespace ceph::crypto;

static RGW_OS_Auth_Get rgw_os_auth_get;

static int build_token(string& os_user, string& key, uint64_t nonce, utime_t& expiration, bufferlist& bl)
{
  ::encode(os_user, bl);
  ::encode(nonce, bl);
  ::encode(expiration, bl);

  bufferptr p(HMACSHA1::DIGESTSIZE);
  int len = p.length();

  char buf[bl.length() * 2 + 1];
  buf_to_hex((const unsigned char *)bl.c_str(), bl.length(), buf);
  RGW_LOG(0) << "bl=" << buf << std::endl;

  char k[HMACSHA1::DIGESTSIZE];
  memset(k, 0, sizeof(k));
  const char *s = key.c_str();
  for (int i = 0; i < (int)key.length(); i++, s++) {
    k[i % HMACSHA1::DIGESTSIZE] |= *s;
  }
  int ret = calc_hmac_sha1(k, sizeof(k), bl.c_str(), bl.length(),
                            p.c_str(), &len);
  if (ret < 0)
     return ret;

  if (len != HMACSHA1::DIGESTSIZE)
    return -EINVAL;

  bl.append(p);

  return 0;

}

static int encode_token(string& os_user, string& key, bufferlist& bl)
{
  uint64_t nonce;

  int ret = get_random_bytes((char *)&nonce, sizeof(nonce));
  if (ret < 0)
    return ret;

  utime_t expiration = g_clock.now();
  expiration += RGW_OS_TOKEN_EXPIRATION; // 15 minutes

  ret = build_token(os_user, key, nonce, expiration, bl);

  return ret;
}

int hexdigit(char c)
{
  if (c >= '0' && c <= '9')
    return (c - '0');
  c = toupper(c);
  if (c >= 'A' && c <= 'F')
    return c - 'A' + 0xa;
  return -EINVAL;
}

int hex_to_buf(const char *hex, char *buf, int len)
{
  int i = 0;
  const char *p = hex;
  while (*p) {
    if (i >= len)
      return -EINVAL;
    buf[i] = 0;
    int d = hexdigit(*p);
    if (d < 0)
      return d;
    buf[i] = d << 4;
    p++;
    if (!*p)
      return -EINVAL;
    d = hexdigit(*p);
    if (d < 0)
      return -d;
    buf[i] += d;
    i++;
    p++;
  }
  return i;
}

int rgw_os_verify_signed_token(const char *token, RGWUserInfo& info)
{
  if (strncmp(token, "AUTH_rgwtk", 10) != 0)
    return -EINVAL;

  token += 10;

  int len = strlen(token);
  if (len & 1) {
    RGW_LOG(0) << "invalid token length" << std::endl;
    return -EINVAL;
  }

  bufferptr p(len/2);
  int ret = hex_to_buf(token, p.c_str(), len);
  if (ret < 0)
    return ret;

  bufferlist bl;
  bl.append(p);

  bufferlist::iterator iter = bl.begin();

  uint64_t nonce;
  utime_t expiration;
  string os_user;
  string s3_user;

  try {
    ::decode(os_user, iter);
    ::decode(nonce, iter);
    ::decode(expiration, iter);
  } catch (buffer::error *err) {
    RGW_LOG(0) << "failed to decode token" << std::endl;
    return -EINVAL;
  }
  if (expiration < g_clock.now()) {
    RGW_LOG(0) << "old timed out token was used now=" << g_clock.now() << " token.expiration=" << expiration << std::endl;
    return -EPERM;
  }

  if ((ret = rgw_get_uid_by_openstack(os_user, s3_user, info)) < 0)
    return ret;

  RGW_LOG(0) << "os_user=" << os_user << std::endl;

  bufferlist tok;
  ret = build_token(os_user, info.openstack_key, nonce, expiration, tok);
  if (ret < 0)
    return ret;

  if (tok.length() != bl.length()) {
    RGW_LOG(0) << "tokens length mismatch: bl.length()=" << bl.length() << " tok.length()=" << tok.length() << std::endl;
    return -EPERM;
  }

  if (memcmp(tok.c_str(), bl.c_str(), tok.length()) != 0) {
    char buf[tok.length() * 2 + 1];
    buf_to_hex((const unsigned char *)tok.c_str(), tok.length(), buf);
    RGW_LOG(0) << "tokens mismatch tok=" << buf << std::endl;
    return -EPERM;
  }

  return 0;
}

void RGW_OS_Auth_Get::execute()
{
  int ret = -EPERM;

  RGW_LOG(0) << "RGW_OS_Auth_Get::execute()" << std::endl;

  const char *key = FCGX_GetParam("HTTP_X_AUTH_KEY", s->fcgx->envp);
  const char *user = FCGX_GetParam("HTTP_X_AUTH_USER", s->fcgx->envp);
  const char *url_prefix = FCGX_GetParam("RGW_OPENSTACK_URL_PREFIX", s->fcgx->envp);
  const char *os_url = FCGX_GetParam("RGW_OPENSTACK_URL", s->fcgx->envp);

  string user_str = user;
  string user_id;
  RGWUserInfo info;
  bufferlist bl;

  if (!key || !user)
    goto done;

  if ((ret = rgw_get_uid_by_openstack(user_str, user_id, info)) < 0)
    goto done;

  if (info.openstack_key.compare(key) != 0) {
    RGW_LOG(0) << "RGW_OS_Auth_Get::execute(): bad openstack key" << std::endl;
    ret = -EPERM;
    goto done;
  }

  CGI_PRINTF(s, "X-Storage-Url: %s/%s/v1\n", os_url, url_prefix);

  if ((ret = encode_token(info.openstack_name, info.openstack_key, bl)) < 0)
    goto done;

  {
    char buf[bl.length() * 2 + 1];
    buf_to_hex((const unsigned char *)bl.c_str(), bl.length(), buf);

    CGI_PRINTF(s, "X-Storage-Token: AUTH_rgwtk%s\n", buf);
  }

  ret = 204;

done:
  dump_errno(s, ret);
  end_header(s);

}

bool RGWHandler_OS_Auth::authorize(struct req_state *s)
{
  return true;
}

RGWOp *RGWHandler_OS_Auth::get_op()
{
  RGWOp *op;
  switch (s->op) {
   case OP_GET:
     op = &rgw_os_auth_get;
     break;
   default:
     return NULL;
  }

  if (op) {
    op->init(s);
  }
  return op;
}

<commit_msg>rgw: generated swift urls are more compatble with openstack<commit_after>#include "rgw_os_auth.h"
#include "rgw_rest.h"

#include "common/ceph_crypto.h"
#include "common/Clock.h"

#include "auth/Crypto.h"

using namespace ceph::crypto;

static RGW_OS_Auth_Get rgw_os_auth_get;

static int build_token(string& os_user, string& key, uint64_t nonce, utime_t& expiration, bufferlist& bl)
{
  ::encode(os_user, bl);
  ::encode(nonce, bl);
  ::encode(expiration, bl);

  bufferptr p(HMACSHA1::DIGESTSIZE);
  int len = p.length();

  char buf[bl.length() * 2 + 1];
  buf_to_hex((const unsigned char *)bl.c_str(), bl.length(), buf);
  RGW_LOG(0) << "bl=" << buf << std::endl;

  char k[HMACSHA1::DIGESTSIZE];
  memset(k, 0, sizeof(k));
  const char *s = key.c_str();
  for (int i = 0; i < (int)key.length(); i++, s++) {
    k[i % HMACSHA1::DIGESTSIZE] |= *s;
  }
  int ret = calc_hmac_sha1(k, sizeof(k), bl.c_str(), bl.length(),
                            p.c_str(), &len);
  if (ret < 0)
     return ret;

  if (len != HMACSHA1::DIGESTSIZE)
    return -EINVAL;

  bl.append(p);

  return 0;

}

static int encode_token(string& os_user, string& key, bufferlist& bl)
{
  uint64_t nonce;

  int ret = get_random_bytes((char *)&nonce, sizeof(nonce));
  if (ret < 0)
    return ret;

  utime_t expiration = g_clock.now();
  expiration += RGW_OS_TOKEN_EXPIRATION; // 15 minutes

  ret = build_token(os_user, key, nonce, expiration, bl);

  return ret;
}

int hexdigit(char c)
{
  if (c >= '0' && c <= '9')
    return (c - '0');
  c = toupper(c);
  if (c >= 'A' && c <= 'F')
    return c - 'A' + 0xa;
  return -EINVAL;
}

int hex_to_buf(const char *hex, char *buf, int len)
{
  int i = 0;
  const char *p = hex;
  while (*p) {
    if (i >= len)
      return -EINVAL;
    buf[i] = 0;
    int d = hexdigit(*p);
    if (d < 0)
      return d;
    buf[i] = d << 4;
    p++;
    if (!*p)
      return -EINVAL;
    d = hexdigit(*p);
    if (d < 0)
      return -d;
    buf[i] += d;
    i++;
    p++;
  }
  return i;
}

int rgw_os_verify_signed_token(const char *token, RGWUserInfo& info)
{
  if (strncmp(token, "AUTH_rgwtk", 10) != 0)
    return -EINVAL;

  token += 10;

  int len = strlen(token);
  if (len & 1) {
    RGW_LOG(0) << "invalid token length" << std::endl;
    return -EINVAL;
  }

  bufferptr p(len/2);
  int ret = hex_to_buf(token, p.c_str(), len);
  if (ret < 0)
    return ret;

  bufferlist bl;
  bl.append(p);

  bufferlist::iterator iter = bl.begin();

  uint64_t nonce;
  utime_t expiration;
  string os_user;
  string s3_user;

  try {
    ::decode(os_user, iter);
    ::decode(nonce, iter);
    ::decode(expiration, iter);
  } catch (buffer::error *err) {
    RGW_LOG(0) << "failed to decode token" << std::endl;
    return -EINVAL;
  }
  if (expiration < g_clock.now()) {
    RGW_LOG(0) << "old timed out token was used now=" << g_clock.now() << " token.expiration=" << expiration << std::endl;
    return -EPERM;
  }

  if ((ret = rgw_get_uid_by_openstack(os_user, s3_user, info)) < 0)
    return ret;

  RGW_LOG(0) << "os_user=" << os_user << std::endl;

  bufferlist tok;
  ret = build_token(os_user, info.openstack_key, nonce, expiration, tok);
  if (ret < 0)
    return ret;

  if (tok.length() != bl.length()) {
    RGW_LOG(0) << "tokens length mismatch: bl.length()=" << bl.length() << " tok.length()=" << tok.length() << std::endl;
    return -EPERM;
  }

  if (memcmp(tok.c_str(), bl.c_str(), tok.length()) != 0) {
    char buf[tok.length() * 2 + 1];
    buf_to_hex((const unsigned char *)tok.c_str(), tok.length(), buf);
    RGW_LOG(0) << "tokens mismatch tok=" << buf << std::endl;
    return -EPERM;
  }

  return 0;
}

void RGW_OS_Auth_Get::execute()
{
  int ret = -EPERM;

  RGW_LOG(0) << "RGW_OS_Auth_Get::execute()" << std::endl;

  const char *key = FCGX_GetParam("HTTP_X_AUTH_KEY", s->fcgx->envp);
  const char *user = FCGX_GetParam("HTTP_X_AUTH_USER", s->fcgx->envp);
  const char *url_prefix = FCGX_GetParam("RGW_OPENSTACK_URL_PREFIX", s->fcgx->envp);
  const char *os_url = FCGX_GetParam("RGW_OPENSTACK_URL", s->fcgx->envp);

  string user_str = user;
  string user_id;
  RGWUserInfo info;
  bufferlist bl;

  if (!os_url || !url_prefix) {
    RGW_LOG(0) << "server is misconfigured, missing RGW_OPENSTACK_URL_PREFIX or RGW_OPENSTACK_URL" << std::endl;
    ret = -EINVAL;
    goto done;
  }

  if (!key || !user)
    goto done;

  if ((ret = rgw_get_uid_by_openstack(user_str, user_id, info)) < 0)
    goto done;

  if (info.openstack_key.compare(key) != 0) {
    RGW_LOG(0) << "RGW_OS_Auth_Get::execute(): bad openstack key" << std::endl;
    ret = -EPERM;
    goto done;
  }

  CGI_PRINTF(s, "X-Storage-Url: %s/%s/v1/AUTH_rgw\n", os_url, url_prefix);

  if ((ret = encode_token(info.openstack_name, info.openstack_key, bl)) < 0)
    goto done;

  {
    char buf[bl.length() * 2 + 1];
    buf_to_hex((const unsigned char *)bl.c_str(), bl.length(), buf);

    CGI_PRINTF(s, "X-Storage-Token: AUTH_rgwtk%s\n", buf);
  }

  ret = 204;

done:
  dump_errno(s, ret);
  end_header(s);

}

bool RGWHandler_OS_Auth::authorize(struct req_state *s)
{
  return true;
}

RGWOp *RGWHandler_OS_Auth::get_op()
{
  RGWOp *op;
  switch (s->op) {
   case OP_GET:
     op = &rgw_os_auth_get;
     break;
   default:
     return NULL;
  }

  if (op) {
    op->init(s);
  }
  return op;
}

<|endoftext|>


<commit_before>#include <fstream>
#include <iostream>
#include <sstream>
#include <unordered_map>
#ifdef __linux__
 #include <cstdlib>
 #include <unistd.h>
#endif
#ifdef _WIN32
 #include <Windows.h>
#endif
#include "utils.h"

#define MAX_PATH_LEN 8192

static std::unordered_map<std::string, std::string> configs = {
	{ "8ball", "/extra8ballresponses" },
	{ "giveaway-settings", "/giveaway/giveaway-settings" },
	{ "giveaway", "/giveaway/giveaway" },
	{ "recurring", "/recurring" },
	{ "settings", "/settings" },
	{ "submessage", "/submessage" },
	{ "whitelist", "/whitelist" }
};

bool utils::startsWith(const std::string &str, const std::string &prefix)
{
	return str.find(prefix) == 0;
}

bool utils::endsWith(const std::string &str, const std::string &suffix)
{
	return str.find(suffix) == str.length() - suffix.length();
}

std::vector<std::string> &utils::split(const std::string &str, char delim, std::vector<std::string> &elems)
{
	std::stringstream ss(str);
	std::string item;
	while (std::getline(ss, item, delim)) {
		if (!item.empty())
			elems.push_back(item);
	}
	return elems;
}

std::string utils::formatInteger(std::string integer)
{
	int pos = integer.length() - 3;
	if (pos < 1)
		return integer;
	while (pos > 0) {
		integer.insert(pos, ",");
		pos -= 3;
	}
	return integer;
}

#ifdef _WIN32
static std::string configdir_win()
{
	char buf[MAX_PATH_LEN];
	int bytes;
	if ((bytes = GetModuleFileName(NULL, buf, sizeof(buf))) == 0) {
		std::cerr << "could not get current directory" << std::endl;
		return "";
	}

	/* strip filename from path */
	std::string path(buf);
	path = path.substr(0, path.find_last_of("\\"));

	return path;
}
#endif

#ifdef __linux__
static std::string configdir_unix()
{
	char *h;
	if (!(h= getenv("HOME"))) {
		std::cerr << "could not read $HOME" << std::endl;
		return "";
	}
	return std::string(h) + "/.lynxbot";
}
#endif

std::string utils::configdir()
{
#ifdef __linux__
	return configdir_unix();
#endif
#ifdef _WIN32
	return configdir_win();
#endif
}

std::string utils::config(const std::string &cfg)
{
	std::string path = "";
	if (configs.find(cfg) != configs.end()) {
		path += configs[cfg];
#ifdef _WIN32
		path += ".txt";
#endif
	}
	return path;
}

bool utils::readJSON(const std::string &filename, Json::Value &val)
{
	Json::Reader reader;
	std::ifstream fileStream(configdir() + "/json/" + filename,
		std::ifstream::binary);

	if (!reader.parse(fileStream, val)) {
		std::cerr << reader.getFormattedErrorMessages() << std::endl;
		return false;
	}
	return true;
}
<commit_msg>Windows path fix<commit_after>#include <fstream>
#include <iostream>
#include <sstream>
#include <unordered_map>
#ifdef __linux__
 #include <cstdlib>
 #include <unistd.h>
#endif
#ifdef _WIN32
 #include <Windows.h>
#endif
#include "utils.h"

#define MAX_PATH_LEN 8192

static std::unordered_map<std::string, std::string> configs = {
	{ "8ball", "/extra8ballresponses" },
	{ "giveaway-settings", "/giveaway/giveaway-settings" },
	{ "giveaway", "/giveaway/giveaway" },
	{ "recurring", "/recurring" },
	{ "settings", "/settings" },
	{ "submessage", "/submessage" },
	{ "whitelist", "/whitelist" }
};

bool utils::startsWith(const std::string &str, const std::string &prefix)
{
	return str.find(prefix) == 0;
}

bool utils::endsWith(const std::string &str, const std::string &suffix)
{
	return str.find(suffix) == str.length() - suffix.length();
}

std::vector<std::string> &utils::split(const std::string &str, char delim, std::vector<std::string> &elems)
{
	std::stringstream ss(str);
	std::string item;
	while (std::getline(ss, item, delim)) {
		if (!item.empty())
			elems.push_back(item);
	}
	return elems;
}

std::string utils::formatInteger(std::string integer)
{
	int pos = integer.length() - 3;
	if (pos < 1)
		return integer;
	while (pos > 0) {
		integer.insert(pos, ",");
		pos -= 3;
	}
	return integer;
}

#ifdef _WIN32
static std::string configdir_win()
{
	char buf[MAX_PATH_LEN];
	int bytes;
	if ((bytes = GetModuleFileName(NULL, buf, sizeof(buf))) == 0) {
		std::cerr << "could not get current directory" << std::endl;
		return "";
	}

	/* strip filename from path */
	std::string path(buf);
	path = path.substr(0, path.find_last_of("\\"));

	return path;
}
#endif

#ifdef __linux__
static std::string configdir_unix()
{
	char *h;
	if (!(h= getenv("HOME"))) {
		std::cerr << "could not read $HOME" << std::endl;
		return "";
	}
	return std::string(h) + "/.lynxbot";
}
#endif

std::string utils::configdir()
{
#ifdef __linux__
	return configdir_unix();
#endif
#ifdef _WIN32
	return configdir_win();
#endif
}

std::string utils::config(const std::string &cfg)
{
	std::string path = "";
	if (configs.find(cfg) != configs.end()) {
		path += configs[cfg];
#ifdef _WIN32
		std::replace(path.begin(), path.end(), '/', '\\');
		path += ".txt";
#endif
	}
	return path;
}

bool utils::readJSON(const std::string &filename, Json::Value &val)
{
	Json::Reader reader;
	std::ifstream fileStream(configdir() + "/json/" + filename,
		std::ifstream::binary);

	if (!reader.parse(fileStream, val)) {
		std::cerr << reader.getFormattedErrorMessages() << std::endl;
		return false;
	}
	return true;
}
<|endoftext|>


<commit_before>#include <iostream>

class Base
{
	public:
	~Base(){}
	virtual	void DoSomething() const {}
	virtual	void DoSomethingElse() const {}
};

template <class TInterface>
class VirtualWrapper_A : public virtual TInterface { protected: ~VirtualWrapper_A(){} };

template <class TInterface>
class VirtualWrapper_B : public virtual TInterface { protected: ~VirtualWrapper_B(){} };

template <class TInterface>
class Wrapper_A : public TInterface { protected: ~Wrapper_A(){} };

template <class TInterface>
class Wrapper_B : public TInterface { protected: ~Wrapper_B(){} };

class VirtualDerived : public VirtualWrapper_A<Base>, public VirtualWrapper_B<Base> {};

class NestedDerived : public VirtualWrapper_A<VirtualWrapper_B<Base>> {};

int main(int argc, char* argv[])
{
	VirtualDerived vd;
	vd.DoSomething();

	NestedDerived nd;
	nd.DoSomething();

	std::cout << "sizeof(Base) " << sizeof(Base) << std::endl;
	std::cout << "sizeof(VirtualDerived) " << sizeof(vd) << std::endl;
	std::cout << "sizeof(NestedDerived) " << sizeof(nd) << std::endl;
}

<commit_msg>Print size of different implementation strategies<commit_after>#include <iostream>

struct DataForBase
{
	int m_base;
	std::string m_baseName;
};

struct DataForA
{
	int m_a;
	std::string m_aName;
};

struct DataForB
{
	int m_b;
	std::string m_bName;
};

struct DataForC
{
	int m_c;
};

class Interface
{
	public:

		virtual ~Interface(){}

		virtual	void DoBase() const = 0 ;

		virtual	void DoA() const = 0;

		virtual	void DoB() const = 0;

		virtual	void DoC() const = 0;
};

template <class TInterface>
class VirtualWrapper_A : public virtual TInterface
{
	private:
		DataForA m_aData;

	protected:
		~VirtualWrapper_A(){}

	public:
		virtual void DoA() const {}
};

template <class TInterface>
class VirtualWrapper_B : public virtual TInterface
{
	private:
		DataForB m_bData;

	protected:
		~VirtualWrapper_B(){}

	public:
		virtual void DoB() const {}
};

template <class TInterface>
class VirtualWrapper_C : public virtual TInterface
{
	private:
		DataForC m_cData;

	protected:
		~VirtualWrapper_C(){}

	public:
		virtual void DoC() const {}
};

template <class TInterface>
class Wrapper_A : public TInterface
{
	private:
		DataForA m_aData;

	protected:
		~Wrapper_A(){}

	public:
		virtual void DoA() const {}
};

template <class TInterface>
class Wrapper_B : public TInterface
{
	private:
		DataForB m_bData;

	protected:
		~Wrapper_B(){}

	public:
		virtual void DoB() const {}
};

template <class TInterface>
class Wrapper_C : public TInterface
{
	private:
		DataForC m_cData;

	protected:
		~Wrapper_C(){}

	public:
		virtual void DoC() const {}
};

class VirtualDerived : public VirtualWrapper_A<Interface>, public VirtualWrapper_B<Interface>, public VirtualWrapper_C<Interface>
{
	private:
		DataForBase m_baseData;

	public:
		virtual void DoBase() const {};
};

class NestedDerived : public VirtualWrapper_A<VirtualWrapper_B<VirtualWrapper_C<Interface>>>
{
	private:
		DataForBase m_baseData;

	public:
		virtual void DoBase() const {};
};

class DelegateBase
{
	DataForBase m_base;
	public:
	virtual void DoBase() const {}
};

class DelegateA
{
	DataForA m_base;
	public:
	virtual void DoA() const {}
};

class DelegateB
{
	DataForB m_base;
	public:
	virtual void DoB() const {}
};

class DelegateC
{
	DataForC m_base;
	public:
	virtual void DoC() const {}
};

class DelegatingImpl : public Interface
{
	private:
		DelegateBase m_dBase;
		DelegateA m_dA;
		DelegateB m_dB;
		DelegateC m_dC;

	public:
		virtual void DoBase() const { m_dBase.DoBase(); }
		virtual void DoA() const { m_dA.DoA(); }
		virtual void DoB() const { m_dB.DoB(); }
		virtual void DoC() const { m_dC.DoC(); }
};

class RawImpl : public Interface
{
	private:
		DataForBase m_baseData;
		DataForA m_aData;
		DataForB m_bData;
		DataForC m_cData;

	public:
		virtual void DoBase() const {}
		virtual void DoA() const {}
		virtual void DoB() const {}
		virtual void DoC() const {}
};

int main(int argc, char* argv[])
{
	VirtualDerived vd;
	vd.DoBase();
	vd.DoA();
	vd.DoB();
	vd.DoC();

	NestedDerived nd;
	nd.DoBase();
	nd.DoA();
	nd.DoB();
	nd.DoC();

	DelegatingImpl di;
	di.DoBase();
	di.DoA();
	di.DoB();
	di.DoC();

	RawImpl ri;
	ri.DoBase();
	ri.DoA();
	ri.DoB();
	ri.DoC();

	std::cout << "sizeof(DataForBase) " << sizeof(DataForBase) << std::endl;
	std::cout << "sizeof(DataForA) " << sizeof(DataForA) << std::endl;
	std::cout << "sizeof(DataForB) " << sizeof(DataForB) << std::endl;
	std::cout << "sizeof(Interface) " << sizeof(Interface) << std::endl;
	std::cout << "sizeof(RawImpl) " << sizeof(RawImpl) << std::endl;
	std::cout << "sizeof(DelegatingImpl) " << sizeof(DelegatingImpl) << std::endl;
	std::cout << "sizeof(VirtualDerived) " << sizeof(VirtualDerived) << std::endl;
	std::cout << "sizeof(NestedDerived) " << sizeof(NestedDerived) << std::endl;
	std::cout << "sizeof(void*) " << sizeof(void*) << std::endl;
}

<|endoftext|>


<commit_before>/*
===============================================================================

  FILE    laszippertest.cpp

  CONTENTS

    This tool reads and writes point data in the LAS 1.X format compressed
    or uncompressed to test the laszipper and lasunzipper interfaces.

  PROGRAMMERS:

    martin.isenburg@gmail.com

  COPYRIGHT:

    (c) 2010-2011, Martin Isenburg, LASSO - tools to catch reality

    This is free software; you can redistribute and/or modify it under the
    terms of the GNU Lesser General Licence as published by the Free Software
    Foundation. See the COPYING file for more information.

    This software is distributed WITHOUT ANY WARRANTY and without even the
    implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

  CHANGE HISTORY:

    14 January 2011 -- mpg@flaxen.com adds randomness and commandline controls
    10 January 2011 -- licensing change for LGPL release and liblas integration
    13 December 2010 -- created to test the remodularized laszip compressor

===============================================================================
*/

#include "laszipper.hpp"
#include "lasunzipper.hpp"

#ifdef LZ_WIN32_VC6
#include <fstream.h>
#else
#include <istream>
#include <fstream>
using namespace std;
#endif

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

//---------------------------------------------------------------------------

static double taketime()
{
  return (double)(clock())/CLOCKS_PER_SEC;
}

//---------------------------------------------------------------------------
// abstractions for doing I/O, which support VC6 streams, modern streams, and FILE*

class OStream
{
public:
  OStream(bool use_iostream, const char* filename) :
    m_use_iostream(use_iostream),
    m_filename(filename),
    ofile(NULL),
    streamo(NULL)
  {
    if (m_use_iostream)
    {
#ifdef LZ_WIN32_VC6
      ofb.open(filename, ios::out);
      ofb.setmode(filebuf::binary);
      streamo = new ostream(&ofb);
#else
      streamo = new ofstream();
      streamo->open(filename, std::ios::out | std::ios::binary );
#endif
    }
    else
    {
      ofile = fopen(filename, "wb");
    }
  };

  ~OStream()
  {
    if (m_use_iostream)
    {
      delete streamo;
#ifdef LZ_WIN32_VC6
      ofb.close();
#endif
    }
    else
    {
      if (ofile)
        fclose(ofile);
    }
  };

  bool m_use_iostream;
  const char* m_filename;
  FILE* ofile;
  filebuf ofb;
#ifdef LZ_WIN32_VC6
  ostream* streamo;
#else
  ofstream* streamo;
#endif
};

//---------------------------------------------------------------------------

struct IStream
{
public:
  IStream(bool use_iostream, const char* filename) :
    m_use_iostream(use_iostream),
    m_filename(filename),
    ifile(NULL),
    streami(NULL)
  {
    if (m_use_iostream)
    {
#ifdef LZ_WIN32_VC6
      ifb.open(filename, ios::in);
      ifb.setmode(filebuf::binary);
      streami = new istream(&ifb);
#else
      streami = new ifstream();
      streami->open(filename, std::ios::in | std::ios::binary);
#endif
    }
    else
    {
      ifile = fopen(filename, "rb");
    }
  };

  ~IStream()
  {
    if (m_use_iostream)
    {
      delete streami;
#ifdef LZ_WIN32_VC6
      ifb.close();
#endif
    }
    else
    {
      if (ifile)
        fclose(ifile);
    }
  };

  bool m_use_iostream;
  const char* m_filename;
  FILE* ifile;
  filebuf ifb;
#ifdef LZ_WIN32_VC6
  istream* streami;
#else
  ifstream* streami;
#endif
};

//---------------------------------------------------------------------------

class PointData
{
public:
  PointData(unsigned char type=5, unsigned short size=70)
  {
    point_type = type;
    point_size = size;
    point = 0;
    point_data = 0;
  }

  bool PointData::setup(unsigned int num_items, const LASitem* items)
  {
    unsigned int offset = 0;
    if (point) delete [] point;
    point = new unsigned char*[num_items];
    if (point_data) delete [] point_data;
    point_data = new unsigned char[point_size];
    for (unsigned int i = 0; i < num_items; i++)
    {
      point[i] = &(point_data[offset]);
      offset += items[i].size;
    }
    return (offset == point_size);
  }

  ~PointData()
  {
    if (point) delete [] point;
    if (point_data) delete [] point_data;
  }

  unsigned char point_type;
  unsigned short point_size;
  unsigned char** point;
  unsigned char* point_data;
};

//---------------------------------------------------------------------------

class Settings
{
public:
  Settings(unsigned int num_pts, bool random, bool use_stream) :
    num_points(num_pts),
    use_random(random),
    use_iostream(use_stream)
  {
    logfile = fopen("zippertest.log","w");
    return;
  }

  ~Settings()
  {
    fclose(logfile);
    return;
  }

  unsigned num_points;
  bool use_random;
  unsigned int seed;
  bool use_iostream;
  FILE* logfile;
};

static Settings* settings = NULL; // singleton

//---------------------------------------------------------------------------

static void log(const char* format, ...)
{
  va_list args;

  va_start(args, format);
  vfprintf(stderr, format, args);
  va_end(args);
  fflush(stderr);

  va_start(args, format);
  vfprintf(settings->logfile, format, args);
  va_end(args);
  fflush(settings->logfile);

  return;
}

//---------------------------------------------------------------------------

static LASzipper* make_zipper(LASzip* laszip)
{
  LASzipper* zipper = new LASzipper();
  int stat = zipper->setup(laszip);
  if (stat != 0)
  {
    log("ERROR: could not make laszipper\n");
    exit(1);
  }
  return zipper;
}

//---------------------------------------------------------------------------

static void open_zipper(LASzipper* zipper, OStream* ost)
{
  int stat = 0;
  if (ost->m_use_iostream)
    stat = zipper->open(*ost->streamo);
  else
    stat = zipper->open(ost->ofile);
  if (stat != 0)
  {
    log("ERROR: could not open laszipper with %s\n", ost->m_filename);
    exit(1);
  }
}

//---------------------------------------------------------------------------

static LASunzipper* make_unzipper(const LASzip* laszip)
{
  LASunzipper* unzipper = new LASunzipper();
  int stat = unzipper->setup(laszip);
  if (stat != 0)
  {
    log("ERROR: could not make lasunzipper\n");
    exit(1);
  }
  return unzipper;
}

//---------------------------------------------------------------------------

static void open_unzipper(LASunzipper* unzipper, IStream* ist)
{
  int stat = 0;
  if (ist->m_use_iostream)
    stat = unzipper->open(*ist->streami);
  else
    stat = unzipper->open(ist->ifile);
  if (stat != 0)
  {
    log("ERROR: could not open laszipper with %s\n", ist->m_filename);
    exit(1);
  }
}

//---------------------------------------------------------------------------

static void write_points(LASzipper* zipper, PointData& data)
{
  if (zipper==NULL) // range coder test
    return;

  double start_time, end_time;
  unsigned char c;
  unsigned int i,j;
  unsigned int num_bytes;

  // the two branches of this IF are the same, except for the use of a random number;
  // we keep the random case separate, so that we can get fastest timing tests w/o random data
  if (settings->use_random)
  {
    srand(settings->seed);
    start_time = taketime();
    c = rand() % 256;
    for (i = 0; i < settings->num_points; i++)
    {
      for (j = 0; j < data.point_size; j++)
      {
        data.point_data[j] = c;
        c = rand() % 256;
      }
      zipper->write(data.point);
    }
    num_bytes = zipper->close();
    end_time = taketime();
  }
  else
  {
    start_time = taketime();
    c = 0;
    for (i = 0; i < settings->num_points; i++)
    {
      for (j = 0; j < data.point_size; j++)
      {
        data.point_data[j] = c;
        c++;
      }
      zipper->write(data.point);
    }
    num_bytes = zipper->close();
    end_time = taketime();
  }

  log("laszipper wrote %u bytes in %g seconds\n", num_bytes, end_time-start_time);

  return;
}

//---------------------------------------------------------------------------

static void read_points(LASunzipper* unzipper, PointData& data)
{
  if (unzipper==NULL) // range coder test
    return;

  unsigned char c;
  unsigned int i,j;
  unsigned int num_errors, num_bytes;
  double start_time, end_time;

  start_time = taketime();
  num_errors = 0;

  if (settings->use_random)
  {
    srand(settings->seed);
    c = rand() % 256;
    for (i = 0; i < settings->num_points; i++)
    {
      unzipper->read(data.point);
      for (j = 0; j < data.point_size; j++)
      {
        if (data.point_data[j] != c)
        {
          log("%d %d %d != %d\n", i, j, data.point_data[j], c);
          num_errors++;
          if (num_errors > 20) break;
        }
        c = rand() % 256;
      }
      if (num_errors > 20) break;
    }
    num_bytes = unzipper->close();
    end_time = taketime();
  }
  else
  {
    c = 0;
    for (i = 0; i < settings->num_points; i++)
    {
      unzipper->read(data.point);
      for (j = 0; j < data.point_size; j++)
      {
        if (data.point_data[j] != c)
        {
          log("%d %d %d != %d\n", i, j, data.point_data[j], c);
          num_errors++;
          if (num_errors > 20) break;
        }
        c++;
      }
      if (num_errors > 20) break;
    }
    num_bytes = unzipper->close();
    end_time = taketime();
  }

  if (num_errors)
  {
    log("ERROR: with lasunzipper %d\n", num_errors);
    getc(stdin);
  }
  else
  {
    log("SUCCESS: lasunzipper read %u bytes in %g seconds\n", num_bytes, end_time-start_time);
  }

  return;
}

//---------------------------------------------------------------------------

static void run_test(const char* filename, PointData& data, unsigned short compressor, unsigned short requested_version=0, unsigned short chunk_size=0)
{
  LASzip laszip;
  laszip.setup(data.point_type, data.point_size, compressor);
  data.setup(laszip.num_items, laszip.items);
  if (requested_version) laszip.request_version(requested_version);
  if (chunk_size) laszip.set_chunk_size(chunk_size);

  LASzipper* laszipper = make_zipper(&laszip);
  // only now (that the version numbers were set) can we pack laszip
  unsigned char* bytes;
  int num;
  laszip.pack(bytes, num);
  OStream* ost = new OStream(settings->use_iostream, filename);
  open_zipper(laszipper, ost);
  write_points(laszipper, data);
  delete laszipper;
  delete ost;

  // copy VLR to laszip
  LASzip laszip_dec;
  laszip_dec.unpack(bytes, num);
  data.setup(laszip_dec.num_items, laszip_dec.items);
  LASunzipper* lasunzipper = make_unzipper(&laszip_dec);
  IStream* ist = new IStream(settings->use_iostream, filename);
  open_unzipper(lasunzipper, ist);
  read_points(lasunzipper, data);
  delete lasunzipper;
  delete ist;

  return;
}

//---------------------------------------------------------------------------

int main(int argc, char *argv[])
{
  unsigned int num_points = 100000;
  bool use_iostream = false;
  bool run_forever = false;
  bool use_random = false;
  unsigned int user_seed = (unsigned int)time(NULL);

  for (int i=1; i<argc; i++)
  {
    const char* p = argv[i];
    if (strcmp(p,"-n")==0)
    {
      ++i;
      num_points = atoi(argv[i]);
    }
    else if (strcmp(p,"-s")==0)
    {
      use_iostream = true;
    }
    else if (strcmp(p,"-f")==0)
    {
      run_forever = true;
    }
    else if (strcmp(p,"-r")==0)
    {
      use_random = true;
    }
    else if (strcmp(p,"-x")==0)
    {
      ++i;
      user_seed = atoi(argv[i]);
    }
    else
    {
      fprintf(stderr, "Usage   ziptest [-n NUMBER] [-s] [-f] [-r]\n");
      fprintf(stderr, "   -n    number of points to process (default   100000)\n");
      fprintf(stderr, "   -s    use C++ stream I/O (default   use FILE* I/O)\n");
      fprintf(stderr, "   -f    run forever (default   run just one pass)\n");
      fprintf(stderr, "   -r    use random input data (default   use fixed data)\n");
      fprintf(stderr, "   -x    set random seed, instead of current time (default: use time)\n");
      exit(1);
    }
  }

  settings = new Settings(num_points, use_random, use_iostream);

  log("Settings:\n");
  log("  num_points=%u, use_iostream=%s, run_forever=%s, use_random=%s, user_seed=%d\n",
    num_points, use_iostream?"true":"false", run_forever?"true":"false", use_random?"true":"false", user_seed);

  settings->seed = user_seed;

  unsigned int run = 1;
  do
  {
  PointData data;

  // use a seed based on the current time
  if (run_forever && settings->use_random)
  {
    settings->seed = (unsigned int)time(NULL);
    log("Seed: %u\n", settings->seed);
  }

  run_test("test1.lax", data, LASZIP_COMPRESSOR_NONE);
  run_test("test2.lax", data, LASZIP_COMPRESSOR_DEFAULT);
  run_test("test3.lax", data, LASZIP_COMPRESSOR_DEFAULT, 2);
  run_test("test4.lax", data, LASZIP_COMPRESSOR_CHUNKED);
  run_test("test5.lax", data, LASZIP_COMPRESSOR_CHUNKED, 2);
  log("Finished %u runs\n\n", run);
  ++run;
  } while (run_forever);

  return 0;
}
<commit_msg>further clean-up and commenting<commit_after>/*
===============================================================================

  FILE    laszippertest.cpp

  CONTENTS

    This tool reads and writes point data in the LAS 1.X format compressed
    or uncompressed to test the laszipper and lasunzipper interfaces.

  PROGRAMMERS:

    martin.isenburg@gmail.com

  COPYRIGHT:

    (c) 2010-2011, Martin Isenburg, LASSO - tools to catch reality

    This is free software; you can redistribute and/or modify it under the
    terms of the GNU Lesser General Licence as published by the Free Software
    Foundation. See the COPYING file for more information.

    This software is distributed WITHOUT ANY WARRANTY and without even the
    implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

  CHANGE HISTORY:

    14 January 2011 -- mpg@flaxen.com adds randomness and commandline controls
    10 January 2011 -- licensing change for LGPL release and liblas integration
    13 December 2010 -- created to test the remodularized laszip compressor

===============================================================================
*/

#include "laszipper.hpp"
#include "lasunzipper.hpp"

#ifdef LZ_WIN32_VC6
#include <fstream.h>
#else
#include <istream>
#include <fstream>
using namespace std;
#endif

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

//---------------------------------------------------------------------------

static double taketime()
{
  return (double)(clock())/CLOCKS_PER_SEC;
}

//---------------------------------------------------------------------------
// abstractions for doing I/O, which support VC6 streams, modern streams, and FILE*

class OStream
{
public:
  OStream(bool use_iostream, const char* filename) :
    m_use_iostream(use_iostream),
    m_filename(filename),
    ofile(NULL),
    streamo(NULL)
  {
    if (m_use_iostream)
    {
#ifdef LZ_WIN32_VC6
      ofb.open(filename, ios::out);
      ofb.setmode(filebuf::binary);
      streamo = new ostream(&ofb);
#else
      streamo = new ofstream();
      streamo->open(filename, std::ios::out | std::ios::binary );
#endif
    }
    else
    {
      ofile = fopen(filename, "wb");
    }
  };

  ~OStream()
  {
    if (m_use_iostream)
    {
      delete streamo;
#ifdef LZ_WIN32_VC6
      ofb.close();
#endif
    }
    else
    {
      if (ofile)
        fclose(ofile);
    }
  };

  bool m_use_iostream;
  const char* m_filename;
  FILE* ofile;
  filebuf ofb;
#ifdef LZ_WIN32_VC6
  ostream* streamo;
#else
  ofstream* streamo;
#endif
};

//---------------------------------------------------------------------------

struct IStream
{
public:
  IStream(bool use_iostream, const char* filename) :
    m_use_iostream(use_iostream),
    m_filename(filename),
    ifile(NULL),
    streami(NULL)
  {
    if (m_use_iostream)
    {
#ifdef LZ_WIN32_VC6
      ifb.open(filename, ios::in);
      ifb.setmode(filebuf::binary);
      streami = new istream(&ifb);
#else
      streami = new ifstream();
      streami->open(filename, std::ios::in | std::ios::binary);
#endif
    }
    else
    {
      ifile = fopen(filename, "rb");
    }
  };

  ~IStream()
  {
    if (m_use_iostream)
    {
      delete streami;
#ifdef LZ_WIN32_VC6
      ifb.close();
#endif
    }
    else
    {
      if (ifile)
        fclose(ifile);
    }
  };

  bool m_use_iostream;
  const char* m_filename;
  FILE* ifile;
  filebuf ifb;
#ifdef LZ_WIN32_VC6
  istream* streami;
#else
  ifstream* streami;
#endif
};

//---------------------------------------------------------------------------

class PointData
{
public:
  PointData(unsigned char type=5, unsigned short size=70)
  {
    point_type = type;
    point_size = size;
    point = 0;
    point_data = 0;
  }

  bool PointData::setup(unsigned int num_items, const LASitem* items)
  {
    unsigned int offset = 0;
    if (point) delete [] point;
    point = new unsigned char*[num_items];
    if (point_data) delete [] point_data;
    point_data = new unsigned char[point_size];
    for (unsigned int i = 0; i < num_items; i++)
    {
      point[i] = &(point_data[offset]);
      offset += items[i].size;
    }
    return (offset == point_size);
  }

  ~PointData()
  {
    if (point) delete [] point;
    if (point_data) delete [] point_data;
  }

  unsigned char point_type;
  unsigned short point_size;
  unsigned char** point;
  unsigned char* point_data;
};

//---------------------------------------------------------------------------

class Settings
{
public:
  Settings(unsigned int num_pts, bool random, bool use_stream) :
    num_points(num_pts),
    use_random(random),
    use_iostream(use_stream)
  {
    logfile = fopen("zippertest.log","w");
    return;
  }

  ~Settings()
  {
    fclose(logfile);
    return;
  }

  unsigned num_points;
  bool use_random;
  unsigned int seed;
  bool use_iostream;
  FILE* logfile;
};

static Settings* settings = NULL; // singleton

//---------------------------------------------------------------------------

static void log(const char* format, ...)
{
  va_list args;

  va_start(args, format);
  vfprintf(stderr, format, args);
  va_end(args);
  fflush(stderr);

  va_start(args, format);
  vfprintf(settings->logfile, format, args);
  va_end(args);
  fflush(settings->logfile);

  return;
}

//---------------------------------------------------------------------------

static LASzipper* make_zipper(OStream* ost, const LASzip* laszip)
{
  LASzipper* zipper = new LASzipper();
  if (zipper == 0)
  {
    log("ERROR: could not make laszipper\n");
    exit(1);
  }
  int stat = 0;
  if (ost->m_use_iostream)
    stat = zipper->open(*ost->streamo, laszip);
  else
    stat = zipper->open(ost->ofile, laszip);
  if (stat != 0)
  {
    log("ERROR: could not open laszipper with %s\n", ost->m_filename);
    exit(1);
  }
  return zipper;
}

//---------------------------------------------------------------------------

static LASunzipper* make_unzipper(IStream* ist, const LASzip* laszip)
{
  LASunzipper* unzipper = new LASunzipper();
  if (unzipper == 0)
  {
    log("ERROR: could not make lasunzipper\n");
    exit(1);
  }
  int stat = 0;
  if (ist->m_use_iostream)
    stat = unzipper->open(*ist->streami, laszip);
  else
    stat = unzipper->open(ist->ifile, laszip);
  if (stat != 0)
  {
    log("ERROR: could not open laszipper with %s\n", ist->m_filename);
    exit(1);
  }
  return unzipper;
}

//---------------------------------------------------------------------------

static void write_points(LASzipper* zipper, PointData& data)
{
  if (zipper==NULL) // range coder test
    return;

  double start_time, end_time;
  unsigned char c;
  unsigned int i,j;
  unsigned int num_bytes;

  // the two branches of this IF are the same, except for the use of a random number;
  // we keep the random case separate, so that we can get fastest timing tests w/o random data
  if (settings->use_random)
  {
    srand(settings->seed);
    start_time = taketime();
    c = rand() % 256;
    for (i = 0; i < settings->num_points; i++)
    {
      for (j = 0; j < data.point_size; j++)
      {
        data.point_data[j] = c;
        c = rand() % 256;
      }
      zipper->write(data.point);
    }
    num_bytes = zipper->close();
    end_time = taketime();
  }
  else
  {
    start_time = taketime();
    c = 0;
    for (i = 0; i < settings->num_points; i++)
    {
      for (j = 0; j < data.point_size; j++)
      {
        data.point_data[j] = c;
        c++;
      }
      zipper->write(data.point);
    }
    num_bytes = zipper->close();
    end_time = taketime();
  }

  log("laszipper wrote %u bytes in %g seconds\n", num_bytes, end_time-start_time);

  return;
}

//---------------------------------------------------------------------------

static void read_points(LASunzipper* unzipper, PointData& data)
{
  if (unzipper==NULL) // range coder test
    return;

  unsigned char c;
  unsigned int i,j;
  unsigned int num_errors, num_bytes;
  double start_time, end_time;

  start_time = taketime();
  num_errors = 0;

  if (settings->use_random)
  {
    srand(settings->seed);
    c = rand() % 256;
    for (i = 0; i < settings->num_points; i++)
    {
      unzipper->read(data.point);
      for (j = 0; j < data.point_size; j++)
      {
        if (data.point_data[j] != c)
        {
          log("%d %d %d != %d\n", i, j, data.point_data[j], c);
          num_errors++;
          if (num_errors > 20) break;
        }
        c = rand() % 256;
      }
      if (num_errors > 20) break;
    }
    num_bytes = unzipper->close();
    end_time = taketime();
  }
  else
  {
    c = 0;
    for (i = 0; i < settings->num_points; i++)
    {
      unzipper->read(data.point);
      for (j = 0; j < data.point_size; j++)
      {
        if (data.point_data[j] != c)
        {
          log("%d %d %d != %d\n", i, j, data.point_data[j], c);
          num_errors++;
          if (num_errors > 20) break;
        }
        c++;
      }
      if (num_errors > 20) break;
    }
    num_bytes = unzipper->close();
    end_time = taketime();
  }

  if (num_errors)
  {
    log("ERROR: with lasunzipper %d\n", num_errors);
    getc(stdin);
  }
  else
  {
    log("SUCCESS: lasunzipper read %u bytes in %g seconds\n", num_bytes, end_time-start_time);
  }

  return;
}

//---------------------------------------------------------------------------

static void run_test(const char* filename, PointData& data, unsigned short compressor, unsigned short requested_version=0, int chunk_size=-1)
{
  //
  // COMPRESSION
  //

  // setting up LASzip parameters
  LASzip laszip;
  laszip.setup(data.point_type, data.point_size, compressor);
  if (requested_version > 0) laszip.request_version(requested_version);
  if (chunk_size > -1) laszip.set_chunk_size((unsigned int)chunk_size);

  // packing up LASzip
  unsigned char* bytes;
  int num;
  laszip.pack(bytes, num);

  // creating the output stream
  OStream* ost = new OStream(settings->use_iostream, filename);

  // creating the zipper
  LASzipper* laszipper = make_zipper(ost, &laszip);

  // allocating the data to read from
  data.setup(laszip.num_items, laszip.items);

  // writing the points
  write_points(laszipper, data);

  // cleaning up
  delete laszipper;
  delete ost;

  //
  // DECOMPRESSION
  //

  // setting up LASzip parameters
  LASzip laszip_dec;
  laszip_dec.unpack(bytes, num);

  // creating the input stream
  IStream* ist = new IStream(settings->use_iostream, filename);

  // creating the zipper
  LASunzipper* lasunzipper = make_unzipper(ist, &laszip_dec);

  // allocating the data to write into
  data.setup(laszip_dec.num_items, laszip_dec.items);

  // reading the points
  read_points(lasunzipper, data);

  // cleaning up
  delete lasunzipper;
  delete ist;

  return;
}

//---------------------------------------------------------------------------

int main(int argc, char *argv[])
{
  unsigned int num_points = 100000;
  bool use_iostream = false;
  bool run_forever = false;
  bool use_random = false;
  unsigned int user_seed = (unsigned int)time(NULL);

  for (int i=1; i<argc; i++)
  {
    const char* p = argv[i];
    if (strcmp(p,"-n")==0)
    {
      ++i;
      num_points = atoi(argv[i]);
    }
    else if (strcmp(p,"-s")==0)
    {
      use_iostream = true;
    }
    else if (strcmp(p,"-f")==0)
    {
      run_forever = true;
    }
    else if (strcmp(p,"-r")==0)
    {
      use_random = true;
    }
    else if (strcmp(p,"-x")==0)
    {
      ++i;
      user_seed = atoi(argv[i]);
    }
    else
    {
      fprintf(stderr, "Usage   ziptest [-n NUMBER] [-s] [-f] [-r]\n");
      fprintf(stderr, "   -n    number of points to process (default   100000)\n");
      fprintf(stderr, "   -s    use C++ stream I/O (default   use FILE* I/O)\n");
      fprintf(stderr, "   -f    run forever (default   run just one pass)\n");
      fprintf(stderr, "   -r    use random input data (default   use fixed data)\n");
      fprintf(stderr, "   -x    set random seed, instead of current time (default: use time)\n");
      exit(1);
    }
  }

  settings = new Settings(num_points, use_random, use_iostream);

  log("Settings:\n");
  log("  num_points=%u, use_iostream=%s, run_forever=%s, use_random=%s, user_seed=%d\n",
    num_points, use_iostream?"true":"false", run_forever?"true":"false", use_random?"true":"false", user_seed);

  settings->seed = user_seed;

  unsigned int run = 1;
  do
  {
  PointData data;

  // use a seed based on the current time
  if (run_forever && settings->use_random)
  {
    settings->seed = (unsigned int)time(NULL);
    log("Seed: %u\n", settings->seed);
  }

  run_test("test1.lax", data, LASZIP_COMPRESSOR_NONE);
  run_test("test2.lax", data, LASZIP_COMPRESSOR_DEFAULT);
  run_test("test3.lax", data, LASZIP_COMPRESSOR_DEFAULT, 2);
  run_test("test4.lax", data, LASZIP_COMPRESSOR_CHUNKED);
  run_test("test5.lax", data, LASZIP_COMPRESSOR_CHUNKED, 2);
  log("Finished %u runs\n\n", run);
  ++run;
  } while (run_forever);

  return 0;
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <ctype.h>
#include <unistd.h>

#include <opencv2/opencv.hpp>

#include <AprilTags/apriltag.h>
#include <AprilTags/common/image_u8.h>
#include <AprilTags/tag36h11.h>
#include <AprilTags/common/zarray.h>
#include <AprilTags/common/getopt.h>

#include <drc_utils/LcmWrapper.hpp>
#include <drc_utils/BotWrapper.hpp>
#include <lcm/lcm-cpp.hpp>

#include <lcmtypes/drc/robot_state_t.hpp>
#include <lcmtypes/bot_core/images_t.hpp>
#include <lcmtypes/bot_core/image_t.hpp>

#include <bot_core/camtrans.h>
#include <bot_param/param_util.h>

#include <vector>
#include <iostream>

#include <Eigen/Dense>

struct TagMatch {
    cv::Point2d p0, p1, p2, p3;
    Eigen::Matrix3d H;
};

class AprilTagDetector {
    public:
    AprilTagDetector(getopt_t *options) : getopt(options) {
        tf = tag36h11_create();
        tf->black_border = getopt_get_int(options, "border");
        td = apriltag_detector_create();
        apriltag_detector_add_family(td, tf);

        td->quad_decimate = getopt_get_double(getopt, "decimate");
        td->quad_sigma = getopt_get_double(getopt, "blur");
        td->nthreads = getopt_get_int(getopt, "threads");
        td->debug = getopt_get_bool(getopt, "debug");
        td->refine_edges = getopt_get_bool(getopt, "refine-edges");
        td->refine_decode = getopt_get_bool(getopt, "refine-decode");
        td->refine_pose = getopt_get_bool(getopt, "refine-pose");

        quiet = getopt_get_bool(getopt, "quiet");
    }

    ~AprilTagDetector() {

        apriltag_detector_destroy(td);
        tag36h11_destroy(tf);
    }

    std::vector<TagMatch> detectTags(image_u8_t *im) {

        const int hamm_hist_max = 10;

        int hamm_hist[hamm_hist_max];
        memset(hamm_hist, 0, sizeof(hamm_hist));
        //image_u8_t *im = image_u8_create_from_pnm(path);

        zarray_t *detections = apriltag_detector_detect(td, im);

        std::vector<TagMatch> tag_matches;
        for (int i = 0; i < zarray_size(detections); i++) {
            apriltag_detection_t *det;
            zarray_get(detections, i, &det);

            if (!quiet)
                printf("detection %3d: id (%2dx%2d)-%-4d, hamming %d, goodness %8.3f, margin %8.3f\n",
                       i, det->family->d*det->family->d, det->family->h, det->id, det->hamming, det->goodness, det->decision_margin);

            for (int x = 0; x < 3 ; x++) {
                image_u8_draw_line(im, det->p[x][0], det->p[x][1], det->p[x+1][0], det->p[x+1][1], 255, 10);
            }
            TagMatch tag_match;
            tag_match.p0 = cv::Point2d(det->p[0][0], det->p[0][1]);
            tag_match.p1 = cv::Point2d(det->p[1][0], det->p[1][1]);
            tag_match.p2 = cv::Point2d(det->p[2][0], det->p[2][1]);
            tag_match.p3 = cv::Point2d(det->p[3][0], det->p[3][1]);
            Eigen::Map<Eigen::Matrix3d> H_map(det->H->data);
            tag_match.H = H_map.transpose();
            tag_matches.push_back(tag_match);
            hamm_hist[det->hamming]++;
        }

        apriltag_detections_destroy(detections);

        if (!quiet) {
            timeprofile_display(td->tp);
            printf("nedges: %d, nsegments: %d, nquads: %d\n", td->nedges, td->nsegments, td->nquads);
            printf("Hamming histogram: ");
            for (int i = 0; i < hamm_hist_max; i++)
                printf("%5d", hamm_hist[i]);
            printf("%12.3f", timeprofile_total_utime(td->tp) / 1.0E3);
            printf("\n");
        }

        return tag_matches;
    }
    private:
    int quiet;
    apriltag_family_t *tf;
    apriltag_detector_t *td;
    getopt_t *getopt;
};

class CameraListener {
    public:

    void setDetector(AprilTagDetector* detector) {
        mDetector = detector;
    }

    bool setup() {
        mBotWrapper.reset(new drc::BotWrapper());
        mLcmWrapper.reset(new drc::LcmWrapper(mBotWrapper->getLcm()));
        mLcmWrapper->get()->subscribe("CAMERA", &CameraListener::onCamera, this);

        if (mBotWrapper->getBotParam() == nullptr) {
            printf("Couldn't get bot params\n");
            return false;
        }

        mCamTransLeft = bot_param_get_new_camtrans(mBotWrapper->getBotParam(),"CAMERA_LEFT");
        std::cout << bot_camtrans_get_width(mCamTransLeft) << std::endl;
        std::cout << bot_camtrans_get_height(mCamTransLeft) << std::endl;
        std::cout << bot_camtrans_get_focal_length_x(mCamTransLeft) << std::endl;
        std::cout << bot_camtrans_get_focal_length_y(mCamTransLeft) << std::endl;
        std::cout << bot_camtrans_get_principal_x(mCamTransLeft) << std::endl;
        std::cout << bot_camtrans_get_principal_y(mCamTransLeft) << std::endl;

        return true;
    }

    void start() {
        mLcmWrapper->startHandleThread(true);
    }

    void onCamera(const lcm::ReceiveBuffer* buffer, const std::string& channel,
                const bot_core::images_t* msg) {
        cv::Mat image;
        decodeImage(msg, image);
        image_u8_t *image_u8 = fromCvMat(image);

        std::vector<TagMatch> tags = mDetector->detectTags(image_u8);
        cv::cvtColor(image, image, CV_GRAY2RGB);
        for (int i = 0; i < tags.size(); i++) {

            cv::line(image, tags[i].p0, tags[i].p1, cv::Scalar(255,0,0), 2, CV_AA);
            cv::line(image, tags[i].p1, tags[i].p2, cv::Scalar(0,255,0), 2, CV_AA);
            cv::line(image, tags[i].p2, tags[i].p3, cv::Scalar(0,0,255), 2, CV_AA);
            cv::line(image, tags[i].p3, tags[i].p0, cv::Scalar(0,0,255), 2, CV_AA);

            Eigen::Vector3d x_axis(2,0,1);
            Eigen::Vector3d y_axis(0,2,1);
            Eigen::Vector3d origin(0,0,1);

            Eigen::Vector3d px = tags[i].H * x_axis;
            Eigen::Vector3d py = tags[i].H * y_axis;
            Eigen::Vector3d o  = tags[i].H * origin;

            px/= px[2];
            py/= py[2];
            o/= o[2];

            cv::line(image, cv::Point2d(o[0], o[1]), cv::Point2d(px[0], px[1]), cv::Scalar(255,0,255), 1, CV_AA);
            cv::line(image, cv::Point2d(o[0], o[1]), cv::Point2d(py[0], py[1]), cv::Scalar(255,255,0), 1, CV_AA);
        }
        cv::imshow("detections", image);
        cv::waitKey(1);
        image_u8_destroy(image_u8);
    }

    void decodeImage(const bot_core::images_t* msg, cv::Mat & decoded_image) {
        bot_core::image_t* leftImage = NULL;
        for (int i = 0; i < msg->n_images; ++i) {
          if (msg->image_types[i] == bot_core::images_t::LEFT) {
            leftImage = (bot_core::image_t*)(&msg->images[i]);
            decoded_image = leftImage->pixelformat == leftImage->PIXEL_FORMAT_MJPEG ?
                cv::imdecode(cv::Mat(leftImage->data), -1) :
                cv::Mat(leftImage->height, leftImage->width, CV_8UC1, leftImage->data.data());
                if (decoded_image.channels() > 1) {
                    cv::cvtColor(decoded_image, decoded_image, CV_RGB2GRAY);
                }
                break;
          }
        }
    }

    image_u8_t *fromCvMat(const cv::Mat & img) {
        image_u8_t *image_u8 = image_u8_create_alignment(img.cols, img.rows, img.step);
        int size = img.total() * img.elemSize();
        memcpy(image_u8->buf, img.data, size * sizeof(uint8_t));
        return image_u8;
    }

    private:
    AprilTagDetector *mDetector;
    drc::LcmWrapper::Ptr mLcmWrapper;
    drc::BotWrapper::Ptr mBotWrapper;
    BotCamTrans* mCamTransLeft;
};

int main(int argc, char *argv[])
{
    getopt_t *getopt = getopt_create();

    getopt_add_bool(getopt, 'h', "help", 0, "Show this help");
    getopt_add_bool(getopt, 'd', "debug", 0, "Enable debugging output (slow)");
    getopt_add_bool(getopt, 'q', "quiet", 0, "Reduce output");
    getopt_add_int(getopt, '\0', "border", "1", "Set tag family border size");
    getopt_add_int(getopt, 't', "threads", "4", "Use this many CPU threads");
    getopt_add_double(getopt, 'x', "decimate", "1.0", "Decimate input image by this factor");
    getopt_add_double(getopt, 'b', "blur", "0.0", "Apply low-pass blur to input");
    getopt_add_bool(getopt, '0', "refine-edges", 1, "Spend more time trying to align edges of tags");
    getopt_add_bool(getopt, '1', "refine-decode", 0, "Spend more time trying to decode tags");
    getopt_add_bool(getopt, '2', "refine-pose", 0, "Spend more time trying to precisely localize tags");

    if (!getopt_parse(getopt, argc, argv, 1) || getopt_get_bool(getopt, "help")) {
        printf("Usage: %s [options]\n", argv[0]);
        getopt_do_usage(getopt);
        exit(0);
    }

    AprilTagDetector tag_detector(getopt);
    CameraListener camera_listener;

    if (camera_listener.setup()) {
        camera_listener.setDetector(&tag_detector);
        camera_listener.start();
    }

    return 0;
}
<commit_msg>added camera K matrix and its inverse<commit_after>#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <ctype.h>
#include <unistd.h>

#include <opencv2/opencv.hpp>

#include <AprilTags/apriltag.h>
#include <AprilTags/common/image_u8.h>
#include <AprilTags/tag36h11.h>
#include <AprilTags/common/zarray.h>
#include <AprilTags/common/getopt.h>

#include <drc_utils/LcmWrapper.hpp>
#include <drc_utils/BotWrapper.hpp>
#include <lcm/lcm-cpp.hpp>

#include <lcmtypes/drc/robot_state_t.hpp>
#include <lcmtypes/bot_core/images_t.hpp>
#include <lcmtypes/bot_core/image_t.hpp>

#include <bot_core/camtrans.h>
#include <bot_param/param_util.h>

#include <vector>
#include <iostream>

#include <Eigen/Dense>

struct TagMatch {
    cv::Point2d p0, p1, p2, p3;
    Eigen::Matrix3d H;
};

class AprilTagDetector {
    public:
    AprilTagDetector(getopt_t *options) : getopt(options) {
        tf = tag36h11_create();
        tf->black_border = getopt_get_int(options, "border");
        td = apriltag_detector_create();
        apriltag_detector_add_family(td, tf);

        td->quad_decimate = getopt_get_double(getopt, "decimate");
        td->quad_sigma = getopt_get_double(getopt, "blur");
        td->nthreads = getopt_get_int(getopt, "threads");
        td->debug = getopt_get_bool(getopt, "debug");
        td->refine_edges = getopt_get_bool(getopt, "refine-edges");
        td->refine_decode = getopt_get_bool(getopt, "refine-decode");
        td->refine_pose = getopt_get_bool(getopt, "refine-pose");

        quiet = getopt_get_bool(getopt, "quiet");
    }

    ~AprilTagDetector() {

        apriltag_detector_destroy(td);
        tag36h11_destroy(tf);
    }

    std::vector<TagMatch> detectTags(image_u8_t *im) {

        const int hamm_hist_max = 10;

        int hamm_hist[hamm_hist_max];
        memset(hamm_hist, 0, sizeof(hamm_hist));
        //image_u8_t *im = image_u8_create_from_pnm(path);

        zarray_t *detections = apriltag_detector_detect(td, im);

        std::vector<TagMatch> tag_matches;
        for (int i = 0; i < zarray_size(detections); i++) {
            apriltag_detection_t *det;
            zarray_get(detections, i, &det);

            if (!quiet)
                printf("detection %3d: id (%2dx%2d)-%-4d, hamming %d, goodness %8.3f, margin %8.3f\n",
                       i, det->family->d*det->family->d, det->family->h, det->id, det->hamming, det->goodness, det->decision_margin);

            for (int x = 0; x < 3 ; x++) {
                image_u8_draw_line(im, det->p[x][0], det->p[x][1], det->p[x+1][0], det->p[x+1][1], 255, 10);
            }
            TagMatch tag_match;
            tag_match.p0 = cv::Point2d(det->p[0][0], det->p[0][1]);
            tag_match.p1 = cv::Point2d(det->p[1][0], det->p[1][1]);
            tag_match.p2 = cv::Point2d(det->p[2][0], det->p[2][1]);
            tag_match.p3 = cv::Point2d(det->p[3][0], det->p[3][1]);
            Eigen::Map<Eigen::Matrix3d> H_map(det->H->data);
            tag_match.H = H_map.transpose();
            tag_matches.push_back(tag_match);
            hamm_hist[det->hamming]++;
        }

        apriltag_detections_destroy(detections);

        if (!quiet) {
            timeprofile_display(td->tp);
            printf("nedges: %d, nsegments: %d, nquads: %d\n", td->nedges, td->nsegments, td->nquads);
            printf("Hamming histogram: ");
            for (int i = 0; i < hamm_hist_max; i++)
                printf("%5d", hamm_hist[i]);
            printf("%12.3f", timeprofile_total_utime(td->tp) / 1.0E3);
            printf("\n");
        }

        return tag_matches;
    }
    private:
    int quiet;
    apriltag_family_t *tf;
    apriltag_detector_t *td;
    getopt_t *getopt;
};

class CameraListener {
    public:

    void setDetector(AprilTagDetector* detector) {
        mDetector = detector;
    }

    bool setup() {
        mBotWrapper.reset(new drc::BotWrapper());
        mLcmWrapper.reset(new drc::LcmWrapper(mBotWrapper->getLcm()));
        mLcmWrapper->get()->subscribe("CAMERA", &CameraListener::onCamera, this);

        if (mBotWrapper->getBotParam() == nullptr) {
            printf("Couldn't get bot params\n");
            return false;
        }

        mCamTransLeft = bot_param_get_new_camtrans(mBotWrapper->getBotParam(),"CAMERA_LEFT");

        K = Eigen::Matrix3d::Identity();

        K(0,0) = bot_camtrans_get_focal_length_x(mCamTransLeft);
        K(1,1) = bot_camtrans_get_focal_length_y(mCamTransLeft);
        K(0,2) = bot_camtrans_get_principal_x(mCamTransLeft);
        K(1,2) = bot_camtrans_get_principal_y(mCamTransLeft);

        std::cout << K << std::endl;
        Kinv = K.inverse();
        std::cout << Kinv << std::endl;

        return true;
    }

    void start() {
        mLcmWrapper->startHandleThread(true);
    }

    void onCamera(const lcm::ReceiveBuffer* buffer, const std::string& channel,
                const bot_core::images_t* msg) {
        cv::Mat image;
        decodeImage(msg, image);
        image_u8_t *image_u8 = fromCvMat(image);

        std::vector<TagMatch> tags = mDetector->detectTags(image_u8);
        cv::cvtColor(image, image, CV_GRAY2RGB);
        for (int i = 0; i < tags.size(); i++) {

            cv::line(image, tags[i].p0, tags[i].p1, cv::Scalar(255,0,0), 2, CV_AA);
            cv::line(image, tags[i].p1, tags[i].p2, cv::Scalar(0,255,0), 2, CV_AA);
            cv::line(image, tags[i].p2, tags[i].p3, cv::Scalar(0,0,255), 2, CV_AA);
            cv::line(image, tags[i].p3, tags[i].p0, cv::Scalar(0,0,255), 2, CV_AA);

            Eigen::Vector3d x_axis(2,0,1);
            Eigen::Vector3d y_axis(0,2,1);
            Eigen::Vector3d origin(0,0,1);

            Eigen::Vector3d px = tags[i].H * x_axis;
            Eigen::Vector3d py = tags[i].H * y_axis;
            Eigen::Vector3d o  = tags[i].H * origin;

            px/= px[2];
            py/= py[2];
            o/= o[2];

            cv::line(image, cv::Point2d(o[0], o[1]), cv::Point2d(px[0], px[1]), cv::Scalar(255,0,255), 1, CV_AA);
            cv::line(image, cv::Point2d(o[0], o[1]), cv::Point2d(py[0], py[1]), cv::Scalar(255,255,0), 1, CV_AA);
        }
        cv::imshow("detections", image);
        cv::waitKey(1);
        image_u8_destroy(image_u8);
    }

    void decodeImage(const bot_core::images_t* msg, cv::Mat & decoded_image) {
        bot_core::image_t* leftImage = NULL;
        for (int i = 0; i < msg->n_images; ++i) {
          if (msg->image_types[i] == bot_core::images_t::LEFT) {
            leftImage = (bot_core::image_t*)(&msg->images[i]);
            decoded_image = leftImage->pixelformat == leftImage->PIXEL_FORMAT_MJPEG ?
                cv::imdecode(cv::Mat(leftImage->data), -1) :
                cv::Mat(leftImage->height, leftImage->width, CV_8UC1, leftImage->data.data());
                if (decoded_image.channels() > 1) {
                    cv::cvtColor(decoded_image, decoded_image, CV_RGB2GRAY);
                }
                break;
          }
        }
    }

    image_u8_t *fromCvMat(const cv::Mat & img) {
        image_u8_t *image_u8 = image_u8_create_alignment(img.cols, img.rows, img.step);
        int size = img.total() * img.elemSize();
        memcpy(image_u8->buf, img.data, size * sizeof(uint8_t));
        return image_u8;
    }

    private:
    AprilTagDetector *mDetector;
    drc::LcmWrapper::Ptr mLcmWrapper;
    drc::BotWrapper::Ptr mBotWrapper;
    BotCamTrans* mCamTransLeft;
    Eigen::Matrix3d K;
    Eigen::Matrix3d Kinv;

};

int main(int argc, char *argv[])
{
    getopt_t *getopt = getopt_create();

    getopt_add_bool(getopt, 'h', "help", 0, "Show this help");
    getopt_add_bool(getopt, 'd', "debug", 0, "Enable debugging output (slow)");
    getopt_add_bool(getopt, 'q', "quiet", 0, "Reduce output");
    getopt_add_int(getopt, '\0', "border", "1", "Set tag family border size");
    getopt_add_int(getopt, 't', "threads", "4", "Use this many CPU threads");
    getopt_add_double(getopt, 'x', "decimate", "1.0", "Decimate input image by this factor");
    getopt_add_double(getopt, 'b', "blur", "0.0", "Apply low-pass blur to input");
    getopt_add_bool(getopt, '0', "refine-edges", 1, "Spend more time trying to align edges of tags");
    getopt_add_bool(getopt, '1', "refine-decode", 0, "Spend more time trying to decode tags");
    getopt_add_bool(getopt, '2', "refine-pose", 0, "Spend more time trying to precisely localize tags");

    if (!getopt_parse(getopt, argc, argv, 1) || getopt_get_bool(getopt, "help")) {
        printf("Usage: %s [options]\n", argv[0]);
        getopt_do_usage(getopt);
        exit(0);
    }

    AprilTagDetector tag_detector(getopt);
    CameraListener camera_listener;

    if (camera_listener.setup()) {
        camera_listener.setDetector(&tag_detector);
        camera_listener.start();
    }

    return 0;
}
<|endoftext|>