<commit_before>#include "SerpentEncryptor.h"
using Kryptan::Core::Internal::SerpentEncryptor;
using Kryptan::Core::Internal::EncryptionKey;
using Kryptan::Core::SecureString;

#include "Exceptions.h"
using Kryptan::Core::KryptanBaseException;

//#define OS_RNG_AVAILABLE

#ifdef OS_RNG_AVAILABLE
# include <cryptopp/osrng.h>
using CryptoPP::AutoSeededRandomPool;
#else
# include <cryptopp/randpool.h>
  using CryptoPP::RandomPool;
# ifdef _WIN32

# endif
#endif

#include <cryptopp/gcm.h>
using CryptoPP::GCM;

#include <cryptopp/serpent.h>
using CryptoPP::Serpent;

#include <cryptopp/secblock.h>
using CryptoPP::SecByteBlock;

#include <cryptopp/filters.h>
using CryptoPP::StringSink;
using CryptoPP::StringSource;
using CryptoPP::AuthenticatedEncryptionFilter;
using CryptoPP::AuthenticatedDecryptionFilter;
using CryptoPP::BufferedTransformation;
using CryptoPP::AAD_CHANNEL;
using CryptoPP::DEFAULT_CHANNEL;

#include <cryptopp/base64.h>
using CryptoPP::Base64Encoder;
using CryptoPP::Base64Decoder;

#include <cryptopp/sha.h>
using CryptoPP::SHA512;
#include <cryptopp/sha3.h>
//using CryptoPP::SHA3_512;
#include <cryptopp/pwdbased.h>
using CryptoPP::PKCS5_PBKDF2_HMAC;

//while developing
//using namespace CryptoPP;

#define MAGIC_VALUE "KRYPTAN\n"

const int TAG_SIZE = 16; //bytes
const int IV_SIZE = 16; //bytes
typedef SHA512 KEY_CHECK_HASH_FUNCTION;
const int KEY_CHECK_LENGTH = KEY_CHECK_HASH_FUNCTION::DIGESTSIZE;
const int MIN_ITERATION_COUNT = 2 ^ 10;
const int TARGET_ITERATION_TIME = 2; //seconds
const int SALT_SIZE = 16; //bytes
typedef uint32_t iter_t;

RandomPool* getPrng()
{
#ifdef OS_RNG_AVAILABLE
    static AutoSeededRandomPool g_prng;
#else
    static RandomPool g_prng;
    static bool inited = false;
    if (!inited)
    {
        const int SEED_LEN = 32;
        byte seed[SEED_LEN];
#ifdef _WIN32
        //RtlGenRandom(seed, SEED_LEN);
        //TODO: FIX THIS!
#else
#error Requires cryptographically secure seed
#endif
        g_prng.IncorporateEntropy(seed, SEED_LEN);
        inited = true;
    }

#endif
    return &g_prng;
}

//
class EncryptionKeyImpl : public EncryptionKey
{
private:
    SecByteBlock xor1;
    SecByteBlock xor2;
    int keyLength;
    iter_t createdWithNumberOfIterations;
public:
    EncryptionKeyImpl(byte* kData, int kLength, byte* sData, int sLength, iter_t nIterations)
    {
        keyLength = kLength;
        xor1.Grow(kLength + sLength);
        xor2.Grow(kLength + sLength);
        createdWithNumberOfIterations = nIterations;

        //fill with random data
        getPrng()->GenerateBlock(xor1, kLength + sLength);

        //put key data into storage
        for (int i = 0; i < kLength; i++)
        {
            xor2[i] = kData[i] ^ xor1[i];
        }

        //put salt data into storage
        for (int i = 0; i < sLength; i++)
        {
            xor2[kLength + i] = sData[i] ^ xor1[kLength + i];
        }
    }

    SecByteBlock getDataCopy()
    {
        SecByteBlock data(keyLength);
        for (int i = 0; i < keyLength; i++)
        {
            data[i] = xor1[i] ^ xor2[i];
        }
        return data;
    }

    SecByteBlock getSaltCopy()
    {
        int saltLength = xor1.size() - keyLength;
        SecByteBlock data(saltLength);
        for (int i = 0; i < saltLength; i++)
        {
            data[i] = xor1[keyLength + i] ^ xor2[keyLength + i];
        }
        return data;
    }

    iter_t getNumberOfIterations()
    {
        return createdWithNumberOfIterations;
    }

    ~EncryptionKeyImpl()
    {
        //clean xor1 and xor2
        xor1.CleanNew(0);
        xor2.CleanNew(0);
    }
};

SerpentEncryptor::SerpentEncryptor()
{
};

SerpentEncryptor::~SerpentEncryptor()
{
};

EncryptionKeyImpl* generateKeyFromPassphrase_p(SecureString passphrase, SecByteBlock salt, iter_t iterations = 0)
{

    SecByteBlock derived_key(Serpent::DEFAULT_KEYLENGTH);

    double target_iteration_time = TARGET_ITERATION_TIME;
    iter_t iteration_count = MIN_ITERATION_COUNT;

    if (iterations > 0)
    {
        target_iteration_time = 0;
        iteration_count = iterations;
    }

    PKCS5_PBKDF2_HMAC<SHA512> pbkdf2;
    iter_t actualIterationCount = pbkdf2.DeriveKey(
        derived_key,
        derived_key.size(),
        0,
        reinterpret_cast<const byte *>(passphrase.getUnsecureString()),
        passphrase.length(),
        salt,
        salt.size(),
        iteration_count,
        target_iteration_time
        );

    return new EncryptionKeyImpl(derived_key, derived_key.size(), salt, salt.size(), actualIterationCount);
}

EncryptionKey* SerpentEncryptor::generateKeyFromPassphraseRandomSalt(SecureString passphrase, int mashIterations)
{
    SecByteBlock salt(SALT_SIZE);

    //generate salt
    getPrng()->GenerateBlock(salt, salt.size());

    return generateKeyFromPassphrase_p(passphrase, salt, mashIterations);
}

EncryptionKey* SerpentEncryptor::generateKeyFromPassphraseFixedSalt(SecureString passphrase, std::string filecontents)
{
    //DATA FORMAT
    //|            plaintext           |             encrypted            |  plain |    <-- confidentiality level
    //|-iter count-|-pwd salt--|--iv---|---------------data---------------|---mac--|    <-- data organization
    //|	   iter_t  | SALT_SIZE |IV_SIZE|          unknown length          |TAG_SIZE|    <-- data sizes

    if (filecontents.substr(0, sizeof(MAGIC_VALUE)-1) != MAGIC_VALUE)
    {
        // no magic value, then the string does not follow the format specified in this source file
        throw KryptanDecryptMacBadException("Bad format");
    }

    int offset = 0;

    std::string decoded;
    StringSource source(filecontents.substr(sizeof(MAGIC_VALUE)-1), true, new Base64Decoder(new StringSink(decoded)));

    //get password itereation count
    iter_t iteration_count = *reinterpret_cast<const iter_t*>(decoded.data());
    offset += sizeof(iter_t);
    //get password salt
    SecByteBlock pwdSalt(reinterpret_cast<const byte*>(decoded.substr(offset, SALT_SIZE).data()), SALT_SIZE);

    assert(pwdSalt.size() == (unsigned int)SALT_SIZE);

    return generateKeyFromPassphrase_p(passphrase, pwdSalt, iteration_count);
}

/*
* Time for encryption
* We use GCM mode with iv as ADATA (authenticated but not encrypted)
* PDATA is ofcourse 'data' and is both encrypted and authenticated
*/
std::string SerpentEncryptor::Encrypt(SecureString data, EncryptionKey* key)
{
    try
    {
        //get keydata
        EncryptionKeyImpl* keyImpl = static_cast<EncryptionKeyImpl*>(key);
        SecByteBlock keyData = keyImpl->getDataCopy();
        SecByteBlock keySaltData = keyImpl->getSaltCopy();
        iter_t iterations = keyImpl->getNumberOfIterations();

        //generate iv
        SecByteBlock iv(IV_SIZE);
        getPrng()->GenerateBlock(iv, iv.size());

        //put result here
        std::string encrypted(MAGIC_VALUE);

        //create keycheck block
        SecByteBlock keycheckShouldbe(KEY_CHECK_LENGTH);
        KEY_CHECK_HASH_FUNCTION hasher;
        hasher.Update(keyData, keyData.size());
        hasher.Final(keycheckShouldbe);

        GCM< Serpent >::Encryption e;
        e.SetKeyWithIV(keyData, keyData.size(), iv, iv.size());

        // Not required for GCM mode (but required for CCM mode)
        // e.SpecifyDataLengths( adata.size(), pdata.size(), 0 );

        BufferedTransformation* destination = new Base64Encoder(new StringSink(encrypted));

        //put iv to the beginning of the destination
        destination->Put(reinterpret_cast<const byte*>(&iterations), sizeof(iter_t));
        destination->Put(keySaltData, keySaltData.size());
        destination->Put(iv, iv.size());

        //ef takes ownership of destination, no delete necessary
        AuthenticatedEncryptionFilter ef(e, destination, false, TAG_SIZE);

        // AuthenticatedEncryptionFilter::ChannelPut
        //  defines two channels: "" (empty) and "AAD"
        //   channel "" is encrypted and authenticated
        //   channel "AAD" is authenticated
        // NOTE: AAD is not put into destination, thats
        // why we have already done that manually.
        ef.ChannelPut(AAD_CHANNEL, reinterpret_cast<const byte*>(&iterations), sizeof(iter_t), true);
        ef.ChannelPut(AAD_CHANNEL, keySaltData, keySaltData.size());
        ef.ChannelPut(AAD_CHANNEL, iv, iv.size());
        ef.ChannelMessageEnd(AAD_CHANNEL);

        // Authenticated data *must* be pushed before
        //  Confidential/Authenticated data. Otherwise
        //  we must catch the BadState exception
        ef.ChannelPut(DEFAULT_CHANNEL, keycheckShouldbe, keycheckShouldbe.size());
        ef.ChannelPut(DEFAULT_CHANNEL, (const byte*)data.getUnsecureString(), data.length());
        ef.ChannelMessageEnd(DEFAULT_CHANNEL);

        //we're finished with the unsecure data, let's remove it
        data.UnsecuredStringFinished();

        //return to caller with encrypted and encoded data
        return encrypted;
    }
    catch (CryptoPP::BufferedTransformation::NoChannelSupport& e)
    {
        data.UnsecuredStringFinished();
        // The tag must go in to the default channel:
        //  "unknown: this object doesn't support multiple channels"
        // this should never happen
        throw KryptanEncryptException(std::string("Error while encrypting: ") + e.what());
    }
    catch (CryptoPP::AuthenticatedSymmetricCipher::BadState& e)
    {
        data.UnsecuredStringFinished();
        // Pushing PDATA before ADATA results in:
        //  "GMC/AES: Update was called before State_IVSet"

        //this should also never happen
        throw KryptanEncryptException(std::string("Error while encrypting: ") + e.what());
    }
    catch (CryptoPP::InvalidArgument& e)
    {
        data.UnsecuredStringFinished();
        //some arguments were invalid
        //this should ofcourse never happen
        throw KryptanEncryptException(std::string("Error while encrypting: ") + e.what());
    }
    catch (CryptoPP::Exception& e)
    {
        data.UnsecuredStringFinished();
        //unknown exception
        throw KryptanEncryptException(std::string("Error while encrypting: ") + e.what());
    }
}

SecureString SerpentEncryptor::Decrypt(std::string data, EncryptionKey* key)
{
    try
    {
        if (data.substr(0, sizeof(MAGIC_VALUE)-1) != MAGIC_VALUE)
        {
            // no magic value, then the string does not follow the format specified in this source file
            throw KryptanDecryptMacBadException("Bad format");
        }
        //source
        std::string decoded;
        StringSource source(data.substr(sizeof(MAGIC_VALUE)-1), true, new Base64Decoder(new StringSink(decoded)));

        //DATA FORMAT
        //|            plaintext           |             encrypted            |  plain |    <-- confidentiality level
        //|-iter count-|-pwd salt--|--iv---|---------------data---------------|---mac--|    <-- data organization
        //|	   iter_t  | SALT_SIZE |IV_SIZE|          unknown length          |TAG_SIZE|    <-- data sizes

        //pre-data exraction sanity check
        assert(data.length() > TAG_SIZE + IV_SIZE);

        int offset = sizeof(iter_t)+SALT_SIZE;
        //get iv
        SecByteBlock iv(reinterpret_cast<const byte*>(decoded.substr(offset, IV_SIZE).data()), IV_SIZE);
        offset += IV_SIZE;
        //get encrypted
        std::string encrypted = decoded.substr(offset, decoded.length() - offset - TAG_SIZE);
        //get mac
        std::string mac = decoded.substr(decoded.length() - TAG_SIZE);

        //post-data exraction sanity checks
        assert(iv.size() == (unsigned int)IV_SIZE);
        assert(encrypted.size() > 0);
        assert(mac.size() == (unsigned int)TAG_SIZE);

        //get keydata
        EncryptionKeyImpl* keyImpl = static_cast<EncryptionKeyImpl*>(key);
        SecByteBlock keyData = keyImpl->getDataCopy();
        iter_t iterations = keyImpl->getNumberOfIterations();
        SecByteBlock keySaltData = keyImpl->getSaltCopy();

        //Decryptor
        GCM<Serpent>::Decryption d;
        d.SetKeyWithIV(keyData, keyData.size(), iv, iv.size());

        // Object _will_ throw an exception
        //  during decryption\verification _if_
        //  verification fails.
        AuthenticatedDecryptionFilter df(d, NULL,
            AuthenticatedDecryptionFilter::MAC_AT_END |
            AuthenticatedDecryptionFilter::THROW_EXCEPTION, TAG_SIZE);

        //the order of the follwing is important
        df.ChannelPut(AAD_CHANNEL, reinterpret_cast<const byte*>(&iterations), sizeof(iter_t), true);
        df.ChannelPut(AAD_CHANNEL, keySaltData, keySaltData.size());
        df.ChannelPut(AAD_CHANNEL, iv, iv.size());
        df.ChannelMessageEnd(AAD_CHANNEL);

        df.ChannelPut(DEFAULT_CHANNEL, reinterpret_cast<const byte*>(encrypted.data()), encrypted.size());
        df.ChannelPut(DEFAULT_CHANNEL, reinterpret_cast<const byte*>(mac.data()), mac.size());
        df.ChannelMessageEnd(DEFAULT_CHANNEL);

        //if we get this far the authentication is successfull :)

        df.SetRetrievalChannel(DEFAULT_CHANNEL);
        auto totaldecryptedsize = df.MaxRetrievable();

        if (totaldecryptedsize < (unsigned int)KEY_CHECK_LENGTH)
        {
            throw KryptanDecryptMacBadException("Error while decrypting: Cannot find keycheck data!");
        }

        //keycheck
        SecByteBlock keycheck(KEY_CHECK_LENGTH);
        SecByteBlock keycheckShouldbe(KEY_CHECK_LENGTH);
        df.Get(keycheck, keycheck.size());
        KEY_CHECK_HASH_FUNCTION hasher;
        hasher.Update(keyData, keyData.size());
        hasher.Final(keycheckShouldbe);

        if (!VerifyBufsEqual(keycheck, keycheckShouldbe, KEY_CHECK_LENGTH))
        {
            throw KryptanDecryptWrongKeyException("Incorrect key!");
        }

        auto datasize = totaldecryptedsize - KEY_CHECK_LENGTH;

        if (datasize <= 0)
            return SecureString();

        //get data
        byte* destination = new byte[(int)datasize + 1];
        df.Get(destination, (size_t)datasize);
        destination[datasize] = 0;//null terminate

        //imports the data securely and deletes the buffer
        SecureString decrypted((SecureString::ssarr) destination);

        return decrypted;
    }
    catch (CryptoPP::InvalidArgument& e)
    {
        //invalid argument somewhere
        //this should not happen
        throw KryptanDecryptException(e.what());
    }
    catch (CryptoPP::AuthenticatedSymmetricCipher::BadState& e)
    {
        // Pushing PDATA before ADATA results in:
        //  "GMC/AES: Update was called before State_IVSet"
        throw KryptanDecryptException(e.what());
    }
    catch (CryptoPP::HashVerificationFilter::HashVerificationFailed)
    {
        throw KryptanDecryptMacBadException("Integrity check failed, password file is corrupt.");
    }
}
<commit_msg>Worked around the lack of AutoSeededRandomPool in SerpentEncryptor.cpp for the WinRT platform (Windows phone 8)<commit_after>#include "SerpentEncryptor.h"
using Kryptan::Core::Internal::SerpentEncryptor;
using Kryptan::Core::Internal::EncryptionKey;
using Kryptan::Core::SecureString;

#include "Exceptions.h"
using Kryptan::Core::KryptanBaseException;

//#define OS_RNG_AVAILABLE

#ifdef OS_RNG_AVAILABLE
# include <cryptopp/osrng.h>
using CryptoPP::AutoSeededRandomPool;
#else
# include <cryptopp/randpool.h>
using CryptoPP::RandomPool;
#endif

#include <cryptopp/gcm.h>
using CryptoPP::GCM;

#include <cryptopp/serpent.h>
using CryptoPP::Serpent;

#include <cryptopp/secblock.h>
using CryptoPP::SecByteBlock;

#include <cryptopp/filters.h>
using CryptoPP::StringSink;
using CryptoPP::StringSource;
using CryptoPP::AuthenticatedEncryptionFilter;
using CryptoPP::AuthenticatedDecryptionFilter;
using CryptoPP::BufferedTransformation;
using CryptoPP::AAD_CHANNEL;
using CryptoPP::DEFAULT_CHANNEL;

#include <cryptopp/base64.h>
using CryptoPP::Base64Encoder;
using CryptoPP::Base64Decoder;

#include <cryptopp/sha.h>
using CryptoPP::SHA512;
#include <cryptopp/sha3.h>
//using CryptoPP::SHA3_512;
#include <cryptopp/pwdbased.h>
using CryptoPP::PKCS5_PBKDF2_HMAC;

//while developing
//using namespace CryptoPP;

#define MAGIC_VALUE "KRYPTAN\n"

const int TAG_SIZE = 16; //bytes
const int IV_SIZE = 16; //bytes
typedef SHA512 KEY_CHECK_HASH_FUNCTION;
const int KEY_CHECK_LENGTH = KEY_CHECK_HASH_FUNCTION::DIGESTSIZE;
const int MIN_ITERATION_COUNT = 2 ^ 10;
const int TARGET_ITERATION_TIME = 2; //seconds
const int SALT_SIZE = 16; //bytes
typedef uint32_t iter_t;

RandomPool* getPrng()
{
#ifdef OS_RNG_AVAILABLE
    static AutoSeededRandomPool g_prng;
#else
    static RandomPool g_prng;
    static bool inited = false;
    if (!inited)
    {
  #if defined(_WIN32) && defined(WINAPI_FAMILY_APP)
        const int SEED_LEN = 32;
        auto iBuffer = Windows::Security::Cryptography::CryptographicBuffer::GenerateRandom(SEED_LEN);
        auto reader = Windows::Storage::Streams::DataReader::FromBuffer(iBuffer);
        std::vector<unsigned char> data(reader->UnconsumedBufferLength);
        if (!data.empty())
            reader->ReadBytes(
                ::Platform::ArrayReference<unsigned char>(
                    &data[0], data.size()
                )
            );
        g_prng.IncorporateEntropy(&data[0], SEED_LEN);
        inited = true;
  #else
    #error Requires cryptographically secure seed
  #endif
    }

#endif
    return &g_prng;
}

//
class EncryptionKeyImpl : public EncryptionKey
{
private:
    SecByteBlock xor1;
    SecByteBlock xor2;
    int keyLength;
    iter_t createdWithNumberOfIterations;
public:
    EncryptionKeyImpl(byte* kData, int kLength, byte* sData, int sLength, iter_t nIterations)
    {
        keyLength = kLength;
        xor1.Grow(kLength + sLength);
        xor2.Grow(kLength + sLength);
        createdWithNumberOfIterations = nIterations;

        //fill with random data
        getPrng()->GenerateBlock(xor1, kLength + sLength);

        //put key data into storage
        for (int i = 0; i < kLength; i++)
        {
            xor2[i] = kData[i] ^ xor1[i];
        }

        //put salt data into storage
        for (int i = 0; i < sLength; i++)
        {
            xor2[kLength + i] = sData[i] ^ xor1[kLength + i];
        }
    }

    SecByteBlock getDataCopy()
    {
        SecByteBlock data(keyLength);
        for (int i = 0; i < keyLength; i++)
        {
            data[i] = xor1[i] ^ xor2[i];
        }
        return data;
    }

    SecByteBlock getSaltCopy()
    {
        int saltLength = xor1.size() - keyLength;
        SecByteBlock data(saltLength);
        for (int i = 0; i < saltLength; i++)
        {
            data[i] = xor1[keyLength + i] ^ xor2[keyLength + i];
        }
        return data;
    }

    iter_t getNumberOfIterations()
    {
        return createdWithNumberOfIterations;
    }

    ~EncryptionKeyImpl()
    {
        //clean xor1 and xor2
        xor1.CleanNew(0);
        xor2.CleanNew(0);
    }
};

SerpentEncryptor::SerpentEncryptor()
{
};

SerpentEncryptor::~SerpentEncryptor()
{
};

EncryptionKeyImpl* generateKeyFromPassphrase_p(SecureString passphrase, SecByteBlock salt, iter_t iterations = 0)
{

    SecByteBlock derived_key(Serpent::DEFAULT_KEYLENGTH);

    double target_iteration_time = TARGET_ITERATION_TIME;
    iter_t iteration_count = MIN_ITERATION_COUNT;

    if (iterations > 0)
    {
        target_iteration_time = 0;
        iteration_count = iterations;
    }

    PKCS5_PBKDF2_HMAC<SHA512> pbkdf2;
    iter_t actualIterationCount = pbkdf2.DeriveKey(
        derived_key,
        derived_key.size(),
        0,
        reinterpret_cast<const byte *>(passphrase.getUnsecureString()),
        passphrase.length(),
        salt,
        salt.size(),
        iteration_count,
        target_iteration_time
        );

    return new EncryptionKeyImpl(derived_key, derived_key.size(), salt, salt.size(), actualIterationCount);
}

EncryptionKey* SerpentEncryptor::generateKeyFromPassphraseRandomSalt(SecureString passphrase, int mashIterations)
{
    SecByteBlock salt(SALT_SIZE);

    //generate salt
    getPrng()->GenerateBlock(salt, salt.size());

    return generateKeyFromPassphrase_p(passphrase, salt, mashIterations);
}

EncryptionKey* SerpentEncryptor::generateKeyFromPassphraseFixedSalt(SecureString passphrase, std::string filecontents)
{
    //DATA FORMAT
    //|            plaintext           |             encrypted            |  plain |    <-- confidentiality level
    //|-iter count-|-pwd salt--|--iv---|---------------data---------------|---mac--|    <-- data organization
    //|	   iter_t  | SALT_SIZE |IV_SIZE|          unknown length          |TAG_SIZE|    <-- data sizes

    if (filecontents.substr(0, sizeof(MAGIC_VALUE)-1) != MAGIC_VALUE)
    {
        // no magic value, then the string does not follow the format specified in this source file
        throw KryptanDecryptMacBadException("Bad format");
    }

    int offset = 0;

    std::string decoded;
    StringSource source(filecontents.substr(sizeof(MAGIC_VALUE)-1), true, new Base64Decoder(new StringSink(decoded)));

    //get password itereation count
    iter_t iteration_count = *reinterpret_cast<const iter_t*>(decoded.data());
    offset += sizeof(iter_t);
    //get password salt
    SecByteBlock pwdSalt(reinterpret_cast<const byte*>(decoded.substr(offset, SALT_SIZE).data()), SALT_SIZE);

    assert(pwdSalt.size() == (unsigned int)SALT_SIZE);

    return generateKeyFromPassphrase_p(passphrase, pwdSalt, iteration_count);
}

/*
* Time for encryption
* We use GCM mode with iv as ADATA (authenticated but not encrypted)
* PDATA is ofcourse 'data' and is both encrypted and authenticated
*/
std::string SerpentEncryptor::Encrypt(SecureString data, EncryptionKey* key)
{
    try
    {
        //get keydata
        EncryptionKeyImpl* keyImpl = static_cast<EncryptionKeyImpl*>(key);
        SecByteBlock keyData = keyImpl->getDataCopy();
        SecByteBlock keySaltData = keyImpl->getSaltCopy();
        iter_t iterations = keyImpl->getNumberOfIterations();

        //generate iv
        SecByteBlock iv(IV_SIZE);
        getPrng()->GenerateBlock(iv, iv.size());

        //put result here
        std::string encrypted(MAGIC_VALUE);

        //create keycheck block
        SecByteBlock keycheckShouldbe(KEY_CHECK_LENGTH);
        KEY_CHECK_HASH_FUNCTION hasher;
        hasher.Update(keyData, keyData.size());
        hasher.Final(keycheckShouldbe);

        GCM< Serpent >::Encryption e;
        e.SetKeyWithIV(keyData, keyData.size(), iv, iv.size());

        // Not required for GCM mode (but required for CCM mode)
        // e.SpecifyDataLengths( adata.size(), pdata.size(), 0 );

        BufferedTransformation* destination = new Base64Encoder(new StringSink(encrypted));

        //put iv to the beginning of the destination
        destination->Put(reinterpret_cast<const byte*>(&iterations), sizeof(iter_t));
        destination->Put(keySaltData, keySaltData.size());
        destination->Put(iv, iv.size());

        //ef takes ownership of destination, no delete necessary
        AuthenticatedEncryptionFilter ef(e, destination, false, TAG_SIZE);

        // AuthenticatedEncryptionFilter::ChannelPut
        //  defines two channels: "" (empty) and "AAD"
        //   channel "" is encrypted and authenticated
        //   channel "AAD" is authenticated
        // NOTE: AAD is not put into destination, thats
        // why we have already done that manually.
        ef.ChannelPut(AAD_CHANNEL, reinterpret_cast<const byte*>(&iterations), sizeof(iter_t), true);
        ef.ChannelPut(AAD_CHANNEL, keySaltData, keySaltData.size());
        ef.ChannelPut(AAD_CHANNEL, iv, iv.size());
        ef.ChannelMessageEnd(AAD_CHANNEL);

        // Authenticated data *must* be pushed before
        //  Confidential/Authenticated data. Otherwise
        //  we must catch the BadState exception
        ef.ChannelPut(DEFAULT_CHANNEL, keycheckShouldbe, keycheckShouldbe.size());
        ef.ChannelPut(DEFAULT_CHANNEL, (const byte*)data.getUnsecureString(), data.length());
        ef.ChannelMessageEnd(DEFAULT_CHANNEL);

        //we're finished with the unsecure data, let's remove it
        data.UnsecuredStringFinished();

        //return to caller with encrypted and encoded data
        return encrypted;
    }
    catch (CryptoPP::BufferedTransformation::NoChannelSupport& e)
    {
        data.UnsecuredStringFinished();
        // The tag must go in to the default channel:
        //  "unknown: this object doesn't support multiple channels"
        // this should never happen
        throw KryptanEncryptException(std::string("Error while encrypting: ") + e.what());
    }
    catch (CryptoPP::AuthenticatedSymmetricCipher::BadState& e)
    {
        data.UnsecuredStringFinished();
        // Pushing PDATA before ADATA results in:
        //  "GMC/AES: Update was called before State_IVSet"

        //this should also never happen
        throw KryptanEncryptException(std::string("Error while encrypting: ") + e.what());
    }
    catch (CryptoPP::InvalidArgument& e)
    {
        data.UnsecuredStringFinished();
        //some arguments were invalid
        //this should ofcourse never happen
        throw KryptanEncryptException(std::string("Error while encrypting: ") + e.what());
    }
    catch (CryptoPP::Exception& e)
    {
        data.UnsecuredStringFinished();
        //unknown exception
        throw KryptanEncryptException(std::string("Error while encrypting: ") + e.what());
    }
}

SecureString SerpentEncryptor::Decrypt(std::string data, EncryptionKey* key)
{
    try
    {
        if (data.substr(0, sizeof(MAGIC_VALUE)-1) != MAGIC_VALUE)
        {
            // no magic value, then the string does not follow the format specified in this source file
            throw KryptanDecryptMacBadException("Bad format");
        }
        //source
        std::string decoded;
        StringSource source(data.substr(sizeof(MAGIC_VALUE)-1), true, new Base64Decoder(new StringSink(decoded)));

        //DATA FORMAT
        //|            plaintext           |             encrypted            |  plain |    <-- confidentiality level
        //|-iter count-|-pwd salt--|--iv---|---------------data---------------|---mac--|    <-- data organization
        //|	   iter_t  | SALT_SIZE |IV_SIZE|          unknown length          |TAG_SIZE|    <-- data sizes

        //pre-data exraction sanity check
        assert(data.length() > TAG_SIZE + IV_SIZE);

        int offset = sizeof(iter_t)+SALT_SIZE;
        //get iv
        SecByteBlock iv(reinterpret_cast<const byte*>(decoded.substr(offset, IV_SIZE).data()), IV_SIZE);
        offset += IV_SIZE;
        //get encrypted
        std::string encrypted = decoded.substr(offset, decoded.length() - offset - TAG_SIZE);
        //get mac
        std::string mac = decoded.substr(decoded.length() - TAG_SIZE);

        //post-data exraction sanity checks
        assert(iv.size() == (unsigned int)IV_SIZE);
        assert(encrypted.size() > 0);
        assert(mac.size() == (unsigned int)TAG_SIZE);

        //get keydata
        EncryptionKeyImpl* keyImpl = static_cast<EncryptionKeyImpl*>(key);
        SecByteBlock keyData = keyImpl->getDataCopy();
        iter_t iterations = keyImpl->getNumberOfIterations();
        SecByteBlock keySaltData = keyImpl->getSaltCopy();

        //Decryptor
        GCM<Serpent>::Decryption d;
        d.SetKeyWithIV(keyData, keyData.size(), iv, iv.size());

        // Object _will_ throw an exception
        //  during decryption\verification _if_
        //  verification fails.
        AuthenticatedDecryptionFilter df(d, NULL,
            AuthenticatedDecryptionFilter::MAC_AT_END |
            AuthenticatedDecryptionFilter::THROW_EXCEPTION, TAG_SIZE);

        //the order of the follwing is important
        df.ChannelPut(AAD_CHANNEL, reinterpret_cast<const byte*>(&iterations), sizeof(iter_t), true);
        df.ChannelPut(AAD_CHANNEL, keySaltData, keySaltData.size());
        df.ChannelPut(AAD_CHANNEL, iv, iv.size());
        df.ChannelMessageEnd(AAD_CHANNEL);

        df.ChannelPut(DEFAULT_CHANNEL, reinterpret_cast<const byte*>(encrypted.data()), encrypted.size());
        df.ChannelPut(DEFAULT_CHANNEL, reinterpret_cast<const byte*>(mac.data()), mac.size());
        df.ChannelMessageEnd(DEFAULT_CHANNEL);

        //if we get this far the authentication is successfull :)

        df.SetRetrievalChannel(DEFAULT_CHANNEL);
        auto totaldecryptedsize = df.MaxRetrievable();

        if (totaldecryptedsize < (unsigned int)KEY_CHECK_LENGTH)
        {
            throw KryptanDecryptMacBadException("Error while decrypting: Cannot find keycheck data!");
        }

        //keycheck
        SecByteBlock keycheck(KEY_CHECK_LENGTH);
        SecByteBlock keycheckShouldbe(KEY_CHECK_LENGTH);
        df.Get(keycheck, keycheck.size());
        KEY_CHECK_HASH_FUNCTION hasher;
        hasher.Update(keyData, keyData.size());
        hasher.Final(keycheckShouldbe);

        if (!VerifyBufsEqual(keycheck, keycheckShouldbe, KEY_CHECK_LENGTH))
        {
            throw KryptanDecryptWrongKeyException("Incorrect key!");
        }

        auto datasize = totaldecryptedsize - KEY_CHECK_LENGTH;

        if (datasize <= 0)
            return SecureString();

        //get data
        byte* destination = new byte[(int)datasize + 1];
        df.Get(destination, (size_t)datasize);
        destination[datasize] = 0;//null terminate

        //imports the data securely and deletes the buffer
        SecureString decrypted((SecureString::ssarr) destination);

        return decrypted;
    }
    catch (CryptoPP::InvalidArgument& e)
    {
        //invalid argument somewhere
        //this should not happen
        throw KryptanDecryptException(e.what());
    }
    catch (CryptoPP::AuthenticatedSymmetricCipher::BadState& e)
    {
        // Pushing PDATA before ADATA results in:
        //  "GMC/AES: Update was called before State_IVSet"
        throw KryptanDecryptException(e.what());
    }
    catch (CryptoPP::HashVerificationFilter::HashVerificationFailed)
    {
        throw KryptanDecryptMacBadException("Integrity check failed, password file is corrupt.");
    }
}
<|endoftext|>


<commit_before>// Time:  O(n)
// Space: O(n)

class Solution {
public:
    int firstUniqChar(string s) {
        using IT = list<int>::iterator;

    	list<int> candidates;
    	unordered_map<char, IT> lookup;
    	for (int i = 0; i < s.size(); ++i) {
    		const auto c = s[i];
    		if (lookup.count(c)) {
    			if (lookup[c] != candidates.end()) {
    				candidates.erase(lookup[c]);
    			}
    			lookup[c] = candidates.end();
    		} else {
    			lookup[c] = candidates.emplace(candidates.end(), i);
    		}
    	}
    	return candidates.empty() ? -1 : candidates.front();
    }
};
<commit_msg>Update first-unique-character-in-a-string.cpp<commit_after>// Time:  O(n)
// Space: O(n)

class Solution {
public:
    int firstUniqChar(string s) {
        using IT = list<int>::iterator;

    	list<int> candidates;
    	unordered_map<char, IT> lookup;
    	for (int i = 0; i < s.length(); ++i) {
    		const auto c = s[i];
    		if (lookup.count(c)) {
    			if (lookup[c] != candidates.end()) {
    				candidates.erase(lookup[c]);
    			}
    			lookup[c] = candidates.end();
    		} else {
    			lookup[c] = candidates.emplace(candidates.end(), i);
    		}
    	}
    	return candidates.empty() ? -1 : candidates.front();
    }
};
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the config.tests of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <iostream>
#include <cstdlib>
#include <cstring>

class CCRC32
{
public:
    CCRC32() { initialize(); }

    unsigned long FullCRC(const unsigned char *sData, unsigned long ulDataLength)
    {
        unsigned long ulCRC = 0xffffffff;
        PartialCRC(&ulCRC, sData, ulDataLength);
        return(ulCRC ^ 0xffffffff);
    }

    void PartialCRC(unsigned long *ulCRC, const unsigned char *sData, unsigned long ulDataLength)
    {
        while(ulDataLength--) {
            *ulCRC = (*ulCRC >> 8) ^ ulTable[(*ulCRC & 0xFF) ^ *sData++];
        }
    }

private:
    void initialize(void)
    {
        unsigned long ulPolynomial = 0x04C11DB7;
        memset(&ulTable, 0, sizeof(ulTable));
        for(int iCodes = 0; iCodes <= 0xFF; iCodes++) {
            ulTable[iCodes] = Reflect(iCodes, 8) << 24;
            for(int iPos = 0; iPos < 8; iPos++) {
                ulTable[iCodes] = (ulTable[iCodes] << 1)
                    ^ ((ulTable[iCodes] & (1 << 31)) ? ulPolynomial : 0);
            }

            ulTable[iCodes] = Reflect(ulTable[iCodes], 32);
        }
    }
    unsigned long Reflect(unsigned long ulReflect, const char cChar)
    {
        unsigned long ulValue = 0;
        // Swap bit 0 for bit 7, bit 1 For bit 6, etc....
        for(int iPos = 1; iPos < (cChar + 1); iPos++) {
            if(ulReflect & 1) {
                ulValue |= (1 << (cChar - iPos));
            }
            ulReflect >>= 1;
        }
        return ulValue;
    }
    unsigned long ulTable[256]; // CRC lookup table array.
};

int main(int argc, char **argv)
{
    CCRC32 crc;
    char *name;
    if (argc < 2) {
        std::cerr << "usage: crc <string>\n";
        return 0;
    } else {
        name = argv[1];
    }
    std::cout << crc.FullCRC((unsigned char *)name, strlen(name)) << std::endl;
}
<commit_msg>Fixed calculating CRC32 on 64bit platforms<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the config.tests of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <iostream>
#include <cstdlib>
#include <cstring>

class CCRC32
{
public:
    CCRC32() { initialize(); }

    unsigned long FullCRC(const unsigned char *sData, unsigned long ulDataLength)
    {
        unsigned long ulCRC = 0xffffffff;
        PartialCRC(&ulCRC, sData, ulDataLength);
        return(ulCRC ^ 0xffffffff);
    }

    void PartialCRC(unsigned long *ulCRC, const unsigned char *sData, unsigned long ulDataLength)
    {
        while(ulDataLength--) {
            *ulCRC = (*ulCRC >> 8) ^ ulTable[(*ulCRC & 0xFF) ^ *sData++];
        }
    }

private:
    void initialize(void)
    {
        unsigned long ulPolynomial = 0x04C11DB7;
        memset(&ulTable, 0, sizeof(ulTable));
        for(int iCodes = 0; iCodes <= 0xFF; iCodes++) {
            ulTable[iCodes] = Reflect(iCodes, 8) << 24;
            for(int iPos = 0; iPos < 8; iPos++) {
                ulTable[iCodes] = ((ulTable[iCodes] << 1) & 0xffffffff)
                    ^ ((ulTable[iCodes] & (1 << 31)) ? ulPolynomial : 0);
            }

            ulTable[iCodes] = Reflect(ulTable[iCodes], 32);
        }
    }
    unsigned long Reflect(unsigned long ulReflect, const char cChar)
    {
        unsigned long ulValue = 0;
        // Swap bit 0 for bit 7, bit 1 For bit 6, etc....
        for(int iPos = 1; iPos < (cChar + 1); iPos++) {
            if(ulReflect & 1) {
                ulValue |= (1ul << (cChar - iPos));
            }
            ulReflect >>= 1;
        }
        return ulValue;
    }
    unsigned long ulTable[256]; // CRC lookup table array.
};

int main(int argc, char **argv)
{
    CCRC32 crc;
    char *name;
    if (argc < 2) {
        std::cerr << "usage: crc <string>\n";
        return 0;
    } else {
        name = argv[1];
    }
    std::cout << crc.FullCRC((unsigned char *)name, strlen(name)) << std::endl;
}
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// simple_optimizer.cpp
//
// Identification: /peloton/src/optimizer/simple_optimizer.cpp
//
// Copyright (c) 2016, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "optimizer/simple_optimizer.h"
#include "parser/peloton/abstract_parse.h"
#include "planner/abstract_plan.h"
#include "planner/drop_plan.h"
#include "planner/seq_scan_plan.h"

#include "common/logger.h"

#include <memory>

namespace peloton {
namespace planner {
class AbstractPlan;
}
namespace optimizer {

SimpleOptimizer::SimpleOptimizer() {
}
;

SimpleOptimizer::~SimpleOptimizer() {
}
;

std::shared_ptr<planner::AbstractPlan> SimpleOptimizer::BuildPlanTree(
    const std::unique_ptr<parser::AbstractParse>& parse_tree) {

  std::shared_ptr<planner::AbstractPlan> plan_tree;

  // Base Case
  if (parse_tree.get() == nullptr)
    return plan_tree;

  std::unique_ptr<planner::AbstractPlan> child_plan = nullptr;

  // TODO: Transform the parse tree

  // One to one Mapping
  auto parse_item_node_type = parse_tree->GetParseNodeType();

  switch (parse_item_node_type) {
    case PARSE_NODE_TYPE_DROP: {
      std::unique_ptr<planner::AbstractPlan> child_DropPlan(
          new planner::DropPlan("department-table"));
      child_plan = std::move(child_DropPlan);
    }
      break;

    case PARSE_NODE_TYPE_SCAN: {
      std::unique_ptr<planner::AbstractPlan> child_SeqScanPlan(
          new planner::SeqScanPlan());
      child_plan = std::move(child_SeqScanPlan);
    }
      break;

    default:
      LOG_INFO("Unsupported Parse Node Type");
  }

  if (child_plan != nullptr) {
    if (plan_tree != nullptr)
      plan_tree->AddChild(std::move(child_plan));
    else
      plan_tree = std::move(child_plan);
  }

  // Recurse
  auto &children = parse_tree->GetChildren();
  for (auto &child : children) {
    std::unique_ptr<planner::AbstractPlan> child_parse(BuildPlanTree(child));
    child_plan = std::move(child_parse);
  }
  return plan_tree;
}

}  // namespace optimizer
}  // namespace peloton
<commit_msg>Simple Fix and Checkpoint<commit_after>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// simple_optimizer.cpp
//
// Identification: /peloton/src/optimizer/simple_optimizer.cpp
//
// Copyright (c) 2016, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "optimizer/simple_optimizer.h"
#include "parser/peloton/abstract_parse.h"
#include "planner/abstract_plan.h"
#include "planner/drop_plan.h"
#include "planner/seq_scan_plan.h"

#include "common/logger.h"

#include <memory>

namespace peloton {
namespace planner {
class AbstractPlan;
}
namespace optimizer {

SimpleOptimizer::SimpleOptimizer() {
}
;

SimpleOptimizer::~SimpleOptimizer() {
}
;

std::shared_ptr<planner::AbstractPlan> SimpleOptimizer::BuildPlanTree(
    const std::unique_ptr<parser::AbstractParse>& parse_tree) {

  std::shared_ptr<planner::AbstractPlan> plan_tree;

  // Base Case
  if (parse_tree.get() == nullptr)
    return plan_tree;

  std::unique_ptr<planner::AbstractPlan> child_plan = nullptr;

  // TODO: Transform the parse tree

  // One to one Mapping
  auto parse_item_node_type = parse_tree->GetParseNodeType();

  switch (parse_item_node_type) {
    case PARSE_NODE_TYPE_DROP: {
      std::unique_ptr<planner::AbstractPlan> child_DropPlan(
          new planner::DropPlan("department-table"));
      child_plan = std::move(child_DropPlan);
    }
      break;

    case PARSE_NODE_TYPE_SCAN: {
      std::unique_ptr<planner::AbstractPlan> child_SeqScanPlan(
          new planner::SeqScanPlan());
      child_plan = std::move(child_SeqScanPlan);
    }
      break;

    default:
      LOG_INFO("Unsupported Parse Node Type");
  }

  if (child_plan != nullptr) {
    if (plan_tree != nullptr)
      plan_tree->AddChild(std::move(child_plan));
    else
      plan_tree = std::move(child_plan);
  }

  // Recurse
  auto &children = parse_tree->GetChildren();
  for (auto &child : children) {
    auto child_parse = std::move(BuildPlanTree(child));
    child_plan = std::move(child_parse);
  }
  return plan_tree;
}

}  // namespace optimizer
}  // namespace peloton
<|endoftext|>


<commit_before>#include "Component.h"

Msg* Component::pop()
{
	Msg* msg = NULL;
	if(!msgs.empty())
	{
		msg = msgs.front();
		msgs.pop();
	}

	return msg;
}
Msg* Component::peek()
{
	Msg* msg = NULL;
	if(!msgs.empty())
		msg = msgs.front();
	return msg;
}

Component::Component() {}
Component::~Component()
{
	for(unsigned int i = 0; i < msgs.size(); i++)
		msgs.pop(); //calls message's destructor
}

void Component::push(Msg* msg)
{
	msgs.push(msg);
}
<commit_msg>Attempted to resolve memleak by changing Components constructor<commit_after>#include "Component.h"

Msg* Component::pop()
{
	Msg* msg = NULL;
	if(!msgs.empty())
	{
		msg = msgs.front();
		msgs.pop();
	}

	return msg;
}
Msg* Component::peek()
{
	Msg* msg = NULL;
	if(!msgs.empty())
		msg = msgs.front();
	return msg;
}

Component::Component() {}
Component::~Component()
{
	Msg* msg;
	for(unsigned int i = 0; i < msgs.size(); i++)
	{
		msg = msgs.front();
		msgs.pop();
		delete msg;
		//msgs.pop(); //calls message's destructor
	}
}

void Component::push(Msg* msg)
{
	msgs.push(msg);
}
<|endoftext|>


<commit_before>#include <boost/algorithm/string.hpp>
#include "make_unique.h"
#include "Utils.h"
#include "stricmp.h"
#include "DiskUtils.h"
#include "IszImageStream.h"
#include "CsoImageStream.h"
#include "StdStream.h"
#ifdef WIN32
#include "VolumeStream.h"
#else
#include "Posix_VolumeStream.h"
#endif
#ifdef __ANDROID__
#include "PosixFileStream.h"
#endif

static Framework::CStream* CreateImageStream(const boost::filesystem::path& imagePath)
{
#ifdef __ANDROID__
	return new Framework::CPosixFileStream(imagePath.string().c_str(), O_RDONLY);
#else
	return new Framework::CStdStream(imagePath.string().c_str(), "rb");
#endif
}

DiskUtils::Iso9660Ptr DiskUtils::CreateDiskImageFromPath(const boost::filesystem::path& imagePath)
{
	assert(!imagePath.empty());

	std::shared_ptr<Framework::CStream> stream;
	auto extension = imagePath.extension().string();

	//Gotta think of something better than that...
	if(!stricmp(extension.c_str(), ".isz"))
	{
		stream = std::make_shared<CIszImageStream>(CreateImageStream(imagePath));
	}
	else if(!stricmp(extension.c_str(), ".cso"))
	{
		stream = std::make_shared<CCsoImageStream>(CreateImageStream(imagePath));
	}
#ifdef WIN32
	else if(imagePath.string()[0] == '\\')
	{
		stream = std::make_shared<Framework::Win32::CVolumeStream>(imagePath.string()[4]);
	}
#elif !defined(__ANDROID__) && !TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
	else
	{
		try
		{
			stream = std::make_shared<Framework::Posix::CVolumeStream>(path);
		}
		catch(...)
		{
			//Ok if it fails here, might be a standard ISO image file
			//which will be handled below
		}
	}
#endif

	//If it's null after all that, just feed it to a StdStream
	if(!stream)
	{
		stream = std::shared_ptr<Framework::CStream>(CreateImageStream(imagePath));
	}

	Iso9660Ptr result;
	try
	{
		auto blockProvider = std::make_shared<ISO9660::CBlockProvider2048>(stream);
		result = std::make_unique<CISO9660>(blockProvider);
	}
	catch(...)
	{
		//Failed with block size 2048, try with CD-ROM XA
		auto blockProvider = std::make_shared<ISO9660::CBlockProviderCDROMXA>(stream);
		result = std::make_unique<CISO9660>(blockProvider);
	}
	return result;
}

DiskUtils::SystemConfigMap DiskUtils::ParseSystemConfigFile(Framework::CStream* systemCnfFile)
{
	SystemConfigMap result;
	auto line = Utils::GetLine(systemCnfFile);
	while(!systemCnfFile->IsEOF())
	{
		auto trimmedEnd = std::remove_if(line.begin(), line.end(), isspace);
		auto trimmedLine = std::string(line.begin(), trimmedEnd);
		std::vector<std::string> components;
		boost::split(components, trimmedLine, boost::is_any_of("="), boost::algorithm::token_compress_on);
		if(components.size() >= 2)
		{
			result.insert(std::make_pair(components[0], components[1]));
		}
		line = Utils::GetLine(systemCnfFile);
	}
	return result;
}

static std::string GetDiskIdFromPath(const std::string& filePath)
{
	//Expecting something like SCUS_XXX.XX;1
	if(filePath.length() < 13)
	{
		throw std::runtime_error("File name too short");
	}

	auto subFilePath = filePath.substr(filePath.length() - 13);
	auto regionCode = subFilePath.substr(0, 4);
	auto serial1 = subFilePath.substr(5, 3);
	auto serial2 = subFilePath.substr(9, 2);
	return regionCode + "-" + serial1 + serial2;
}

bool DiskUtils::TryGetDiskId(const boost::filesystem::path& imagePath, std::string* diskIdPtr)
{
	try
	{
		auto diskImage = CreateDiskImageFromPath(imagePath);
		auto systemConfigFile = std::unique_ptr<Framework::CStream>(diskImage->Open("SYSTEM.CNF;1"));
		if(!systemConfigFile) return false;

		auto systemConfig = ParseSystemConfigFile(systemConfigFile.get());
		auto bootItemIterator = systemConfig.find("BOOT2");
		if(bootItemIterator == std::end(systemConfig)) return false;

		auto diskId = GetDiskIdFromPath(bootItemIterator->second);
		if(diskIdPtr)
		{
			(*diskIdPtr) = diskId;
		}
		return true;
	}
	catch(const std::exception&)
	{
		return false;
	}
}
<commit_msg>Format native serial values as "SLES_XXX.XX"<commit_after>#include <boost/algorithm/string.hpp>
#include "make_unique.h"
#include "Utils.h"
#include "stricmp.h"
#include "DiskUtils.h"
#include "IszImageStream.h"
#include "CsoImageStream.h"
#include "StdStream.h"
#ifdef WIN32
#include "VolumeStream.h"
#else
#include "Posix_VolumeStream.h"
#endif
#ifdef __ANDROID__
#include "PosixFileStream.h"
#endif

static Framework::CStream* CreateImageStream(const boost::filesystem::path& imagePath)
{
#ifdef __ANDROID__
	return new Framework::CPosixFileStream(imagePath.string().c_str(), O_RDONLY);
#else
	return new Framework::CStdStream(imagePath.string().c_str(), "rb");
#endif
}

DiskUtils::Iso9660Ptr DiskUtils::CreateDiskImageFromPath(const boost::filesystem::path& imagePath)
{
	assert(!imagePath.empty());

	std::shared_ptr<Framework::CStream> stream;
	auto extension = imagePath.extension().string();

	//Gotta think of something better than that...
	if(!stricmp(extension.c_str(), ".isz"))
	{
		stream = std::make_shared<CIszImageStream>(CreateImageStream(imagePath));
	}
	else if(!stricmp(extension.c_str(), ".cso"))
	{
		stream = std::make_shared<CCsoImageStream>(CreateImageStream(imagePath));
	}
#ifdef WIN32
	else if(imagePath.string()[0] == '\\')
	{
		stream = std::make_shared<Framework::Win32::CVolumeStream>(imagePath.string()[4]);
	}
#elif !defined(__ANDROID__) && !TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR
	else
	{
		try
		{
			stream = std::make_shared<Framework::Posix::CVolumeStream>(path);
		}
		catch(...)
		{
			//Ok if it fails here, might be a standard ISO image file
			//which will be handled below
		}
	}
#endif

	//If it's null after all that, just feed it to a StdStream
	if(!stream)
	{
		stream = std::shared_ptr<Framework::CStream>(CreateImageStream(imagePath));
	}

	Iso9660Ptr result;
	try
	{
		auto blockProvider = std::make_shared<ISO9660::CBlockProvider2048>(stream);
		result = std::make_unique<CISO9660>(blockProvider);
	}
	catch(...)
	{
		//Failed with block size 2048, try with CD-ROM XA
		auto blockProvider = std::make_shared<ISO9660::CBlockProviderCDROMXA>(stream);
		result = std::make_unique<CISO9660>(blockProvider);
	}
	return result;
}

DiskUtils::SystemConfigMap DiskUtils::ParseSystemConfigFile(Framework::CStream* systemCnfFile)
{
	SystemConfigMap result;
	auto line = Utils::GetLine(systemCnfFile);
	while(!systemCnfFile->IsEOF())
	{
		auto trimmedEnd = std::remove_if(line.begin(), line.end(), isspace);
		auto trimmedLine = std::string(line.begin(), trimmedEnd);
		std::vector<std::string> components;
		boost::split(components, trimmedLine, boost::is_any_of("="), boost::algorithm::token_compress_on);
		if(components.size() >= 2)
		{
			result.insert(std::make_pair(components[0], components[1]));
		}
		line = Utils::GetLine(systemCnfFile);
	}
	return result;
}

static std::string GetDiskIdFromPath(const std::string& filePath)
{
	//Expecting something like SCUS_XXX.XX;1
	if(filePath.length() < 13)
	{
		throw std::runtime_error("File name too short");
	}

	auto subFilePath = filePath.substr(filePath.length() - 13);
	auto regionCode = subFilePath.substr(0, 4);
	auto serial1 = subFilePath.substr(5, 3);
	auto serial2 = subFilePath.substr(9, 2);
	return regionCode + "_" + serial1 + "." + serial2;
}

bool DiskUtils::TryGetDiskId(const boost::filesystem::path& imagePath, std::string* diskIdPtr)
{
	try
	{
		auto diskImage = CreateDiskImageFromPath(imagePath);
		auto systemConfigFile = std::unique_ptr<Framework::CStream>(diskImage->Open("SYSTEM.CNF;1"));
		if(!systemConfigFile) return false;

		auto systemConfig = ParseSystemConfigFile(systemConfigFile.get());
		auto bootItemIterator = systemConfig.find("BOOT2");
		if(bootItemIterator == std::end(systemConfig)) return false;

		auto diskId = GetDiskIdFromPath(bootItemIterator->second);
		if(diskIdPtr)
		{
			(*diskIdPtr) = diskId;
		}
		return true;
	}
	catch(const std::exception&)
	{
		return false;
	}
}
<|endoftext|>


<commit_before>/// PrecompData_test.cpp

/** Test the PrecompData class
 */

#include "PrecompData.h"
#include "PrecompData_test.h"
#include <cmath>
#include <iostream>
#include <string>
#include <vector>

using namespace std;
using Utilities::PrecompData;

typedef PrecompData<float, float, 2, 1> pcd21;  // f: (X, Y) --> Z

float TestFunc(float x) {
	return sin(x);
}

float TestFuncLin(float x) {            //   y = 2x
    return 2*x;
}

float TestFuncNonLin1(float x) {        //   y = |x|
    return fabs(x);
}

float TestFuncNonLin2(float x) {        //   y = 1/(|x-2| + 0.1)
    return 1/(fabs(x - 2.0f) + 0.1f);
}

float TestFuncNonLinSin(float x) {      //   y = sin(x)
    return sin(x);
}

pcd21::Y TestFunc21(pcd21::X x) {       //   y = sin(x0) + cos(x1)
    return pcd21::Y { sin(x[0]) + cos(x[1]) };
}

namespace Utilities {

PrecompData_test::PrecompData_test()
{
	using namespace Utilities;

    cout << std::fixed;

    const int nValues = 20;

    // Test 1 - Interpolation
	{
        cout << "\n\nTest 1: Zero-degree (nearest-neighbor/point sampling/Voronoi) interpolation:" << endl;
		const string funcName = "TestFunc";
		PrecompData<> itp(funcName);    // default: float type
		itp.SetComment("TestFunc approximation");
		const float x0 = 0.0f, x1 = 6.28f;
		const float step = 0.5f*(x1 - x0)/nValues;
		itp.Set(&TestFunc, x0, x1, nValues);
		float x = x0;
        float err = 0.0f;
		for(int i = 0; i < nValues; ++i) {
            const float y = itp(x);
            err += fabs(TestFunc(x) - y);
			cout << i << ":\t" << funcName << "(" << x << ") = " << TestFunc(x) << " ~ " << y << endl;
			x += step;
		}
        cout << "Total error = " << err << endl;
	}
#if 0
    // Test 2 - Interpolation
    {
        cout << "\n\nTest 2: Linear interpolation:" << endl;
        const string funcName = "TestFunc";
        PrecompData<float> itp(funcName);
        const float x0 = 0.0f, x1 = 6.28f;
        const float step = 0.5*(x1 - x0)/nValues;
        itp.Set(&TestFunc, x0, x1, nValues);
        float x = x0;
        float err = 0.0;
        itp.Interpolation(1);
        cout << "Interpolation: " << itp.Interpolation() << endl;
        for(int i = 0; i < nValues; ++i) {
            const float y = itp.Interpolate(x);
            err += fabs(TestFunc(x) - y);
            cout << i << ":\t" << funcName << "(" << x << ") = " << TestFunc(x) << " ~ " << y << endl;
            x += step;
        }
        cout << "Total error = " << err << endl;
    }

    // Test 3 - AutoSet:  y = 2x
    {
        cout << "\n\nTest 3: Automatic irregular grid:    y = 2x" << endl;
        const string funcName = "y = 2x";
        PrecompData<float> itp(funcName);
        const float x0 = 0.0f, x1 = 6.28f;
        itp.AutoSet(&TestFuncLin, x0, x1, nValues);
        cerr << "x0 = " << x0 << "  x1 = " << x1 << "  nValues = " << nValues << endl;  //+T+
        std::vector<float> vx, vy;
        itp.Get(vx, vy);
        cout << "Sizes:  x = " << vx.size() << ";  y = " << vy.size() << endl;
        for(size_t i = 0; i < nValues; ++i) {
            cout << i << ":  " << vx[i] << ", " << vy[i] << endl;
        }
    }

    // Test 4 - AutoSet:  y = 1/(|x-2| + 0.1)
    {
        cout << "\n\nTest 4: Automatic irregular grid:    y = 1/(|x-2| + 0.1)" << endl;
        const string funcName = "y = 1/(|x-2| + 0.1)";
        PrecompData<float> itp(funcName);
        const float x0 = 0.0f, x1 = 6.28f;
        itp.AutoSet(&TestFuncNonLin2, x0, x1, nValues);
        cerr << "x0 = " << x0 << "  x1 = " << x1 << "  nValues = " << nValues << endl;  //+T+
        std::vector<float> vx, vy;
        itp.Get(vx, vy);
        cout << "Sizes:  x = " << vx.size() << ";  y = " << vy.size() << endl;
        for(size_t i = 0; i < nValues; ++i) {
            cout << i << ":  " << vx[i] << ", " << vy[i] << endl;
        }
    }

    // Test 5 - Derivatives
    {
        cout << "\n\nTest 5: Derivatives" << endl;
        int nTests = 0, nFailed = 0;
        const string funcName = "Derivatives";
        float x1, y1, x2, y2, x3, y3, der1, der2, expRes;
        PrecompData<float> test;

        // First derivative
        x1 = 0.0; y1 = 0.0; x2 = 1.0; y2 = 0.0; expRes = 0.0;
        der1 = test.FirstDerivative(x1, y1, x2, y2);
        ++nTests;
        if(fabs(der1 - expRes) > 0.0001) {
            ++nFailed;
            cerr << "Error - First derivative 1" << endl;
        }
        x1 = 0.0; y1 = 0.0; x2 = 1.0; y2 = 1.0; expRes = 1.0;
        der1 = test.FirstDerivative(x1, y1, x2, y2);
        ++nTests;
        if(fabs(der1 - expRes) > 0.0001) {
            ++nFailed;
            cerr << "Error - First derivative 2" << endl;
        }
        x1 = 1.0; y1 = 0.0; x2 = 0.0; y2 = 1.0; expRes = -1.0;
        der1 = test.FirstDerivative(x1, y1, x2, y2);
        ++nTests;
        if(fabs(der1 - expRes) > 0.0001) {
            ++nFailed;
            cerr << "Error - First derivative 3" << endl;
        }
        x1 = 0.0; y1 = 0.0; x2 = 2.0; y2 = 1.0; expRes = 0.5;
        der1 = test.FirstDerivative(x1, y1, x2, y2);
        ++nTests;
        if(fabs(der1 - expRes) > 0.0001) {
            ++nFailed;
            cerr << "Error - First derivative 4" << endl;
        }
        x1 = 0.0; y1 = -1.0; x2 = 1.0; y2 = 1.0; expRes = 2.0;
        der1 = test.FirstDerivative(x1, y1, x2, y2);
        ++nTests;
        if(fabs(der1 - expRes) > 0.0001) {
            ++nFailed;
            cerr << "Error - First derivative 5" << endl;
        }
        x1 = 0.0; y1 = 1.0; x2 = 1.0; y2 = 1.0; expRes = 0.0;
        der1 = test.FirstDerivative(x1, y1, x2, y2);
        ++nTests;
        if(fabs(der1 - expRes) > 0.0001) {
            ++nFailed;
            cerr << "Error - First derivative 6" << endl;
        }

        // Second derivative
        x1 = 0.0; y1 = 0.0; x2 = 1.0; y2 = 0.0; x3 = 2.0; y3 = 0.0; expRes = 0.0;
        der2 = test.SecondDerivative(x1, y1, x2, y2, x3, y3);
        ++nTests;
        if(fabs(der2 - expRes) > 0.0001) {
            ++nFailed;
            cerr << "Error - Second derivative 1" << endl;
        }
        x1 = 0.0; y1 = 1.0; x2 = 1.0; y2 = 1.0; x3 = 2.0; y3 = 1.0; expRes = 0.0;
        der2 = test.SecondDerivative(x1, y1, x2, y2, x3, y3);
        ++nTests;
        if(fabs(der2 - expRes) > 0.0001) {
            ++nFailed;
            cerr << "Error - Second derivative 2" << endl;
        }
        x1 = 0.0; y1 = 0.0; x2 = 1.0; y2 = 1.0; x3 = 2.0; y3 = 2.0; expRes = 0.0;
        der2 = test.SecondDerivative(x1, y1, x2, y2, x3, y3);
        ++nTests;
        if(fabs(der2 - expRes) > 0.0001) {
            ++nFailed;
            cerr << "Error - Second derivative 3" << endl;
        }
        x1 = 0.0; y1 = 0.0; x2 = 1.0; y2 = 1.0; x3 = 2.0; y3 = 4.0; expRes = 2.0;
        der2 = test.SecondDerivative(x1, y1, x2, y2, x3, y3);
        ++nTests;
        if(fabs(der2 - expRes) > 0.0001) {
            ++nFailed;
            cerr << "Error - Second derivative 4: Result = " << der2 << "; Expected = " << expRes << endl;
        }

        cout << "Derivatives:  Number of tests = " << nTests << ";  Number of failures = " << nFailed << endl;
    }

    // Test 6 - AutoSet:  y = sin(x)
    // Result: values too concentrated in the points with high absolute second derivative
    {
        cout << "\n\nTest 6: Automatic irregular grid:    y = sin(x)" << endl;
        const string funcName = "y = sin(x)";
        PrecompData<float> itp(funcName);
        const float x0 = 0.0f, x1 = 6.28f;
        itp.SetOversampling(1.5f);
        itp.AutoSet(&TestFuncNonLinSin, x0, x1, nValues);
        cerr << "x0 = " << x0 << "  x1 = " << x1 << "  nValues = " << nValues << endl;  //+T+
        std::vector<float> vx, vy;
        itp.Get(vx, vy);
        cout << "Sizes:  x = " << vx.size() << ";  y = " << vy.size() << endl;
        for(size_t i = 0; i < nValues; ++i) {
            cout << i << ":  " << vx[i] << ", " << vy[i] << endl;
        }
        int n = 100;
        cout << "Compare approximation with real sin(x) function (done on " << n << " points):" << endl;
        float error = 0.0f, avgErr = 0.0f;
        float minErrX = 1.0e20f, minErrY = 1.0e20f;
        float maxErrX = 0.0f,    maxErrY = 0.0f;
        float x = x0, step = (x1 - x0)/n;
        for(int i = 0; i < n; ++i) {
            error = fabs(sin(x) - itp.Interpolate(x));
            cout << i << ": \t" << x << ", \t " << sin(x) << ", \t " << itp.Interpolate(x) << ", \t " << error << endl;
            if(error < minErrY) { minErrX = x; minErrY = error; }
            if(error > maxErrY) { maxErrX = x; maxErrY = error; }
            avgErr += error;
            x += step;
        }
        avgErr /= n;
        cout << "Result:  minimum error = [" << minErrX << ", " << minErrY
             <<      "];  maximum error = [" << maxErrX << ", " << maxErrY
             <<      "];  average error = " << avgErr << endl;
    }

    // Test 7 - Multidimensions
    {
        cout << "\n\nTest 7: Storage of data in an NxM space:" << endl;
        const string funcName = "Multidimensions";
        pcd21 itp(funcName);
        itp.SetComment("Y = f(X)    X = x(i,j), Y = y(i)");
        pcd21::X x0 = { 0.00f, 0.00f };     // coordinates of the starting point
        pcd21::X x1 = { 6.28f, 6.28f };     // coordinates of the end point
		const pcd21::X step = { 0.5f*(x1[0] - x0[0])/nValues,
		                        0.5f*(x1[1] - x0[1])/nValues };
        itp.Set(&TestFunc21, x0, x1, nValues*nValues);
        pcd21::X x = x0;
        float err = 0.0;
        for(int j = 0; j < nValues; ++j)
        {
            x[0] = x0[0];
            for(int i = 0; i < nValues; ++i)
            {
                const pcd21::Y y = itp(x);
                err += fabs(TestFunc21(x)[0] - y[0]);
                cout << i << ":\t" << funcName << "[" << x[0] << ", " << x[1] << "] = " << TestFunc21(x)[0] << " ~ " << y[0] << endl;
                x[0] += step[0];
            }
            x[1] += step[1];
        }
        cout << "Total error = " << err << endl;
    }
#endif
}

} // Utilities

int main()
{
    using namespace Utilities;

    PrecompData_test test;

    return 0;
}
<commit_msg>- Test 1: print interpolation order (0).<commit_after>/// PrecompData_test.cpp

/** Test the PrecompData class
 */

#include "PrecompData.h"
#include "PrecompData_test.h"
#include <cmath>
#include <iostream>
#include <string>
#include <vector>

using namespace std;
using Utilities::PrecompData;

typedef PrecompData<float, float, 2, 1> pcd21;  // f: (X, Y) --> Z

float TestFunc(float x) {
	return sin(x);
}

float TestFuncLin(float x) {            //   y = 2x
    return 2*x;
}

float TestFuncNonLin1(float x) {        //   y = |x|
    return fabs(x);
}

float TestFuncNonLin2(float x) {        //   y = 1/(|x-2| + 0.1)
    return 1/(fabs(x - 2.0f) + 0.1f);
}

float TestFuncNonLinSin(float x) {      //   y = sin(x)
    return sin(x);
}

pcd21::Y TestFunc21(pcd21::X x) {       //   y = sin(x0) + cos(x1)
    return pcd21::Y { sin(x[0]) + cos(x[1]) };
}

namespace Utilities {

PrecompData_test::PrecompData_test()
{
	using namespace Utilities;

    cout << std::fixed;

    const int nValues = 20;

    // Test 1 - Interpolation
	{
        cout << "\n\nTest 1: Zero-degree (nearest-neighbor/point sampling/Voronoi) interpolation:" << endl;
		const string funcName = "TestFunc";
		PrecompData<> itp(funcName);    // default: float type
		itp.SetComment("TestFunc approximation");
		const float x0 = 0.0f, x1 = 6.28f;
		const float step = 0.5f*(x1 - x0)/nValues;
		itp.Set(&TestFunc, x0, x1, nValues);
		float x = x0;
        float err = 0.0f;
        itp.Interpolation(0);
        cout << "Interpolation: " << itp.Interpolation() << endl;
		for(int i = 0; i < nValues; ++i) {
            const float y = itp(x);
            err += fabs(TestFunc(x) - y);
			cout << i << ":\t" << funcName << "(" << x << ") = " << TestFunc(x) << " ~ " << y << endl;
			x += step;
		}
        cout << "Total error = " << err << endl;
	}
#if 0
    // Test 2 - Interpolation
    {
        cout << "\n\nTest 2: Linear interpolation:" << endl;
        const string funcName = "TestFunc";
        PrecompData<float> itp(funcName);
        const float x0 = 0.0f, x1 = 6.28f;
        const float step = 0.5*(x1 - x0)/nValues;
        itp.Set(&TestFunc, x0, x1, nValues);
        float x = x0;
        float err = 0.0;
        itp.Interpolation(1);
        cout << "Interpolation: " << itp.Interpolation() << endl;
        for(int i = 0; i < nValues; ++i) {
            const float y = itp.Interpolate(x);
            err += fabs(TestFunc(x) - y);
            cout << i << ":\t" << funcName << "(" << x << ") = " << TestFunc(x) << " ~ " << y << endl;
            x += step;
        }
        cout << "Total error = " << err << endl;
    }

    // Test 3 - AutoSet:  y = 2x
    {
        cout << "\n\nTest 3: Automatic irregular grid:    y = 2x" << endl;
        const string funcName = "y = 2x";
        PrecompData<float> itp(funcName);
        const float x0 = 0.0f, x1 = 6.28f;
        itp.AutoSet(&TestFuncLin, x0, x1, nValues);
        cerr << "x0 = " << x0 << "  x1 = " << x1 << "  nValues = " << nValues << endl;  //+T+
        std::vector<float> vx, vy;
        itp.Get(vx, vy);
        cout << "Sizes:  x = " << vx.size() << ";  y = " << vy.size() << endl;
        for(size_t i = 0; i < nValues; ++i) {
            cout << i << ":  " << vx[i] << ", " << vy[i] << endl;
        }
    }

    // Test 4 - AutoSet:  y = 1/(|x-2| + 0.1)
    {
        cout << "\n\nTest 4: Automatic irregular grid:    y = 1/(|x-2| + 0.1)" << endl;
        const string funcName = "y = 1/(|x-2| + 0.1)";
        PrecompData<float> itp(funcName);
        const float x0 = 0.0f, x1 = 6.28f;
        itp.AutoSet(&TestFuncNonLin2, x0, x1, nValues);
        cerr << "x0 = " << x0 << "  x1 = " << x1 << "  nValues = " << nValues << endl;  //+T+
        std::vector<float> vx, vy;
        itp.Get(vx, vy);
        cout << "Sizes:  x = " << vx.size() << ";  y = " << vy.size() << endl;
        for(size_t i = 0; i < nValues; ++i) {
            cout << i << ":  " << vx[i] << ", " << vy[i] << endl;
        }
    }

    // Test 5 - Derivatives
    {
        cout << "\n\nTest 5: Derivatives" << endl;
        int nTests = 0, nFailed = 0;
        const string funcName = "Derivatives";
        float x1, y1, x2, y2, x3, y3, der1, der2, expRes;
        PrecompData<float> test;

        // First derivative
        x1 = 0.0; y1 = 0.0; x2 = 1.0; y2 = 0.0; expRes = 0.0;
        der1 = test.FirstDerivative(x1, y1, x2, y2);
        ++nTests;
        if(fabs(der1 - expRes) > 0.0001) {
            ++nFailed;
            cerr << "Error - First derivative 1" << endl;
        }
        x1 = 0.0; y1 = 0.0; x2 = 1.0; y2 = 1.0; expRes = 1.0;
        der1 = test.FirstDerivative(x1, y1, x2, y2);
        ++nTests;
        if(fabs(der1 - expRes) > 0.0001) {
            ++nFailed;
            cerr << "Error - First derivative 2" << endl;
        }
        x1 = 1.0; y1 = 0.0; x2 = 0.0; y2 = 1.0; expRes = -1.0;
        der1 = test.FirstDerivative(x1, y1, x2, y2);
        ++nTests;
        if(fabs(der1 - expRes) > 0.0001) {
            ++nFailed;
            cerr << "Error - First derivative 3" << endl;
        }
        x1 = 0.0; y1 = 0.0; x2 = 2.0; y2 = 1.0; expRes = 0.5;
        der1 = test.FirstDerivative(x1, y1, x2, y2);
        ++nTests;
        if(fabs(der1 - expRes) > 0.0001) {
            ++nFailed;
            cerr << "Error - First derivative 4" << endl;
        }
        x1 = 0.0; y1 = -1.0; x2 = 1.0; y2 = 1.0; expRes = 2.0;
        der1 = test.FirstDerivative(x1, y1, x2, y2);
        ++nTests;
        if(fabs(der1 - expRes) > 0.0001) {
            ++nFailed;
            cerr << "Error - First derivative 5" << endl;
        }
        x1 = 0.0; y1 = 1.0; x2 = 1.0; y2 = 1.0; expRes = 0.0;
        der1 = test.FirstDerivative(x1, y1, x2, y2);
        ++nTests;
        if(fabs(der1 - expRes) > 0.0001) {
            ++nFailed;
            cerr << "Error - First derivative 6" << endl;
        }

        // Second derivative
        x1 = 0.0; y1 = 0.0; x2 = 1.0; y2 = 0.0; x3 = 2.0; y3 = 0.0; expRes = 0.0;
        der2 = test.SecondDerivative(x1, y1, x2, y2, x3, y3);
        ++nTests;
        if(fabs(der2 - expRes) > 0.0001) {
            ++nFailed;
            cerr << "Error - Second derivative 1" << endl;
        }
        x1 = 0.0; y1 = 1.0; x2 = 1.0; y2 = 1.0; x3 = 2.0; y3 = 1.0; expRes = 0.0;
        der2 = test.SecondDerivative(x1, y1, x2, y2, x3, y3);
        ++nTests;
        if(fabs(der2 - expRes) > 0.0001) {
            ++nFailed;
            cerr << "Error - Second derivative 2" << endl;
        }
        x1 = 0.0; y1 = 0.0; x2 = 1.0; y2 = 1.0; x3 = 2.0; y3 = 2.0; expRes = 0.0;
        der2 = test.SecondDerivative(x1, y1, x2, y2, x3, y3);
        ++nTests;
        if(fabs(der2 - expRes) > 0.0001) {
            ++nFailed;
            cerr << "Error - Second derivative 3" << endl;
        }
        x1 = 0.0; y1 = 0.0; x2 = 1.0; y2 = 1.0; x3 = 2.0; y3 = 4.0; expRes = 2.0;
        der2 = test.SecondDerivative(x1, y1, x2, y2, x3, y3);
        ++nTests;
        if(fabs(der2 - expRes) > 0.0001) {
            ++nFailed;
            cerr << "Error - Second derivative 4: Result = " << der2 << "; Expected = " << expRes << endl;
        }

        cout << "Derivatives:  Number of tests = " << nTests << ";  Number of failures = " << nFailed << endl;
    }

    // Test 6 - AutoSet:  y = sin(x)
    // Result: values too concentrated in the points with high absolute second derivative
    {
        cout << "\n\nTest 6: Automatic irregular grid:    y = sin(x)" << endl;
        const string funcName = "y = sin(x)";
        PrecompData<float> itp(funcName);
        const float x0 = 0.0f, x1 = 6.28f;
        itp.SetOversampling(1.5f);
        itp.AutoSet(&TestFuncNonLinSin, x0, x1, nValues);
        cerr << "x0 = " << x0 << "  x1 = " << x1 << "  nValues = " << nValues << endl;  //+T+
        std::vector<float> vx, vy;
        itp.Get(vx, vy);
        cout << "Sizes:  x = " << vx.size() << ";  y = " << vy.size() << endl;
        for(size_t i = 0; i < nValues; ++i) {
            cout << i << ":  " << vx[i] << ", " << vy[i] << endl;
        }
        int n = 100;
        cout << "Compare approximation with real sin(x) function (done on " << n << " points):" << endl;
        float error = 0.0f, avgErr = 0.0f;
        float minErrX = 1.0e20f, minErrY = 1.0e20f;
        float maxErrX = 0.0f,    maxErrY = 0.0f;
        float x = x0, step = (x1 - x0)/n;
        for(int i = 0; i < n; ++i) {
            error = fabs(sin(x) - itp.Interpolate(x));
            cout << i << ": \t" << x << ", \t " << sin(x) << ", \t " << itp.Interpolate(x) << ", \t " << error << endl;
            if(error < minErrY) { minErrX = x; minErrY = error; }
            if(error > maxErrY) { maxErrX = x; maxErrY = error; }
            avgErr += error;
            x += step;
        }
        avgErr /= n;
        cout << "Result:  minimum error = [" << minErrX << ", " << minErrY
             <<      "];  maximum error = [" << maxErrX << ", " << maxErrY
             <<      "];  average error = " << avgErr << endl;
    }

    // Test 7 - Multidimensions
    {
        cout << "\n\nTest 7: Storage of data in an NxM space:" << endl;
        const string funcName = "Multidimensions";
        pcd21 itp(funcName);
        itp.SetComment("Y = f(X)    X = x(i,j), Y = y(i)");
        pcd21::X x0 = { 0.00f, 0.00f };     // coordinates of the starting point
        pcd21::X x1 = { 6.28f, 6.28f };     // coordinates of the end point
		const pcd21::X step = { 0.5f*(x1[0] - x0[0])/nValues,
		                        0.5f*(x1[1] - x0[1])/nValues };
        itp.Set(&TestFunc21, x0, x1, nValues*nValues);
        pcd21::X x = x0;
        float err = 0.0;
        for(int j = 0; j < nValues; ++j)
        {
            x[0] = x0[0];
            for(int i = 0; i < nValues; ++i)
            {
                const pcd21::Y y = itp(x);
                err += fabs(TestFunc21(x)[0] - y[0]);
                cout << i << ":\t" << funcName << "[" << x[0] << ", " << x[1] << "] = " << TestFunc21(x)[0] << " ~ " << y[0] << endl;
                x[0] += step[0];
            }
            x[1] += step[1];
        }
        cout << "Total error = " << err << endl;
    }
#endif
}

} // Utilities

int main()
{
    using namespace Utilities;

    PrecompData_test test;

    return 0;
}
<|endoftext|>


<commit_before>/**************************************************************
COSC 501
Elliott Plack
14 NOV 2013                            Due date: 30 NOV 2013

Problem:
	Write a program that plays the game of HANGMAN(guessing a
	mystery word).  Read a word to be guessed from a file into
	successive elements of the array WORD. The player must
	guess the letters belonging to WORD. A single guessing
	session should be terminated when either all letters have
	been guessed correctly (player wins) or a specified number
	of incorrect guesses have been made (computer wins). A run
	must consist of at least two sessions: one player wins and
	one computer wins. The player decides whether or not to
	start a new session.

***************************************************************/

#include <iomanip>
#include <iostream>
#include <fstream>
#include <string>
#include <time.h> // for random
using namespace std;

ifstream inFile;     // define ifstream to inFile command
ofstream outFile;    // define outfile2

void readString();
void initialize(unsigned long); // function to initalize everything
void guess();

// global variables
//char guess; // guess from user
string word; // word to be read from file (the solution)
string solution; // solution (guessed by user)
unsigned long wordLength; // length of word

// functions

int main() // reads in the file and sets the functions in motion
{
	readString();
	initialize(wordLength); // sends length of word to initialize function
	cout << "Let's play hangman!\n";
	guess();

	return 0;
}

void readString()
{
	int random20 = 0; // random number
	string dictionary[20]; // 20 words to load from file

	inFile.open("Words4Hangman.txt"); // open input file

	while (inFile.good())
	{
		for (int i = 0; i < 20; i++)
		{
			inFile >> dictionary[i]; // load file and fill dict
		}
	}

	inFile.close(); // close the file

	srand((int)time(NULL)); // initialize random seed
	random20 = (rand() % 20); // set random to 20 +-

	word = dictionary[rand() % 20]; // set word = to a random letter in the dictionary
	cout << word << endl; // cheater! (testing)
	wordLength = word.size(); // size (length) of the string
}

void initialize(unsigned long wordLength)
{
	solution.assign(wordLength, '*');
}

void guess()
{
	char guessLetter = ' '; // letter to guess
	string solutionOld = solution; // solution string to compare with
	int winning = 0; // variable to check if won

	cout << solution << endl; // output solution
	cout << "Guess a letter\n";
	cin >> guessLetter;

	while (winning == 0)
	{
		for (unsigned long i = 0; i < wordLength; i++)
		{
			if (guessLetter == word[i])
			{
				cout << "char " << (i + 1) /* +1 because first is 0*/ << " is " << guessLetter << endl;
				solution[i] = guessLetter;
			}
		}

		if (solutionOld.compare(solution) != 0) // check if solution has changed
		{
			cout << "Good guess!\n"
				<< solution << endl; // display positive
			solutionOld = solution; // set compare string to old for next run.
		}
	}
}<commit_msg>working (logic errors)<commit_after>/**************************************************************
COSC 501
Elliott Plack
14 NOV 2013                            Due date: 30 NOV 2013

Problem:
	Write a program that plays the game of HANGMAN(guessing a
	mystery word).  Read a word to be guessed from a file into
	successive elements of the array WORD. The player must
	guess the letters belonging to WORD. A single guessing
	session should be terminated when either all letters have
	been guessed correctly (player wins) or a specified number
	of incorrect guesses have been made (computer wins). A run
	must consist of at least two sessions: one player wins and
	one computer wins. The player decides whether or not to
	start a new session.

***************************************************************/

#include <iomanip>
#include <iostream>
#include <fstream>
#include <string>
#include <time.h> // for random
using namespace std;

ifstream inFile;     // define ifstream to inFile command
ofstream outFile;    // define outfile2

void readString();
void initialize(unsigned long); // function to initalize everything
void guess();

// global variables
//char guess; // guess from user
string word; // word to be read from file (the solution)
string solution; // solution (guessed by user)
unsigned long wordLength; // length of word

// functions

int main() // reads in the file and sets the functions in motion
{
	readString();
	initialize(wordLength); // sends length of word to initialize function
	cout << "Let's play hangman!\n";
	guess();

	return 0;
}

void readString()
{
	int random20 = 0; // random number
	string dictionary[20]; // 20 words to load from file

	inFile.open("Words4Hangman.txt"); // open input file

	while (inFile.good())
	{
		for (int i = 0; i < 20; i++)
		{
			inFile >> dictionary[i]; // load file and fill dict
		}
	}

	inFile.close(); // close the file

	srand((int)time(NULL)); // initialize random seed
	random20 = (rand() % 20); // set random to 20 +-

	word = dictionary[rand() % 20]; // set word = to a random letter in the dictionary
	cout << word << endl; // cheater! (testing)
	wordLength = word.size(); // size (length) of the string
}

void initialize(unsigned long wordLength)
{
	solution.assign(wordLength, '*');
}

void guess()
{
	char guessLetter = ' '; // letter to guess
	string solutionOld = solution; // solution string to compare with
	int winning = 0; // variable to check if won
	int guessesCounter = 7;

	cout << solution << endl; // output solution
	cout << "Guess a letter\n";
	cin >> guessLetter;

	while ((guessesCounter > 0) && (winning == 0)) //
	{
		for (unsigned long i = 0; i < wordLength; i++) // loop through word looking for guess
		{
			if (guessLetter == word[i])
			{
				cout << "char " << (i + 1) /* +1 because first is 0*/ << " is " << guessLetter << endl; // outputs that guess was correct
				solution[i] = guessLetter;
			}
		}

		if (solutionOld.compare(solution) != 0) // check if solution has changed
		{
			if (solution == word) // thus victory
			{
				winning = 1; // you won
				cout << "Victory!\n"; // quick output for testing
			}
			else
			{
				cout << "Good guess!\n"
					<< solution << endl; // display positive
				solutionOld = solution; // set compare string to old for next run.
			}
		}
		else
		{
			guessesCounter--; // decrement guess
			cout << "The letter " << guessLetter << " does not appear in the word.\n"
				<< "You have " << guessesCounter << "remaining.\n"
				<< "Enter another letter: ";
			cin >> guessLetter;
		}
	}
}<|endoftext|>


<commit_before>//
// OpenFlight loader for OpenSceneGraph
//
//  Copyright (C) 2005-2006  Brede Johansen
//

#include <osgSim/OpenFlightOptimizer>

#include <osg/Notify>
#include <osg/Geode>

#include <osgUtil/Tesselator>
#include <osgUtil/Optimizer>

#include <vector>
#include <map>

using namespace osgFlightUtil;

void Optimizer::optimize(osg::Node* node)
{
    unsigned int options = 0;

    const char* env = getenv("OSG_FLIGHTUTIL_OPTIMIZER");
    if (env)
    {
        std::string str(env);

        if(str.find("OFF")!=std::string::npos) options = 0;

        if(str.find("~DEFAULT")!=std::string::npos) options ^= DEFAULT_OPTIMIZATIONS;
        else if(str.find("DEFAULT")!=std::string::npos) options |= DEFAULT_OPTIMIZATIONS;

        if(str.find("~TESSELATE_POLYGON")!=std::string::npos) options ^= TESSELATE_POLYGON;
        else if(str.find("TESSELATE_POLYGON")!=std::string::npos) options |= TESSELATE_POLYGON;

        if(str.find("~MAKE_LIT")!=std::string::npos) options ^= MAKE_LIT;
        else if(str.find("MAKE_LIT")!=std::string::npos) options |= MAKE_LIT;

        if(str.find("~MERGE_GEODES")!=std::string::npos) options ^= MERGE_GEODES;
        else if(str.find("MERGE_GEODES")!=std::string::npos) options |= MERGE_GEODES;
    }
    else
    {
        options = DEFAULT_OPTIMIZATIONS;
    }

    optimize(node,options);
}

void Optimizer::optimize(osg::Node* node, unsigned int options)
{
    if (options & TESSELATE_POLYGON)
    {
        osg::notify(osg::INFO)<<"osgFlightUtil::Optimizer::optimize() doing TESSELATE_POLYGON"<<std::endl;

        TesselateVisitor visitor;
        node->accept(visitor);
    }

    if (options & MAKE_LIT)
    {
        osg::notify(osg::INFO)<<"osgFlightUtil::Optimizer::optimize() doing MAKE_LIT"<<std::endl;

        MakeLitVisitor visitor;
        node->accept(visitor);
    }

    if (options & MERGE_GEODES)
    {
        osg::notify(osg::INFO)<<"osgFlightUtil::Optimizer::optimize() doing MERGE_GEODES"<<std::endl;

        MergeGeodesVisitor visitor;
        node->accept(visitor);
    }
}

void Optimizer::TesselateVisitor::apply(osg::Geode& geode)
{
    for (unsigned int i=0; i<geode.getNumDrawables(); ++i)
    {
        osg::Geometry* geometry = dynamic_cast<osg::Geometry*>(geode.getDrawable(i));
        if (geometry)
        {
            if (hasPolygons(*geometry))
            {
                // Tesselate
                osgUtil::Tesselator tesselator;
                tesselator.retesselatePolygons(*geometry);
            }
        }
    }
}

bool Optimizer::TesselateVisitor::hasPolygons(osg::Geometry& geometry)
{
    for (unsigned int i=0; i<geometry.getNumPrimitiveSets(); ++i)
    {
        if (geometry.getPrimitiveSet(i)->getMode() == osg::PrimitiveSet::POLYGON)
            return true;
    }

    return false;
}

void Optimizer::MakeLitVisitor::apply(osg::Geode& /*geode*/)
{
#if 0 // TODO
    osg::StateSet* stateset = geode.getStateSet();
    if (stateset)
    {
        // Not lit?
        if (!(stateset->getMode(GL_LIGHTING)&osg::StateAttribute::ON))
        {
            stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON);
            for (unsigned int i=0; i<geode.getNumDrawables(); ++i)
            {
                osg::Geometry* geometry = dynamic_cast<osg::Geometry*>(geode.getDrawable(i));
                if (geometry)
                {
                    if () TODO Compare vertex array length and normal array length + normal binding.
                    {
                        // generate normals
                        osgUtil::SmoothingVisitor smoother;
                        smoother.smooth(*geometry);
                    }
                }
            }
        }
    }
#endif
}

/** Need to share stateset before merging geodes.
  */
class GeodeStateOptimizer : public osgUtil::Optimizer::StateVisitor
{
    public:

        GeodeStateOptimizer():
            osgUtil::Optimizer::StateVisitor() {}

        void optimize(osg::Group& group)
        {
            for (unsigned int i=0; i<group.getNumChildren(); ++i)
            {
                osg::Node* child = group.getChild(i);
                if (typeid(*child)==typeid(osg::Geode))
                {
                    osg::Geode* geode = (osg::Geode*)child;
                    addStateSet(geode->getStateSet(),geode);
                }
            }

            osgUtil::Optimizer::StateVisitor::optimize();
        }

};

void Optimizer::MergeGeodesVisitor::apply(osg::Group& group)
{
    mergeGeodes(group);
    traverse(group);
}

// Requires shared stateset to work. Run GeodeStateOptimizer before MergeGeodesVisitor.
struct LessGeode
{
    bool operator() (const osg::Geode* lhs,const osg::Geode* rhs) const
    {
        if (lhs->getStateSet()<rhs->getStateSet()) return true;
//      if (rhs->getStateSet()<lhs->getStateSet()) return false;
        return false;
    }
};

void Optimizer::MergeGeodesVisitor::mergeGeodes(osg::Group& group)
{
    {
        GeodeStateOptimizer gsopt;
        gsopt.optimize(group);
    }

    typedef std::vector<osg::Geode*>                      DuplicateList;
    typedef std::map<osg::Geode*,DuplicateList,LessGeode> GeodeDuplicateMap;

    GeodeDuplicateMap geodeDuplicateMap;

    for (unsigned int i=0; i<group.getNumChildren(); ++i)
    {
        osg::Node* child = group.getChild(i);
        if (typeid(*child)==typeid(osg::Geode))
        {
            osg::Geode* geode = (osg::Geode*)child;
            geodeDuplicateMap[geode].push_back(geode);
        }
    }

    // merge
    for(GeodeDuplicateMap::iterator itr=geodeDuplicateMap.begin();
        itr!=geodeDuplicateMap.end();
        ++itr)
    {
        if (itr->second.size()>1)
        {
            osg::Geode* lhs = itr->second[0];
            for(DuplicateList::iterator dupItr=itr->second.begin()+1;
                dupItr!=itr->second.end();
                ++dupItr)
            {
                osg::Geode* rhs = *dupItr;

                if (mergeGeode(*lhs,*rhs))
                {
                    group.removeChild(rhs);

                    static int co = 0;
                    osg::notify(osg::INFO)<<"merged and removed Geode "<<++co<<std::endl;
                }
            }
        }
    }
}

bool Optimizer::MergeGeodesVisitor::mergeGeode(osg::Geode& lhs, osg::Geode& rhs)
{
    for (unsigned int i=0; i<rhs.getNumDrawables(); ++i)
    {
        lhs.addDrawable(rhs.getDrawable(i));
    }

    return true;
}
<commit_msg>Removed explict definition of osgUtil::Optimizer::StateVisitor to attempt to get round VS 6.0 cruddiness.<commit_after>//
// OpenFlight loader for OpenSceneGraph
//
//  Copyright (C) 2005-2006  Brede Johansen
//

#include <osgSim/OpenFlightOptimizer>

#include <osg/Notify>
#include <osg/Geode>

#include <osgUtil/Tesselator>
#include <osgUtil/Optimizer>

#include <vector>
#include <map>

using namespace osgFlightUtil;

void Optimizer::optimize(osg::Node* node)
{
    unsigned int options = 0;

    const char* env = getenv("OSG_FLIGHTUTIL_OPTIMIZER");
    if (env)
    {
        std::string str(env);

        if(str.find("OFF")!=std::string::npos) options = 0;

        if(str.find("~DEFAULT")!=std::string::npos) options ^= DEFAULT_OPTIMIZATIONS;
        else if(str.find("DEFAULT")!=std::string::npos) options |= DEFAULT_OPTIMIZATIONS;

        if(str.find("~TESSELATE_POLYGON")!=std::string::npos) options ^= TESSELATE_POLYGON;
        else if(str.find("TESSELATE_POLYGON")!=std::string::npos) options |= TESSELATE_POLYGON;

        if(str.find("~MAKE_LIT")!=std::string::npos) options ^= MAKE_LIT;
        else if(str.find("MAKE_LIT")!=std::string::npos) options |= MAKE_LIT;

        if(str.find("~MERGE_GEODES")!=std::string::npos) options ^= MERGE_GEODES;
        else if(str.find("MERGE_GEODES")!=std::string::npos) options |= MERGE_GEODES;
    }
    else
    {
        options = DEFAULT_OPTIMIZATIONS;
    }

    optimize(node,options);
}

void Optimizer::optimize(osg::Node* node, unsigned int options)
{
    if (options & TESSELATE_POLYGON)
    {
        osg::notify(osg::INFO)<<"osgFlightUtil::Optimizer::optimize() doing TESSELATE_POLYGON"<<std::endl;

        TesselateVisitor visitor;
        node->accept(visitor);
    }

    if (options & MAKE_LIT)
    {
        osg::notify(osg::INFO)<<"osgFlightUtil::Optimizer::optimize() doing MAKE_LIT"<<std::endl;

        MakeLitVisitor visitor;
        node->accept(visitor);
    }

    if (options & MERGE_GEODES)
    {
        osg::notify(osg::INFO)<<"osgFlightUtil::Optimizer::optimize() doing MERGE_GEODES"<<std::endl;

        MergeGeodesVisitor visitor;
        node->accept(visitor);
    }
}

void Optimizer::TesselateVisitor::apply(osg::Geode& geode)
{
    for (unsigned int i=0; i<geode.getNumDrawables(); ++i)
    {
        osg::Geometry* geometry = dynamic_cast<osg::Geometry*>(geode.getDrawable(i));
        if (geometry)
        {
            if (hasPolygons(*geometry))
            {
                // Tesselate
                osgUtil::Tesselator tesselator;
                tesselator.retesselatePolygons(*geometry);
            }
        }
    }
}

bool Optimizer::TesselateVisitor::hasPolygons(osg::Geometry& geometry)
{
    for (unsigned int i=0; i<geometry.getNumPrimitiveSets(); ++i)
    {
        if (geometry.getPrimitiveSet(i)->getMode() == osg::PrimitiveSet::POLYGON)
            return true;
    }

    return false;
}

void Optimizer::MakeLitVisitor::apply(osg::Geode& /*geode*/)
{
#if 0 // TODO
    osg::StateSet* stateset = geode.getStateSet();
    if (stateset)
    {
        // Not lit?
        if (!(stateset->getMode(GL_LIGHTING)&osg::StateAttribute::ON))
        {
            stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON);
            for (unsigned int i=0; i<geode.getNumDrawables(); ++i)
            {
                osg::Geometry* geometry = dynamic_cast<osg::Geometry*>(geode.getDrawable(i));
                if (geometry)
                {
                    if () TODO Compare vertex array length and normal array length + normal binding.
                    {
                        // generate normals
                        osgUtil::SmoothingVisitor smoother;
                        smoother.smooth(*geometry);
                    }
                }
            }
        }
    }
#endif
}

/** Need to share stateset before merging geodes.
  */
class GeodeStateOptimizer : public osgUtil::Optimizer::StateVisitor
{
    public:

        GeodeStateOptimizer():
            osgUtil::Optimizer::StateVisitor() {}

        void optimize(osg::Group& group)
        {
            for (unsigned int i=0; i<group.getNumChildren(); ++i)
            {
                osg::Node* child = group.getChild(i);
                if (typeid(*child)==typeid(osg::Geode))
                {
                    osg::Geode* geode = (osg::Geode*)child;
                    addStateSet(geode->getStateSet(),geode);
                }
            }

            StateVisitor::optimize();
        }

};

void Optimizer::MergeGeodesVisitor::apply(osg::Group& group)
{
    mergeGeodes(group);
    traverse(group);
}

// Requires shared stateset to work. Run GeodeStateOptimizer before MergeGeodesVisitor.
struct LessGeode
{
    bool operator() (const osg::Geode* lhs,const osg::Geode* rhs) const
    {
        if (lhs->getStateSet()<rhs->getStateSet()) return true;
//      if (rhs->getStateSet()<lhs->getStateSet()) return false;
        return false;
    }
};

void Optimizer::MergeGeodesVisitor::mergeGeodes(osg::Group& group)
{
    {
        GeodeStateOptimizer gsopt;
        gsopt.optimize(group);
    }

    typedef std::vector<osg::Geode*>                      DuplicateList;
    typedef std::map<osg::Geode*,DuplicateList,LessGeode> GeodeDuplicateMap;

    GeodeDuplicateMap geodeDuplicateMap;

    for (unsigned int i=0; i<group.getNumChildren(); ++i)
    {
        osg::Node* child = group.getChild(i);
        if (typeid(*child)==typeid(osg::Geode))
        {
            osg::Geode* geode = (osg::Geode*)child;
            geodeDuplicateMap[geode].push_back(geode);
        }
    }

    // merge
    for(GeodeDuplicateMap::iterator itr=geodeDuplicateMap.begin();
        itr!=geodeDuplicateMap.end();
        ++itr)
    {
        if (itr->second.size()>1)
        {
            osg::Geode* lhs = itr->second[0];
            for(DuplicateList::iterator dupItr=itr->second.begin()+1;
                dupItr!=itr->second.end();
                ++dupItr)
            {
                osg::Geode* rhs = *dupItr;

                if (mergeGeode(*lhs,*rhs))
                {
                    group.removeChild(rhs);

                    static int co = 0;
                    osg::notify(osg::INFO)<<"merged and removed Geode "<<++co<<std::endl;
                }
            }
        }
    }
}

bool Optimizer::MergeGeodesVisitor::mergeGeode(osg::Geode& lhs, osg::Geode& rhs)
{
    for (unsigned int i=0; i<rhs.getNumDrawables(); ++i)
    {
        lhs.addDrawable(rhs.getDrawable(i));
    }

    return true;
}
<|endoftext|>