<commit_before>/*************************************************
* Noekeon Source File                            *
* (C) 1999-2008 Jack Lloyd                       *
*************************************************/

#include <botan/noekeon.h>
#include <botan/loadstor.h>
#include <botan/bit_ops.h>

namespace Botan {

namespace {

inline void theta(u32bit& A0, u32bit& A1,
                  u32bit& A2, u32bit& A3,
                  const u32bit EK[4])
   {
   u32bit T = A0 ^ A2;
   T ^= rotate_left(T, 8) ^ rotate_right(T, 8);
   A1 ^= T;
   A3 ^= T;

   A0 ^= EK[0];
   A1 ^= EK[1];
   A2 ^= EK[2];
   A3 ^= EK[3];

   T = A1 ^ A3;
   T ^= rotate_left(T, 8) ^ rotate_right(T, 8);
   A0 ^= T;
   A2 ^= T;
   }

inline void gamma(u32bit& A0, u32bit& A1, u32bit& A2, u32bit& A3)
   {
   A1 ^= ~A3 & ~A2;
   A0 ^= A2 & A1;

   u32bit T = A3;
   A3 = A0;
   A0 = T;

   A2 ^= A0 ^ A1 ^ A3;

   A1 ^= ~A3 & ~A2;
   A0 ^= A2 & A1;
   }

}

/*************************************************
* Noekeon Round Constants                        *
*************************************************/
const byte Noekeon::RC[] = {
   0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A,
   0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A,
   0xD4 };

/*************************************************
* Noekeon Encryption                             *
*************************************************/
void Noekeon::enc(const byte in[], byte out[]) const
   {
   u32bit A0 = load_be<u32bit>(in, 0);
   u32bit A1 = load_be<u32bit>(in, 1);
   u32bit A2 = load_be<u32bit>(in, 2);
   u32bit A3 = load_be<u32bit>(in, 3);

   for(u32bit j = 0; j != 16; ++j)
      {
      A0 ^= RC[j];
      theta(A0, A1, A2, A3, EK);

      A1 = rotate_left(A1, 1);
      A2 = rotate_left(A2, 5);
      A3 = rotate_left(A3, 2);

      gamma(A0, A1, A2, A3);

      A1 = rotate_right(A1, 1);
      A2 = rotate_right(A2, 5);
      A3 = rotate_right(A3, 2);
      }

   A0 ^= RC[16];
   theta(A0, A1, A2, A3, EK);

   store_be(out, A0, A1, A2, A3);
   }

/*************************************************
* Noekeon Encryption                             *
*************************************************/
void Noekeon::dec(const byte in[], byte out[]) const
   {
   u32bit A0 = load_be<u32bit>(in, 0);
   u32bit A1 = load_be<u32bit>(in, 1);
   u32bit A2 = load_be<u32bit>(in, 2);
   u32bit A3 = load_be<u32bit>(in, 3);

   for(u32bit j = 16; j != 0; --j)
      {
      theta(A0, A1, A2, A3, DK);
      A0 ^= RC[j];

      A1 = rotate_left(A1, 1);
      A2 = rotate_left(A2, 5);
      A3 = rotate_left(A3, 2);

      gamma(A0, A1, A2, A3);

      A1 = rotate_right(A1, 1);
      A2 = rotate_right(A2, 5);
      A3 = rotate_right(A3, 2);
      }

   theta(A0, A1, A2, A3, DK);
   A0 ^= RC[0];

   store_be(out, A0, A1, A2, A3);
   }

/*************************************************
* Noekeon Key Schedule                           *
*************************************************/
void Noekeon::key(const byte key[], u32bit)
   {
   const u32bit NullVector[] = { 0, 0, 0, 0 };

   u32bit A0 = load_be<u32bit>(key, 0);
   u32bit A1 = load_be<u32bit>(key, 1);
   u32bit A2 = load_be<u32bit>(key, 2);
   u32bit A3 = load_be<u32bit>(key, 3);

   for(u32bit j = 0; j != 16; ++j)
      {
      A0 ^= RC[j];
      theta(A0, A1, A2, A3, NullVector);

      A1 = rotate_left(A1, 1);
      A2 = rotate_left(A2, 5);
      A3 = rotate_left(A3, 2);

      gamma(A0, A1, A2, A3);

      A1 = rotate_right(A1, 1);
      A2 = rotate_right(A2, 5);
      A3 = rotate_right(A3, 2);
      }

   A0 ^= RC[16];

   DK[0] = A0;
   DK[1] = A1;
   DK[2] = A2;
   DK[3] = A3;

   theta(A0, A1, A2, A3, NullVector);

   EK[0] = A0;
   EK[1] = A1;
   EK[2] = A2;
   EK[3] = A3;
   }

/*************************************************
* Clear memory of sensitive data                 *
*************************************************/
void Noekeon::clear() throw()
   {
   EK.clear();
   DK.clear();
   }

}
<commit_msg>Add a specialized version of theta() for NullVector, since it cleans up the key schedule, and perhaps offers slightly better code generation.<commit_after>/*************************************************
* Noekeon Source File                            *
* (C) 1999-2008 Jack Lloyd                       *
*************************************************/

#include <botan/noekeon.h>
#include <botan/loadstor.h>
#include <botan/bit_ops.h>

namespace Botan {

namespace {

/*************************************************
* Noekeon's Theta Operation                      *
*************************************************/
inline void theta(u32bit& A0, u32bit& A1,
                  u32bit& A2, u32bit& A3,
                  const u32bit EK[4])
   {
   u32bit T = A0 ^ A2;
   T ^= rotate_left(T, 8) ^ rotate_right(T, 8);
   A1 ^= T;
   A3 ^= T;

   A0 ^= EK[0];
   A1 ^= EK[1];
   A2 ^= EK[2];
   A3 ^= EK[3];

   T = A1 ^ A3;
   T ^= rotate_left(T, 8) ^ rotate_right(T, 8);
   A0 ^= T;
   A2 ^= T;
   }

/*************************************************
* Theta With Null Key                            *
*************************************************/
inline void theta(u32bit& A0, u32bit& A1,
                  u32bit& A2, u32bit& A3)
   {
   u32bit T = A0 ^ A2;
   T ^= rotate_left(T, 8) ^ rotate_right(T, 8);
   A1 ^= T;
   A3 ^= T;

   T = A1 ^ A3;
   T ^= rotate_left(T, 8) ^ rotate_right(T, 8);
   A0 ^= T;
   A2 ^= T;
   }

/*************************************************
* Noekeon's Gamma S-Box Layer                    *
*************************************************/
inline void gamma(u32bit& A0, u32bit& A1, u32bit& A2, u32bit& A3)
   {
   A1 ^= ~A3 & ~A2;
   A0 ^= A2 & A1;

   u32bit T = A3;
   A3 = A0;
   A0 = T;

   A2 ^= A0 ^ A1 ^ A3;

   A1 ^= ~A3 & ~A2;
   A0 ^= A2 & A1;
   }

}

/*************************************************
* Noekeon Round Constants                        *
*************************************************/
const byte Noekeon::RC[] = {
   0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A,
   0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A,
   0xD4 };

/*************************************************
* Noekeon Encryption                             *
*************************************************/
void Noekeon::enc(const byte in[], byte out[]) const
   {
   u32bit A0 = load_be<u32bit>(in, 0);
   u32bit A1 = load_be<u32bit>(in, 1);
   u32bit A2 = load_be<u32bit>(in, 2);
   u32bit A3 = load_be<u32bit>(in, 3);

   for(u32bit j = 0; j != 16; ++j)
      {
      A0 ^= RC[j];
      theta(A0, A1, A2, A3, EK);

      A1 = rotate_left(A1, 1);
      A2 = rotate_left(A2, 5);
      A3 = rotate_left(A3, 2);

      gamma(A0, A1, A2, A3);

      A1 = rotate_right(A1, 1);
      A2 = rotate_right(A2, 5);
      A3 = rotate_right(A3, 2);
      }

   A0 ^= RC[16];
   theta(A0, A1, A2, A3, EK);

   store_be(out, A0, A1, A2, A3);
   }

/*************************************************
* Noekeon Encryption                             *
*************************************************/
void Noekeon::dec(const byte in[], byte out[]) const
   {
   u32bit A0 = load_be<u32bit>(in, 0);
   u32bit A1 = load_be<u32bit>(in, 1);
   u32bit A2 = load_be<u32bit>(in, 2);
   u32bit A3 = load_be<u32bit>(in, 3);

   for(u32bit j = 16; j != 0; --j)
      {
      theta(A0, A1, A2, A3, DK);
      A0 ^= RC[j];

      A1 = rotate_left(A1, 1);
      A2 = rotate_left(A2, 5);
      A3 = rotate_left(A3, 2);

      gamma(A0, A1, A2, A3);

      A1 = rotate_right(A1, 1);
      A2 = rotate_right(A2, 5);
      A3 = rotate_right(A3, 2);
      }

   theta(A0, A1, A2, A3, DK);
   A0 ^= RC[0];

   store_be(out, A0, A1, A2, A3);
   }

/*************************************************
* Noekeon Key Schedule                           *
*************************************************/
void Noekeon::key(const byte key[], u32bit)
   {
   u32bit A0 = load_be<u32bit>(key, 0);
   u32bit A1 = load_be<u32bit>(key, 1);
   u32bit A2 = load_be<u32bit>(key, 2);
   u32bit A3 = load_be<u32bit>(key, 3);

   for(u32bit j = 0; j != 16; ++j)
      {
      A0 ^= RC[j];
      theta(A0, A1, A2, A3);

      A1 = rotate_left(A1, 1);
      A2 = rotate_left(A2, 5);
      A3 = rotate_left(A3, 2);

      gamma(A0, A1, A2, A3);

      A1 = rotate_right(A1, 1);
      A2 = rotate_right(A2, 5);
      A3 = rotate_right(A3, 2);
      }

   A0 ^= RC[16];

   DK[0] = A0;
   DK[1] = A1;
   DK[2] = A2;
   DK[3] = A3;

   theta(A0, A1, A2, A3);

   EK[0] = A0;
   EK[1] = A1;
   EK[2] = A2;
   EK[3] = A3;
   }

/*************************************************
* Clear memory of sensitive data                 *
*************************************************/
void Noekeon::clear() throw()
   {
   EK.clear();
   DK.clear();
   }

}
<|endoftext|>


<commit_before>/*
* mod_compare - compares apache requests
*
* Copyright (C) 2013 Orange
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <httpd.h>
#include <http_config.h>
#include <http_request.h>
#include <http_protocol.h>
#include <http_connection.h>
#include <apr_pools.h>
#include <apr_hooks.h>
#include "apr_strings.h"
#include <unistd.h>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <exception>
#include <set>
#include <sstream>
#include <sys/syscall.h>
#include <algorithm>
#include <boost/tokenizer.hpp>
#include <fstream>

#include "mod_compare.hh"

namespace alg = boost::algorithm;

namespace CompareModule {

const char *gName = "Compare";
const char *c_COMPONENT_VERSION = "Compare/1.0";
const char* c_UNIQUE_ID = "UNIQUE_ID";

std::ofstream gFile;
const char * gFilePath;
boost::interprocess::named_mutex gMutex(boost::interprocess::open_or_create, "mod_compare_log_mutex");

CompareConf::CompareConf(): mCompareDisabled(false) {
}

apr_status_t CompareConf::cleaner(void *self) {
    if(self){
        CompareConf *c = reinterpret_cast<CompareConf *>(self);

        c->~CompareConf();
    }
    return 0;
}

/**
 * @brief allocate a pointer to a string which will hold the path for the dir config if mod_compare is active on it
 * @param pPool the apache pool on which to allocate data
 * @param pDirName the directory name for which to create data
 * @return a void pointer to newly allocated object
 */
void *
createDirConfig(apr_pool_t *pPool, char *pDirName)
{
    void *addr= apr_pcalloc(pPool, sizeof(class CompareConf));
    new (addr) CompareConf();
    apr_pool_cleanup_register(pPool, addr, CompareConf::cleaner,  apr_pool_cleanup_null);
    return addr;
}

/**
 * @brief Initialize logging post-config
 * @param pPool the apache pool
 * @param pServer the corresponding server record
 * @return Always OK
 */
int
postConfig(apr_pool_t * pPool, apr_pool_t * pLog, apr_pool_t * pTemp, server_rec * pServer) {
    Log::init();

    ap_add_version_component(pPool, c_COMPONENT_VERSION) ;
    return OK;
}

apr_status_t
closeLogFile(void *) {

    gFile.close();
    return APR_SUCCESS;
}

apr_status_t openLogFile(const char * filepath,std::ios_base::openmode mode) {
    gFile.open(filepath,mode);
    if (!gFile.is_open()){
    	Log::warn(43,"Couldn't open correctly the file, we'll now attempt to close and reopen it");
    	gFile.close();
    	gFile.open(filepath,mode);
    	if (!gFile.is_open()){
    		Log::error(43,std::string("Couldn't open the file :").append(filepath).c_str());
    		throw std::ofstream::failure(std::string("Couldn't open the file :").append(filepath));
    	}
    }
    return APR_SUCCESS;
}

void
childInit(apr_pool_t *pPool, server_rec *pServer)
{
    gFile.open(gFilePath, std::ofstream::out | std::ofstream::app );
    apr_pool_cleanup_register(pPool, NULL, apr_pool_cleanup_null, closeLogFile);
}

/**
 * @brief Set the list of errors which stop the comparison
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pListType the type of list (STOP or IGNORE)
 * @param pValue the reg_ex to insert in the list
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char*
setBodyList(cmd_parms* pParams, void* pCfg, const char* pListType, const char* pValue) {
    if (!pValue || strlen(pValue) == 0) {
        return "Missing reg_ex value for the body";
    }

    if (!pListType || strlen(pListType) == 0) {
        return "Missing the type of list";
    }

    CompareConf *lConf = reinterpret_cast<CompareConf *>(pCfg);
    std::string lListType(pListType);
    std::string lValue(pValue);

    if (strcmp("STOP", pListType) == 0)
    {
        lConf->mCompBody.addStopRegex(lValue);
    }
    else if(strcmp("IGNORE", pListType) == 0)
    {
        lConf->mCompBody.addIgnoreRegex(lValue);
    }
    else
    {
        return "Invalid value for the list type";
    }

    return NULL;
}

/**
 * @brief Set the list of errors to ignore in the comparison
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pListType the type of list (STOP or IGNORE)
 * @param pHeader the header for which to apply the regex
 * @param pValue the reg_ex to insert in the list
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char* setHeaderList(cmd_parms* pParams, void* pCfg, const char* pListType, const char* pAffectedKey,const char* pValue) {
    if (!pValue || strlen(pValue) == 0) {
        return "Missing reg_ex value for the header";
    }

    if (!pAffectedKey || strlen(pAffectedKey) == 0) {
            return "Missing header value";
        }

    if (!pListType || strlen(pListType) == 0) {
        return "Missing the type list";
    }

    CompareConf *lConf = reinterpret_cast<CompareConf *>(pCfg);
    std::string lHeader(pAffectedKey);
    std::string lValue(pValue);

    if (strcmp("STOP", pListType) == 0)
    {
        lConf->mCompHeader.addStopRegex(lHeader, lValue);
    }
    else if(strcmp("IGNORE", pListType) == 0)
    {
        lConf->mCompHeader.addIgnoreRegex(lHeader, lValue);
    }
    else
    {
        return "Invalid value for the list type";
    }

    return NULL;
}

/**
 * @brief Set the list of errors to ignore in the comparison
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pListType the type of list (Header or Body)
 * @param pValue the value to insert in the list
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char* setFilePath(cmd_parms* pParams, void* pCfg, const char* pPath) {
    if (!pPath || strlen(pPath) == 0) {
        return "Missing path value";
    }
    Log::init();
    gFilePath = pPath;
    std::string lPath(gFilePath);
    //Log::error(12, "File path %s", lPath.c_str());

    return NULL;
}

/**
 * @brief Enable/Disable the utilization of the libws-diff tools
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pValue the value
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char*
setDisableLibwsdiff(cmd_parms* pParams, void* pCfg, const char* pValue) {
	CompareConf *lConf = reinterpret_cast<CompareConf *>(pCfg);
	lConf->mCompareDisabled= strcmp(pValue, "1")==0 || strcmp(pValue, "true")==0;
    if(lConf->mCompareDisabled){
    	Log::warn(42,"The use of the diffing library libws-diff has been disabled!");
    }
    return NULL;
}

/** @brief Declaration of configuration commands */
    command_rec gCmds[] = {
        // AP_INIT_(directive,
        //          function,
        //          void * extra data,
        //          overrides to allow in order to enable,
        //          help message),
        AP_INIT_TAKE2("BodyList",
                      reinterpret_cast<const char *(*)()>(&setBodyList),
                      0,
                      ACCESS_CONF,
                      "List of reg_ex to apply to the body for the comparison."),
        AP_INIT_TAKE3("HeaderList",
                      reinterpret_cast<const char *(*)()>(&setHeaderList),
                      0,
                      ACCESS_CONF,
                      "List of reg_ex to apply to the Header for the comparison."),
        AP_INIT_TAKE1("FilePath",
                      reinterpret_cast<const char *(*)()>(&setFilePath),
                      0,
                      OR_ALL,
                      "Path of file where the differences will be logged."),
        AP_INIT_TAKE1("DisableLibwsdiff",
                      reinterpret_cast<const char *(*)()>(&setDisableLibwsdiff),
                      0,
                      OR_ALL,
                      "Disable the use of libws-diff tools. Print raw serialization of the data in the log file."),
        {0}
    };

/**
 * @brief register hooks in apache
 * @param pPool the apache pool
 */
void
registerHooks(apr_pool_t *pPool) {
#ifndef UNIT_TESTING
    ap_hook_post_config(postConfig, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_child_init(&childInit, NULL, NULL, APR_HOOK_MIDDLE);
    ap_register_input_filter(gName, inputFilterHandler, NULL, AP_FTYPE_RESOURCE);
    ap_register_output_filter(gName, outputFilterHandler, NULL, AP_FTYPE_RESOURCE);
#endif
}

} // End namespace

/// Apache module declaration
module AP_MODULE_DECLARE_DATA compare_module = {
    STANDARD20_MODULE_STUFF,
    CompareModule::createDirConfig,
    0, // merge_dir_config
    0, // create_server_config
    0, // merge_server_config
    CompareModule::gCmds,
    CompareModule::registerHooks
};
<commit_msg>fixed type of directive for DisableLibwsdiff<commit_after>/*
* mod_compare - compares apache requests
*
* Copyright (C) 2013 Orange
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <httpd.h>
#include <http_config.h>
#include <http_request.h>
#include <http_protocol.h>
#include <http_connection.h>
#include <apr_pools.h>
#include <apr_hooks.h>
#include "apr_strings.h"
#include <unistd.h>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <exception>
#include <set>
#include <sstream>
#include <sys/syscall.h>
#include <algorithm>
#include <boost/tokenizer.hpp>
#include <fstream>

#include "mod_compare.hh"

namespace alg = boost::algorithm;

namespace CompareModule {

const char *gName = "Compare";
const char *c_COMPONENT_VERSION = "Compare/1.0";
const char* c_UNIQUE_ID = "UNIQUE_ID";

std::ofstream gFile;
const char * gFilePath;
boost::interprocess::named_mutex gMutex(boost::interprocess::open_or_create, "mod_compare_log_mutex");

CompareConf::CompareConf(): mCompareDisabled(false) {
}

apr_status_t CompareConf::cleaner(void *self) {
    if(self){
        CompareConf *c = reinterpret_cast<CompareConf *>(self);

        c->~CompareConf();
    }
    return 0;
}

/**
 * @brief allocate a pointer to a string which will hold the path for the dir config if mod_compare is active on it
 * @param pPool the apache pool on which to allocate data
 * @param pDirName the directory name for which to create data
 * @return a void pointer to newly allocated object
 */
void *
createDirConfig(apr_pool_t *pPool, char *pDirName)
{
    void *addr= apr_pcalloc(pPool, sizeof(class CompareConf));
    new (addr) CompareConf();
    apr_pool_cleanup_register(pPool, addr, CompareConf::cleaner,  apr_pool_cleanup_null);
    return addr;
}

/**
 * @brief Initialize logging post-config
 * @param pPool the apache pool
 * @param pServer the corresponding server record
 * @return Always OK
 */
int
postConfig(apr_pool_t * pPool, apr_pool_t * pLog, apr_pool_t * pTemp, server_rec * pServer) {
    Log::init();

    ap_add_version_component(pPool, c_COMPONENT_VERSION) ;
    return OK;
}

apr_status_t
closeLogFile(void *) {

    gFile.close();
    return APR_SUCCESS;
}

apr_status_t openLogFile(const char * filepath,std::ios_base::openmode mode) {
    gFile.open(filepath,mode);
    if (!gFile.is_open()){
    	Log::warn(43,"Couldn't open correctly the file, we'll now attempt to close and reopen it");
    	gFile.close();
    	gFile.open(filepath,mode);
    	if (!gFile.is_open()){
    		Log::error(43,std::string("Couldn't open the file :").append(filepath).c_str());
    		throw std::ofstream::failure(std::string("Couldn't open the file :").append(filepath));
    	}
    }
    return APR_SUCCESS;
}

void
childInit(apr_pool_t *pPool, server_rec *pServer)
{
    gFile.open(gFilePath, std::ofstream::out | std::ofstream::app );
    apr_pool_cleanup_register(pPool, NULL, apr_pool_cleanup_null, closeLogFile);
}

/**
 * @brief Set the list of errors which stop the comparison
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pListType the type of list (STOP or IGNORE)
 * @param pValue the reg_ex to insert in the list
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char*
setBodyList(cmd_parms* pParams, void* pCfg, const char* pListType, const char* pValue) {
    if (!pValue || strlen(pValue) == 0) {
        return "Missing reg_ex value for the body";
    }

    if (!pListType || strlen(pListType) == 0) {
        return "Missing the type of list";
    }

    CompareConf *lConf = reinterpret_cast<CompareConf *>(pCfg);
    std::string lListType(pListType);
    std::string lValue(pValue);

    if (strcmp("STOP", pListType) == 0)
    {
        lConf->mCompBody.addStopRegex(lValue);
    }
    else if(strcmp("IGNORE", pListType) == 0)
    {
        lConf->mCompBody.addIgnoreRegex(lValue);
    }
    else
    {
        return "Invalid value for the list type";
    }

    return NULL;
}

/**
 * @brief Set the list of errors to ignore in the comparison
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pListType the type of list (STOP or IGNORE)
 * @param pHeader the header for which to apply the regex
 * @param pValue the reg_ex to insert in the list
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char* setHeaderList(cmd_parms* pParams, void* pCfg, const char* pListType, const char* pAffectedKey,const char* pValue) {
    if (!pValue || strlen(pValue) == 0) {
        return "Missing reg_ex value for the header";
    }

    if (!pAffectedKey || strlen(pAffectedKey) == 0) {
            return "Missing header value";
        }

    if (!pListType || strlen(pListType) == 0) {
        return "Missing the type list";
    }

    CompareConf *lConf = reinterpret_cast<CompareConf *>(pCfg);
    std::string lHeader(pAffectedKey);
    std::string lValue(pValue);

    if (strcmp("STOP", pListType) == 0)
    {
        lConf->mCompHeader.addStopRegex(lHeader, lValue);
    }
    else if(strcmp("IGNORE", pListType) == 0)
    {
        lConf->mCompHeader.addIgnoreRegex(lHeader, lValue);
    }
    else
    {
        return "Invalid value for the list type";
    }

    return NULL;
}

/**
 * @brief Set the list of errors to ignore in the comparison
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pListType the type of list (Header or Body)
 * @param pValue the value to insert in the list
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char* setFilePath(cmd_parms* pParams, void* pCfg, const char* pPath) {
    if (!pPath || strlen(pPath) == 0) {
        return "Missing path value";
    }
    Log::init();
    gFilePath = pPath;
    std::string lPath(gFilePath);
    //Log::error(12, "File path %s", lPath.c_str());

    return NULL;
}

/**
 * @brief Enable/Disable the utilization of the libws-diff tools
 * @param pParams miscellaneous data
 * @param pCfg user data for the directory/location
 * @param pValue the value
 * @return NULL if parameters are valid, otherwise a string describing the error
 */
const char*
setDisableLibwsdiff(cmd_parms* pParams, void* pCfg, const char* pValue) {
	CompareConf *lConf = reinterpret_cast<CompareConf *>(pCfg);
	lConf->mCompareDisabled= strcmp(pValue, "1")==0 || strcmp(pValue, "true")==0;
    if(lConf->mCompareDisabled){
    	Log::warn(42,"The use of the diffing library libws-diff has been disabled!");
    }
    return NULL;
}

/** @brief Declaration of configuration commands */
    command_rec gCmds[] = {
        // AP_INIT_(directive,
        //          function,
        //          void * extra data,
        //          overrides to allow in order to enable,
        //          help message),
        AP_INIT_TAKE2("BodyList",
                      reinterpret_cast<const char *(*)()>(&setBodyList),
                      0,
                      ACCESS_CONF,
                      "List of reg_ex to apply to the body for the comparison."),
        AP_INIT_TAKE3("HeaderList",
                      reinterpret_cast<const char *(*)()>(&setHeaderList),
                      0,
                      ACCESS_CONF,
                      "List of reg_ex to apply to the Header for the comparison."),
        AP_INIT_TAKE1("FilePath",
                      reinterpret_cast<const char *(*)()>(&setFilePath),
                      0,
                      OR_ALL,
                      "Path of file where the differences will be logged."),
        AP_INIT_TAKE1("DisableLibwsdiff",
                      reinterpret_cast<const char *(*)()>(&setDisableLibwsdiff),
                      0,
                      ACCESS_CONF,
                      "Disable the use of libws-diff tools. Print raw serialization of the data in the log file."),
        {0}
    };

/**
 * @brief register hooks in apache
 * @param pPool the apache pool
 */
void
registerHooks(apr_pool_t *pPool) {
#ifndef UNIT_TESTING
    ap_hook_post_config(postConfig, NULL, NULL, APR_HOOK_MIDDLE);
    ap_hook_child_init(&childInit, NULL, NULL, APR_HOOK_MIDDLE);
    ap_register_input_filter(gName, inputFilterHandler, NULL, AP_FTYPE_RESOURCE);
    ap_register_output_filter(gName, outputFilterHandler, NULL, AP_FTYPE_RESOURCE);
#endif
}

} // End namespace

/// Apache module declaration
module AP_MODULE_DECLARE_DATA compare_module = {
    STANDARD20_MODULE_STUFF,
    CompareModule::createDirConfig,
    0, // merge_dir_config
    0, // create_server_config
    0, // merge_server_config
    CompareModule::gCmds,
    CompareModule::registerHooks
};
<|endoftext|>


<commit_before>/*
 * File:   Assets.cpp
 * Author: morgan
 *
 * Created on February 25, 2014, 6:38 PM
 */

#include <mos/assets.hpp>

#include <rapidxml.hpp>
#include <rapidxml_utils.hpp>
#include <lodepng.h>
#include <objload.h>
#include <exception>
#include <memory>
#include <cstring>
#include <fstream>
#include <iostream>
#include <iterator>
#include <stb_vorbis.h>
#include <glm/gtx/io.hpp>
#include <glm/gtx/euler_angles.hpp>
#include <glm/gtc/type_ptr.hpp>

namespace mos {
using namespace std;
using namespace glm;

Assets::Assets(const std::string directory) : directory_(directory) {}

Assets::~Assets() {}

Model Assets::model(rapidjson::Value &value) {
  auto name = !value.HasMember("name") || value["name"].IsNull()
                  ? ""
                  : value["name"].GetString();

  std::string mesh = !value.HasMember("mesh") || value["mesh"].IsNull()
                         ? ""
                         : value["mesh"].GetString();

  std::string texture_name =
      !value.HasMember("texture") || value["texture"].IsNull()
          ? ""
          : value["texture"].GetString();
  std::string texture2_name =
      !value.HasMember("texture2") || value["texture2"].IsNull()
          ? ""
          : value["texture2"].GetString();
  std::string lightmap_name =
      !value.HasMember("lightmap") || value["lightmap"].IsNull()
          ? ""
          : value["lightmap"].GetString();
  std::string material_name =
      !value.HasMember("material") || value["material"].IsNull()
          ? ""
          : value["material"].GetString();

  glm::mat4 transform;

  if (value.HasMember("transform")) {
    std::vector<float> nums;
    for (auto it = value["transform"].Begin(); it != value["transform"].End();
         it++) {
      nums.push_back(it->GetDouble());
    }
    transform = glm::make_mat4x4(nums.data());
  }

  auto m = mos::Model(
      name, mesh_cached(mesh), texture_cached(texture_name),
      texture_cached(texture2_name), transform, mos::Model::Draw::TRIANGLES,
      material_cached(material_name), texture_cached(lightmap_name), nullptr);

  for (auto it = value["models"].Begin(); it != value["models"].End(); it++) {
    m.models.push_back(model(*it));
  }

  return m;
}

rapidjson::Document Assets::document(const std::string &file_name) {
  // std::cout << "Loading: " << file_name << std::endl;
  std::ifstream is(directory_ + file_name);
  if (!is.good()) {
    throw std::runtime_error(directory_ + file_name + " does not exist.");
  }
  std::ifstream file(directory_ + file_name);
  std::string source((std::istreambuf_iterator<char>(file)),
                     std::istreambuf_iterator<char>());
  rapidjson::Document doc;
  doc.Parse(source.c_str());
  return doc;
}

vec3 Assets::position(const string &file_name) {
  return (glm::vec3)(transform(file_name) * glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
}

mat4 Assets::transform(const string &file_name) {
  auto doc = document(file_name);
  glm::mat4 transform;
  if (doc.HasMember("transform")) {
    std::vector<float> nums;
    for (auto it = doc["transform"].Begin(); it != doc["transform"].End();
         it++) {
      nums.push_back(it->GetDouble());
    }
    transform = glm::make_mat4x4(nums.data());
  }
  return transform;
}

Model Assets::model(const std::string &file_name) {
  auto doc = document(file_name);
  return model(doc);
}

Animation Assets::animation(const string &file_name) {
  auto doc = document(file_name);
  auto frame_rate = doc["frame_rate"].GetInt();
  std::map<unsigned int, std::shared_ptr<Mesh const>> keyframes;

  for (auto it = doc["keyframes"].Begin(); it != doc["keyframes"].End(); it++) {
    auto key = (*it)["key"].GetInt();
    auto mesh_file_name = (*it)["mesh"].GetString();
    keyframes.insert({key, mesh_cached(mesh_file_name)});
  }
  Animation animation(keyframes, frame_rate);
  return animation;
}

std::shared_ptr<Mesh> Assets::mesh(const std::string file_name) const {
  // TODO: allow Null mesh? As of now it becomes empty.
  vector<mos::Vertex> vertices;
  vector<int> indices;

  if (file_name.substr(file_name.find_last_of(".") + 1) == "mesh") {

    // std::cout << "Loading: " << file_name << std::endl;
    std::ifstream is(directory_ + file_name, ios::binary);
    if (!is.good()) {
      throw std::runtime_error(directory_ + file_name + " does not exist.");
    }
    int num_vertices;
    int num_indices;
    is.read((char *)&num_vertices, sizeof(int));
    is.read((char *)&num_indices, sizeof(int));

    vertices = vector<mos::Vertex>(num_vertices);
    indices = vector<int>(num_indices);

    if (vertices.size() > 0) {
      is.read((char *)&vertices[0], vertices.size() * sizeof(Vertex));
    }

    if (indices.size() > 0) {
      is.read((char *)&indices[0], indices.size() * sizeof(int));
    }

  } else if (file_name.substr(file_name.find_last_of(".") + 1) == "obj") {

    // std::cout << "Loading: " << directory_ << file_name;
    obj::Model obj_model = obj::loadModelFromFile(directory_ + file_name);

    int j = 0;
    for (int i = 0; i < obj_model.vertex.size(); i += 3) {
      glm::vec3 position(obj_model.vertex[i], obj_model.vertex[i + 1],
                         obj_model.vertex[i + 2]);
      glm::vec3 normal(obj_model.normal[i], obj_model.normal[i + 1],
                       obj_model.normal[i + 2]);
      glm::vec2 uv(0.0f, 0.0f);
      if (obj_model.texCoord.size() > 0) {
        uv.x = obj_model.texCoord[j];
        uv.y = obj_model.texCoord[j + 1];
      }

      j += 2;
      vertices.push_back(Vertex(position, normal, uv));
    }
    indices.assign(obj_model.faces.find("default")->second.begin(),
                   obj_model.faces.find("default")->second.end());
  }
  return std::make_shared<Mesh>(vertices.begin(), vertices.end(),
                                indices.begin(), indices.end());
}

std::shared_ptr<Mesh> Assets::mesh_cached(const std::string file_name) {
  if (meshes_.find(file_name) == meshes_.end()) {
    meshes_.insert(MeshPair(file_name, mesh(file_name)));
  }
  return meshes_.at(file_name);
}

std::shared_ptr<Texture2D> Assets::texture(const std::string file_name,
                                           const bool mipmaps) const {
  using namespace mos;

  vector<unsigned char> texels_decoded;
  unsigned width, height;

  if (file_name.empty()) {
    return std::shared_ptr<Texture2D>(nullptr);
  }

  // std::cout << "Loading: " << directory_ + file_name << std::endl;
  auto error =
      lodepng::decode(texels_decoded, width, height, directory_ + file_name);
  if (error) {
    std::cout << "Decoder error: " << error << ": " << lodepng_error_text(error)
              << std::endl;
  }
  return std::make_shared<Texture2D>(
      texels_decoded.begin(), texels_decoded.end(), width, height, mipmaps);
}

std::shared_ptr<Texture2D> Assets::texture_cached(const std::string file_name,
                                                  const bool mipmaps) {
  if (!file_name.empty()) {
    if (textures_.find(file_name) == textures_.end()) {
      textures_.insert(TexturePair(file_name, texture(file_name, mipmaps)));
    }
    return textures_.at(file_name);
  } else {
    return std::shared_ptr<Texture2D>(nullptr);
  }
}

std::shared_ptr<Sound> Assets::sound(const std::string file_name) const {
  int channels, length, sample_rate;
  short *decoded;

  std::ifstream file(directory_ + file_name, std::ios::binary);
  if (!file.good()) {
    throw std::runtime_error(directory_ + file_name + " does not exist.");
  }
  std::vector<unsigned char> data;

  unsigned char c;
  while (file.read(reinterpret_cast<char *>(&c), sizeof(c))) {
    data.push_back(c);
  }
  length = stb_vorbis_decode_memory(data.data(), data.size(), &channels,
                                    &sample_rate, &decoded);

  return std::make_shared<Sound>(decoded, decoded + length);
}

std::shared_ptr<Stream> Assets::stream(const string file_name) const {
  return std::make_shared<mos::Stream>(directory_ + file_name);
}

Font Assets::font(const string &ngl_file_name) {
  std::map<char, Character> characters;
  rapidxml::xml_document<> doc;
  auto xml_string = text(ngl_file_name);
  doc.parse<0>(&xml_string[0]);

  auto *chars_node = doc.first_node("font")->first_node("chars");
  auto *description_node = doc.first_node("font")->first_node("description");
  std::string name = description_node->first_attribute("family")->value();
  float size = atof(description_node->first_attribute("family")->value());

  auto *metrics_node = doc.first_node("font")->first_node("metrics");
  float height = atof(metrics_node->first_attribute("height")->value());
  float ascender = atof(metrics_node->first_attribute("ascender")->value());
  float descender = atof(metrics_node->first_attribute("descender")->value());

  auto *texture_node = doc.first_node("font")->first_node("texture");
  std::string texture_file_name =
      texture_node->first_attribute("file")->value();

  for (auto *char_node = chars_node->first_node("char"); char_node;
       char_node = char_node->next_sibling()) {

    Character character;

    character.offset_x = atof(char_node->first_attribute("offset_x")->value());
    character.offset_y = atof(char_node->first_attribute("offset_y")->value());
    character.advance = atof(char_node->first_attribute("advance")->value());
    character.rect_w = atof(char_node->first_attribute("rect_w")->value());
    character.id = *char_node->first_attribute("id")->value();
    character.rect_x = atof(char_node->first_attribute("rect_x")->value());
    character.rect_y = atof(char_node->first_attribute("rect_y")->value());
    character.rect_h = atof(char_node->first_attribute("rect_h")->value());
    characters.insert(std::pair<char, Character>(character.id, character));
  }

  auto char_map = characters;
  auto texture = texture_cached(texture_file_name);
  return Font(char_map, texture, height, ascender, descender);
}

std::shared_ptr<Sound> Assets::sound_cached(const std::string file_name) {
  if (sounds_.find(file_name) == sounds_.end()) {

    sounds_.insert(SoundPair(file_name, sound(file_name)));
    return sounds_.at(file_name);
  } else {
    return sounds_.at(file_name);
  }
}

std::shared_ptr<Material> Assets::material(const std::string file_name) const {

  if (file_name.substr(file_name.find_last_of(".") + 1) == "material") {
    // std::cout << "Loading: " << directory_ + file_name << std::endl;
    std::ifstream is(directory_ + file_name, ios::binary);
    glm::vec3 ambient;
    glm::vec3 diffuse;
    glm::vec3 specular;
    float opacity;
    float specular_exponent;

    is.read((char *)&ambient, sizeof(glm::vec3));
    is.read((char *)&diffuse, sizeof(glm::vec3));
    is.read((char *)&specular, sizeof(glm::vec3));
    is.read((char *)&opacity, sizeof(float));
    is.read((char *)&specular_exponent, sizeof(float));

    return std::make_shared<Material>(ambient, diffuse, specular, opacity,
                                      specular_exponent);
  } else {
    // throw std::runtime_error(file_name.substr(file_name.find_last_of(".")) +
    // " file format is not supported.");
    return std::shared_ptr<Material>(nullptr);
  }
}

std::shared_ptr<Material> Assets::material_cached(const std::string file_name) {
  if (materials_.find(file_name) == materials_.end()) {

    materials_.insert(MaterialPair(file_name, material(file_name)));
    return materials_.at(file_name);
  } else {
    return materials_.at(file_name);
  }
}

std::string Assets::text(const std::string file_name) const {

  std::ifstream file(directory_ + file_name);
  std::string source((std::istreambuf_iterator<char>(file)),
                     std::istreambuf_iterator<char>());
  return source;
}

void Assets::clear_unused() {
  for (auto it = textures_.begin(); it != textures_.end();) {
    if (it->second.use_count() <= 1) {
      textures_.erase(it++);
    } else {
      ++it;
    }
  }
  for (auto it = meshes_.begin(); it != meshes_.end();) {
    if (it->second.use_count() <= 1) {
      meshes_.erase(it++);
    } else {
      ++it;
    }
  }
  for (auto it = sounds_.begin(); it != sounds_.end();) {
    if (it->second.use_count() <= 1) {
      sounds_.erase(it++);
    } else {
      ++it;
    }
  }
  for (auto it = materials_.begin(); it != materials_.end();) {
    if (it->second.use_count() <= 1) {
      materials_.erase(it++);
    } else {
      ++it;
    }
  }
}
}
<commit_msg>Receives light.<commit_after>/*
 * File:   Assets.cpp
 * Author: morgan
 *
 * Created on February 25, 2014, 6:38 PM
 */

#include <mos/assets.hpp>

#include <rapidxml.hpp>
#include <rapidxml_utils.hpp>
#include <lodepng.h>
#include <objload.h>
#include <exception>
#include <memory>
#include <cstring>
#include <fstream>
#include <iostream>
#include <iterator>
#include <stb_vorbis.h>
#include <glm/gtx/io.hpp>
#include <glm/gtx/euler_angles.hpp>
#include <glm/gtc/type_ptr.hpp>

namespace mos {
using namespace std;
using namespace glm;

Assets::Assets(const std::string directory) : directory_(directory) {}

Assets::~Assets() {}

Model Assets::model(rapidjson::Value &value) {
  auto name = !value.HasMember("name") || value["name"].IsNull()
                  ? ""
                  : value["name"].GetString();

  std::string mesh = !value.HasMember("mesh") || value["mesh"].IsNull()
                         ? ""
                         : value["mesh"].GetString();

  std::string texture_name =
      !value.HasMember("texture") || value["texture"].IsNull()
          ? ""
          : value["texture"].GetString();
  std::string texture2_name =
      !value.HasMember("texture2") || value["texture2"].IsNull()
          ? ""
          : value["texture2"].GetString();
  std::string lightmap_name =
      !value.HasMember("lightmap") || value["lightmap"].IsNull()
          ? ""
          : value["lightmap"].GetString();
  std::string material_name =
      !value.HasMember("material") || value["material"].IsNull()
          ? ""
          : value["material"].GetString();
  bool recieves_light = !value.HasMember("receives_light") || value["receives_light"].IsNull()
      ? true
      : value["receives_light"].GetBool();

  glm::mat4 transform;

  if (value.HasMember("transform")) {
    std::vector<float> nums;
    for (auto it = value["transform"].Begin(); it != value["transform"].End();
         it++) {
      nums.push_back(it->GetDouble());
    }
    transform = glm::make_mat4x4(nums.data());
  }

  auto created_model = mos::Model(
      name, mesh_cached(mesh), texture_cached(texture_name),
      texture_cached(texture2_name), transform, mos::Model::Draw::TRIANGLES,
      material_cached(material_name), texture_cached(lightmap_name), nullptr,
      recieves_light);

  for (auto it = value["models"].Begin(); it != value["models"].End(); it++) {
    created_model.models.push_back(model(*it));
  }

  return created_model;
}

rapidjson::Document Assets::document(const std::string &file_name) {
  // std::cout << "Loading: " << file_name << std::endl;
  std::ifstream is(directory_ + file_name);
  if (!is.good()) {
    throw std::runtime_error(directory_ + file_name + " does not exist.");
  }
  std::ifstream file(directory_ + file_name);
  std::string source((std::istreambuf_iterator<char>(file)),
                     std::istreambuf_iterator<char>());
  rapidjson::Document doc;
  doc.Parse(source.c_str());
  return doc;
}

vec3 Assets::position(const string &file_name) {
  return (glm::vec3)(transform(file_name) * glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
}

mat4 Assets::transform(const string &file_name) {
  auto doc = document(file_name);
  glm::mat4 transform;
  if (doc.HasMember("transform")) {
    std::vector<float> nums;
    for (auto it = doc["transform"].Begin(); it != doc["transform"].End();
         it++) {
      nums.push_back(it->GetDouble());
    }
    transform = glm::make_mat4x4(nums.data());
  }
  return transform;
}

Model Assets::model(const std::string &file_name) {
  auto doc = document(file_name);
  return model(doc);
}

Animation Assets::animation(const string &file_name) {
  auto doc = document(file_name);
  auto frame_rate = doc["frame_rate"].GetInt();
  std::map<unsigned int, std::shared_ptr<Mesh const>> keyframes;

  for (auto it = doc["keyframes"].Begin(); it != doc["keyframes"].End(); it++) {
    auto key = (*it)["key"].GetInt();
    auto mesh_file_name = (*it)["mesh"].GetString();
    keyframes.insert({key, mesh_cached(mesh_file_name)});
  }
  Animation animation(keyframes, frame_rate);
  return animation;
}

std::shared_ptr<Mesh> Assets::mesh(const std::string file_name) const {
  // TODO: allow Null mesh? As of now it becomes empty.
  vector<mos::Vertex> vertices;
  vector<int> indices;

  if (file_name.substr(file_name.find_last_of(".") + 1) == "mesh") {

    // std::cout << "Loading: " << file_name << std::endl;
    std::ifstream is(directory_ + file_name, ios::binary);
    if (!is.good()) {
      throw std::runtime_error(directory_ + file_name + " does not exist.");
    }
    int num_vertices;
    int num_indices;
    is.read((char *)&num_vertices, sizeof(int));
    is.read((char *)&num_indices, sizeof(int));

    vertices = vector<mos::Vertex>(num_vertices);
    indices = vector<int>(num_indices);

    if (vertices.size() > 0) {
      is.read((char *)&vertices[0], vertices.size() * sizeof(Vertex));
    }

    if (indices.size() > 0) {
      is.read((char *)&indices[0], indices.size() * sizeof(int));
    }

  } else if (file_name.substr(file_name.find_last_of(".") + 1) == "obj") {

    // std::cout << "Loading: " << directory_ << file_name;
    obj::Model obj_model = obj::loadModelFromFile(directory_ + file_name);

    int j = 0;
    for (int i = 0; i < obj_model.vertex.size(); i += 3) {
      glm::vec3 position(obj_model.vertex[i], obj_model.vertex[i + 1],
                         obj_model.vertex[i + 2]);
      glm::vec3 normal(obj_model.normal[i], obj_model.normal[i + 1],
                       obj_model.normal[i + 2]);
      glm::vec2 uv(0.0f, 0.0f);
      if (obj_model.texCoord.size() > 0) {
        uv.x = obj_model.texCoord[j];
        uv.y = obj_model.texCoord[j + 1];
      }

      j += 2;
      vertices.push_back(Vertex(position, normal, uv));
    }
    indices.assign(obj_model.faces.find("default")->second.begin(),
                   obj_model.faces.find("default")->second.end());
  }
  return std::make_shared<Mesh>(vertices.begin(), vertices.end(),
                                indices.begin(), indices.end());
}

std::shared_ptr<Mesh> Assets::mesh_cached(const std::string file_name) {
  if (meshes_.find(file_name) == meshes_.end()) {
    meshes_.insert(MeshPair(file_name, mesh(file_name)));
  }
  return meshes_.at(file_name);
}

std::shared_ptr<Texture2D> Assets::texture(const std::string file_name,
                                           const bool mipmaps) const {
  using namespace mos;

  vector<unsigned char> texels_decoded;
  unsigned width, height;

  if (file_name.empty()) {
    return std::shared_ptr<Texture2D>(nullptr);
  }

  // std::cout << "Loading: " << directory_ + file_name << std::endl;
  auto error =
      lodepng::decode(texels_decoded, width, height, directory_ + file_name);
  if (error) {
    std::cout << "Decoder error: " << error << ": " << lodepng_error_text(error)
              << std::endl;
  }
  return std::make_shared<Texture2D>(
      texels_decoded.begin(), texels_decoded.end(), width, height, mipmaps);
}

std::shared_ptr<Texture2D> Assets::texture_cached(const std::string file_name,
                                                  const bool mipmaps) {
  if (!file_name.empty()) {
    if (textures_.find(file_name) == textures_.end()) {
      textures_.insert(TexturePair(file_name, texture(file_name, mipmaps)));
    }
    return textures_.at(file_name);
  } else {
    return std::shared_ptr<Texture2D>(nullptr);
  }
}

std::shared_ptr<Sound> Assets::sound(const std::string file_name) const {
  int channels, length, sample_rate;
  short *decoded;

  std::ifstream file(directory_ + file_name, std::ios::binary);
  if (!file.good()) {
    throw std::runtime_error(directory_ + file_name + " does not exist.");
  }
  std::vector<unsigned char> data;

  unsigned char c;
  while (file.read(reinterpret_cast<char *>(&c), sizeof(c))) {
    data.push_back(c);
  }
  length = stb_vorbis_decode_memory(data.data(), data.size(), &channels,
                                    &sample_rate, &decoded);

  return std::make_shared<Sound>(decoded, decoded + length);
}

std::shared_ptr<Stream> Assets::stream(const string file_name) const {
  return std::make_shared<mos::Stream>(directory_ + file_name);
}

Font Assets::font(const string &ngl_file_name) {
  std::map<char, Character> characters;
  rapidxml::xml_document<> doc;
  auto xml_string = text(ngl_file_name);
  doc.parse<0>(&xml_string[0]);

  auto *chars_node = doc.first_node("font")->first_node("chars");
  auto *description_node = doc.first_node("font")->first_node("description");
  std::string name = description_node->first_attribute("family")->value();
  float size = atof(description_node->first_attribute("family")->value());

  auto *metrics_node = doc.first_node("font")->first_node("metrics");
  float height = atof(metrics_node->first_attribute("height")->value());
  float ascender = atof(metrics_node->first_attribute("ascender")->value());
  float descender = atof(metrics_node->first_attribute("descender")->value());

  auto *texture_node = doc.first_node("font")->first_node("texture");
  std::string texture_file_name =
      texture_node->first_attribute("file")->value();

  for (auto *char_node = chars_node->first_node("char"); char_node;
       char_node = char_node->next_sibling()) {

    Character character;

    character.offset_x = atof(char_node->first_attribute("offset_x")->value());
    character.offset_y = atof(char_node->first_attribute("offset_y")->value());
    character.advance = atof(char_node->first_attribute("advance")->value());
    character.rect_w = atof(char_node->first_attribute("rect_w")->value());
    character.id = *char_node->first_attribute("id")->value();
    character.rect_x = atof(char_node->first_attribute("rect_x")->value());
    character.rect_y = atof(char_node->first_attribute("rect_y")->value());
    character.rect_h = atof(char_node->first_attribute("rect_h")->value());
    characters.insert(std::pair<char, Character>(character.id, character));
  }

  auto char_map = characters;
  auto texture = texture_cached(texture_file_name);
  return Font(char_map, texture, height, ascender, descender);
}

std::shared_ptr<Sound> Assets::sound_cached(const std::string file_name) {
  if (sounds_.find(file_name) == sounds_.end()) {

    sounds_.insert(SoundPair(file_name, sound(file_name)));
    return sounds_.at(file_name);
  } else {
    return sounds_.at(file_name);
  }
}

std::shared_ptr<Material> Assets::material(const std::string file_name) const {

  if (file_name.substr(file_name.find_last_of(".") + 1) == "material") {
    // std::cout << "Loading: " << directory_ + file_name << std::endl;
    std::ifstream is(directory_ + file_name, ios::binary);
    glm::vec3 ambient;
    glm::vec3 diffuse;
    glm::vec3 specular;
    float opacity;
    float specular_exponent;

    is.read((char *)&ambient, sizeof(glm::vec3));
    is.read((char *)&diffuse, sizeof(glm::vec3));
    is.read((char *)&specular, sizeof(glm::vec3));
    is.read((char *)&opacity, sizeof(float));
    is.read((char *)&specular_exponent, sizeof(float));

    return std::make_shared<Material>(ambient, diffuse, specular, opacity,
                                      specular_exponent);
  } else {
    // throw std::runtime_error(file_name.substr(file_name.find_last_of(".")) +
    // " file format is not supported.");
    return std::shared_ptr<Material>(nullptr);
  }
}

std::shared_ptr<Material> Assets::material_cached(const std::string file_name) {
  if (materials_.find(file_name) == materials_.end()) {

    materials_.insert(MaterialPair(file_name, material(file_name)));
    return materials_.at(file_name);
  } else {
    return materials_.at(file_name);
  }
}

std::string Assets::text(const std::string file_name) const {

  std::ifstream file(directory_ + file_name);
  std::string source((std::istreambuf_iterator<char>(file)),
                     std::istreambuf_iterator<char>());
  return source;
}

void Assets::clear_unused() {
  for (auto it = textures_.begin(); it != textures_.end();) {
    if (it->second.use_count() <= 1) {
      textures_.erase(it++);
    } else {
      ++it;
    }
  }
  for (auto it = meshes_.begin(); it != meshes_.end();) {
    if (it->second.use_count() <= 1) {
      meshes_.erase(it++);
    } else {
      ++it;
    }
  }
  for (auto it = sounds_.begin(); it != sounds_.end();) {
    if (it->second.use_count() <= 1) {
      sounds_.erase(it++);
    } else {
      ++it;
    }
  }
  for (auto it = materials_.begin(); it != materials_.end();) {
    if (it->second.use_count() <= 1) {
      materials_.erase(it++);
    } else {
      ++it;
    }
  }
}
}
<|endoftext|>


<commit_before>#include "nwg_service.h"

#include "nwg_eventloop.h"

namespace Nwg
{

Service::Service(EventLoop *eventLoop)
    : _eventLoop(eventLoop),
      _protocolCodec(nullptr),
      _handler(nullptr)
{
}

Service::~Service()
{
    _protocolCodec.reset();
    _handler.reset();
}

void Service::setBuffSize(int buffSize) { _buffSize = buffSize; }
void Service::setReadBuffSize(int readBuffSize) { _readBuffSize = readBuffSize; }

void Service::setProtocolCodec(const std::shared_ptr<ProtocolCodec> &protocolCodec)
{
    _protocolCodec = protocolCodec;
}

void Service::setHandler(const std::shared_ptr<Handler> &handler)
{
    _handler = handler;
}

EventLoop *Service::getEventLoop() const { return _eventLoop; }

size_t Service::getBuffSize() { return _buffSize; }
size_t Service::getReadBuffSize() { return _readBuffSize; }

ProtocolCodec &Service::getProtocolCodec()
{
    return *_protocolCodec;
}

Handler &Service::getHandler()
{
    return *_handler;
}

} /* namespace Nwg */
<commit_msg>Create BasicProtocolCodec if _protocolCodec is null<commit_after>#include "nwg_service.h"

#include "nwg_eventloop.h"
#include "nwg_basicprotocolcodec.h"

namespace Nwg
{

Service::Service(EventLoop *eventLoop)
    : _eventLoop(eventLoop),
      _protocolCodec(nullptr),
      _handler(nullptr)
{
}

Service::~Service()
{
    _protocolCodec.reset();
    _handler.reset();
}

void Service::setBuffSize(int buffSize) { _buffSize = buffSize; }
void Service::setReadBuffSize(int readBuffSize) { _readBuffSize = readBuffSize; }

void Service::setProtocolCodec(const std::shared_ptr<ProtocolCodec> &protocolCodec)
{
    _protocolCodec = protocolCodec;
}

void Service::setHandler(const std::shared_ptr<Handler> &handler)
{
    _handler = handler;
}

EventLoop *Service::getEventLoop() const { return _eventLoop; }

size_t Service::getBuffSize() { return _buffSize; }
size_t Service::getReadBuffSize() { return _readBuffSize; }

ProtocolCodec &Service::getProtocolCodec()
{
    if (_protocolCodec == nullptr) {
        _protocolCodec = std::make_shared<Nwg::BasicProtocolCodec>();
    }
    return *_protocolCodec;
}

Handler &Service::getHandler()
{
    return *_handler;
}

} /* namespace Nwg */
<|endoftext|>


<commit_before>#include "../../include/wrui.h"
#include "signal_wrappers.h"
#include <QApplication>
#include <QPushButton>

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static int app_run(void* app) {
	GUApplication* t = (GUApplication*)app;
	QApplication* qt_app = (QApplication*)t->p;
	return qt_app->exec();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static GUApplication* application_create() {
	int argc = 0;
	GUApplication* app = new GUApplication;
	app->p = (void*) new QApplication(argc, 0);
	app->run = app_run;
	return app;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static int connect(void* sender, const char* id, void* reciver, void* func) {
	GUObject* object = (GUObject*)sender;
	QObject* q_obj = (QObject*)object->p;
	printf("sender %p\n", q_obj);
	QSlotWrapperNoArgs* wrap = new QSlotWrapperNoArgs(reciver, (SignalNoArgs)func);
	QObject::connect(q_obj, "2released()", wrap, SLOT(method()));
	return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static GUPushButton* push_button_create(const char* label) {
	QPushButton* qt_button = new QPushButton(label, 0);

	// TODO: Smarter allocator than just using new all the time

	GUPushButton* button = new GUPushButton;

	qt_button->show();

	button->base = new GUWidget;
	button->base->o = new GUObject;

	button->base->o->p = (void*) static_cast<QObject*>(qt_button);

	printf("qobj %p\n", button->base->o->p);

	button->base->o->connect = connect;

	return button;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static Wrui s_wrui = {
	application_create,
	0,
	push_button_create,
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

extern "C" Wrui* wrui_get() {
	return &s_wrui;
}
<commit_msg>some debug printing<commit_after>#include "../../include/wrui.h"
#include "signal_wrappers.h"
#include <QApplication>
#include <QPushButton>

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static int app_run(void* app) {
	GUApplication* t = (GUApplication*)app;
	QApplication* qt_app = (QApplication*)t->p;
	return qt_app->exec();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static GUApplication* application_create() {
	int argc = 0;
	GUApplication* app = new GUApplication;
	app->p = (void*) new QApplication(argc, 0);
	app->run = app_run;
	return app;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static int connect(void* sender, const char* id, void* reciver, void* func) {
	GUObject* object = (GUObject*)sender;
	QObject* q_obj = (QObject*)object->p;
	printf("reciver %p - func %p\n", reciver, func);
	QSlotWrapperNoArgs* wrap = new QSlotWrapperNoArgs(reciver, (SignalNoArgs)func);
	QObject::connect(q_obj, "2released()", wrap, SLOT(method()));
	return 0;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static GUPushButton* push_button_create(const char* label) {
	QPushButton* qt_button = new QPushButton(label, 0);

	// TODO: Smarter allocator than just using new all the time

	GUPushButton* button = new GUPushButton;

	qt_button->show();

	button->base = new GUWidget;
	button->base->o = new GUObject;

	button->base->o->p = (void*) static_cast<QObject*>(qt_button);

	printf("qobj %p\n", button->base->o->p);

	button->base->o->connect = connect;

	return button;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static Wrui s_wrui = {
	application_create,
	0,
	push_button_create,
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

extern "C" Wrui* wrui_get() {
	return &s_wrui;
}
<|endoftext|>


<commit_before>#include "openmc/random_lcg.h"

#include <cmath>

namespace openmc {

// Starting seed
int64_t master_seed {1};

// LCG parameters
constexpr uint64_t prn_mult   {2806196910506780709LL};   // multiplication
                                                         //   factor, g
constexpr uint64_t prn_add    {1};                       // additive factor, c
constexpr uint64_t prn_mod    {0x8000000000000000};      // 2^63
constexpr uint64_t prn_mask   {0x7fffffffffffffff};      // 2^63 - 1
constexpr uint64_t prn_stride {152917LL};                // stride between
                                                         //   particles
constexpr double   prn_norm   {1.0 / prn_mod};           // 2^-63

//==============================================================================
// PRN
//==============================================================================

double prn(uint64_t* seed)
{
  // This algorithm uses bit-masking to find the next integer(8) value to be
  // used to calculate the random number.
  *seed = (prn_mult * (*seed) + prn_add) & prn_mask;

  // Once the integer is calculated, we just need to divide by 2**m,
  // represented here as multiplying by a pre-calculated factor
  return (*seed) * prn_norm;
}

//==============================================================================
// FUTURE_PRN
//==============================================================================

double future_prn(int64_t n, uint64_t seed)
{
  return future_seed(static_cast<uint64_t>(n), seed) * prn_norm;
}

//==============================================================================
// INIT_SEED
//==============================================================================

uint64_t init_seed(int64_t id, int offset)
{
  return future_seed(static_cast<uint64_t>(id) * prn_stride, master_seed + offset);
}

//==============================================================================
// INIT_PARTICLE_SEEDS
//==============================================================================

void init_particle_seeds(int64_t id, uint64_t* prn_seeds)
{
  for (int i = 0; i < N_STREAMS; i++) {
    prn_seeds[i] = future_seed(static_cast<uint64_t>(id) * prn_stride, master_seed + i);
  }
}

//==============================================================================
// ADVANCE_PRN_SEED
//==============================================================================

void advance_prn_seed(int64_t n, uint64_t* seed)
{
  *seed = future_seed(static_cast<uint64_t>(n), *seed);
}

//==============================================================================
// FUTURE_SEED
//==============================================================================

uint64_t future_seed(uint64_t n, uint64_t seed)
{
  // Make sure nskip is less than 2^M.
  n &= prn_mask;

  // The algorithm here to determine the parameters used to skip ahead is
  // described in F. Brown, "Random Number Generation with Arbitrary Stride,"
  // Trans. Am. Nucl. Soc. (Nov. 1994). This algorithm is able to skip ahead in
  // O(log2(N)) operations instead of O(N). Basically, it computes parameters G
  // and C which can then be used to find x_N = G*x_0 + C mod 2^M.

  // Initialize constants
  uint64_t g     {prn_mult};
  uint64_t c     {prn_add};
  uint64_t g_new {1};
  uint64_t c_new {0};

  while (n > 0) {
    // Check if the least significant bit is 1.
    if (n & 1) {
      g_new *= g;
      c_new = c_new * g + c;
    }
    c *= (g + 1);
    g *= g;

    // Move bits right, dropping least significant bit.
    n >>= 1;
  }

  // With G and C, we can now find the new seed.
  return (g_new * seed + c_new) & prn_mask;
}

//==============================================================================
//                               API FUNCTIONS
//==============================================================================

extern "C" int64_t openmc_get_seed() {return master_seed;}

extern "C" void openmc_set_seed(int64_t new_seed)
{
  master_seed = new_seed;
}

} // namespace openmc
<commit_msg>refactor seed and seed aray variable names<commit_after>#include "openmc/random_lcg.h"

#include <cmath>

namespace openmc {

// Starting seed
int64_t master_seed {1};

// LCG parameters
constexpr uint64_t prn_mult   {2806196910506780709LL};   // multiplication
                                                         //   factor, g
constexpr uint64_t prn_add    {1};                       // additive factor, c
constexpr uint64_t prn_mod    {0x8000000000000000};      // 2^63
constexpr uint64_t prn_mask   {0x7fffffffffffffff};      // 2^63 - 1
constexpr uint64_t prn_stride {152917LL};                // stride between
                                                         //   particles
constexpr double   prn_norm   {1.0 / prn_mod};           // 2^-63

//==============================================================================
// PRN
//==============================================================================

double prn(uint64_t* seed)
{
  // This algorithm uses bit-masking to find the next integer(8) value to be
  // used to calculate the random number.
  *seed = (prn_mult * (*seed) + prn_add) & prn_mask;

  // Once the integer is calculated, we just need to divide by 2**m,
  // represented here as multiplying by a pre-calculated factor
  return (*seed) * prn_norm;
}

//==============================================================================
// FUTURE_PRN
//==============================================================================

double future_prn(int64_t n, uint64_t seed)
{
  return future_seed(static_cast<uint64_t>(n), seed) * prn_norm;
}

//==============================================================================
// INIT_SEED
//==============================================================================

uint64_t init_seed(int64_t id, int offset)
{
  return future_seed(static_cast<uint64_t>(id) * prn_stride, master_seed + offset);
}

//==============================================================================
// INIT_PARTICLE_SEEDS
//==============================================================================

void init_particle_seeds(int64_t id, uint64_t* seeds)
{
  for (int i = 0; i < N_STREAMS; i++) {
    seeds[i] = future_seed(static_cast<uint64_t>(id) * prn_stride, master_seed + i);
  }
}

//==============================================================================
// ADVANCE_PRN_SEED
//==============================================================================

void advance_prn_seed(int64_t n, uint64_t* seed)
{
  *seed = future_seed(static_cast<uint64_t>(n), *seed);
}

//==============================================================================
// FUTURE_SEED
//==============================================================================

uint64_t future_seed(uint64_t n, uint64_t seed)
{
  // Make sure nskip is less than 2^M.
  n &= prn_mask;

  // The algorithm here to determine the parameters used to skip ahead is
  // described in F. Brown, "Random Number Generation with Arbitrary Stride,"
  // Trans. Am. Nucl. Soc. (Nov. 1994). This algorithm is able to skip ahead in
  // O(log2(N)) operations instead of O(N). Basically, it computes parameters G
  // and C which can then be used to find x_N = G*x_0 + C mod 2^M.

  // Initialize constants
  uint64_t g     {prn_mult};
  uint64_t c     {prn_add};
  uint64_t g_new {1};
  uint64_t c_new {0};

  while (n > 0) {
    // Check if the least significant bit is 1.
    if (n & 1) {
      g_new *= g;
      c_new = c_new * g + c;
    }
    c *= (g + 1);
    g *= g;

    // Move bits right, dropping least significant bit.
    n >>= 1;
  }

  // With G and C, we can now find the new seed.
  return (g_new * seed + c_new) & prn_mask;
}

//==============================================================================
//                               API FUNCTIONS
//==============================================================================

extern "C" int64_t openmc_get_seed() {return master_seed;}

extern "C" void openmc_set_seed(int64_t new_seed)
{
  master_seed = new_seed;
}

} // namespace openmc
<|endoftext|>


<commit_before>/*
 * This file is part of liblcf. Copyright (c) 2017 liblcf authors.
 * https://github.com/EasyRPG/liblcf - https://easyrpg.org
 *
 * liblcf is Free/Libre Open Source Software, released under the MIT License.
 * For the full copyright and license information, please view the COPYING
 * file that was distributed with this source code.
 */

#include <cstdarg>
#include <istream>

#include "reader_lcf.h"
#ifdef NDEBUG
#  include <stdio.h>
#endif

// Statics

std::string LcfReader::error_str;

LcfReader::LcfReader(std::istream& filestream, std::string encoding) :
	encoding(encoding),
	stream(filestream)
{
}

LcfReader::~LcfReader() {
}

size_t LcfReader::Read0(void *ptr, size_t size, size_t nmemb) {
	if (size == 0) { //avoid division by 0
		return 0;
	}
	//Read nmemb elements of size and return the number of read elements
	stream.read(reinterpret_cast<char*>(ptr), size*nmemb);
	size_t result = stream.gcount() / size;
#ifdef NDEBUG
	if (result != nmemb && !Eof()) {
		perror("Reading error: ");
	}
#endif
	return result;
}

void LcfReader::Read(void *ptr, size_t size, size_t nmemb) {
#ifdef NDEBUG
	Read0(ptr, size, nmemb);
#else
	if (Read0(ptr, size, nmemb) != nmemb) {
		fprintf(stderr, "Read error at %d. The file is probably corrupted\n", Tell());
	}
#endif
}

template <>
void LcfReader::Read<bool>(bool& ref) {
	ref = ReadInt() > 0;
}

template <>
void LcfReader::Read<uint8_t>(uint8_t& ref) {
	Read(&ref, 1, 1);
}

template <>
void LcfReader::Read<int16_t>(int16_t& ref) {
	Read(&ref, 2, 1);
	SwapByteOrder(ref);
}

template <>
void LcfReader::Read<uint32_t>(uint32_t& ref) {
	Read(&ref, 4, 1);
	SwapByteOrder(ref);
}

int LcfReader::ReadInt() {
	int value = 0;
	unsigned char temp = 0;
	int loops = 0;
	do {
		value <<= 7;
		if (Read0(&temp, 1, 1) == 0) {
			assert(value == 0);
			return 0;
		}
		value |= temp & 0x7F;

		if (loops > 5) {
			fprintf(stderr, "Invalid compressed integer at %d\n", Tell());
		}
		++loops;
	} while (temp & 0x80);

	return loops > 5 ? 0 : value;
}

template <>
void LcfReader::Read<int32_t>(int32_t& ref) {
	ref = ReadInt();
}

template <>
void LcfReader::Read<double>(double& ref) {
	Read(&ref, 8, 1);
	SwapByteOrder(ref);
}

template <>
void LcfReader::Read<bool>(std::vector<bool> &buffer, size_t size) {
	buffer.clear();

	for (unsigned i = 0; i < size; ++i) {
		uint8_t val;
		Read(&val, 1, 1);
		buffer.push_back(val > 0);
	}
}

template <>
void LcfReader::Read<uint8_t>(std::vector<uint8_t> &buffer, size_t size) {
	buffer.clear();

	for (unsigned int i = 0; i < size; ++i) {
		uint8_t val;
		Read(&val, 1, 1);
		buffer.push_back(val);
	}
}

template <>
void LcfReader::Read<int16_t>(std::vector<int16_t> &buffer, size_t size) {
	buffer.clear();
	size_t items = size / 2;
	for (unsigned int i = 0; i < items; ++i) {
		int16_t val;
		Read(&val, 2, 1);
		SwapByteOrder(val);
		buffer.push_back(val);
	}
	if (size % 2 != 0) {
		Seek(1, FromCurrent);
		buffer.push_back(0);
	}
}

template <>
void LcfReader::Read<int32_t>(std::vector<int32_t> &buffer, size_t size) {
	buffer.clear();
	size_t items = size / 4;
	for (unsigned int i = 0; i < items; ++i) {
		int32_t val;
		Read(&val, 4, 1);
		SwapByteOrder(val);
		buffer.push_back(val);
	}
	if (size % 4 != 0) {
		Seek(size % 4, FromCurrent);
		buffer.push_back(0);
	}
}

template <>
void LcfReader::Read<uint32_t>(std::vector<uint32_t> &buffer, size_t size) {
	buffer.clear();
	size_t items = size / 4;
	for (unsigned int i = 0; i < items; ++i) {
		uint32_t val;
		Read(&val, 4, 1);
		SwapByteOrder(val);
		buffer.push_back(val);
	}
	if (size % 4 != 0) {
		Seek(size % 4, FromCurrent);
		buffer.push_back(0);
	}
}

void LcfReader::ReadString(std::string& ref, size_t size) {
	char* chars = new char[size];
	Read(chars, 1, size);
	ref = Encode(std::string(chars, size));
	delete[] chars;
}

bool LcfReader::IsOk() const {
	return (stream.good());
}

bool LcfReader::Eof() const {
	return stream.eof();
}

void LcfReader::Seek(size_t pos, SeekMode mode) {
	switch (mode) {
	case LcfReader::FromStart:
		stream.seekg(pos, std::ios_base::beg);
		break;
	case LcfReader::FromCurrent:
		stream.seekg(pos, std::ios_base::cur);
		break;
	case LcfReader::FromEnd:
		stream.seekg(pos, std::ios_base::end);
		break;
	default:
		assert(false && "Invalid SeekMode");
	}
}

uint32_t LcfReader::Tell() {
	return (uint32_t)stream.tellg();
}

int LcfReader::Peek() {
	return stream.peek();
}

#ifdef _DEBUG
void LcfReader::SkipDebug(const struct LcfReader::Chunk& chunk_info, const char* srcfile) {
	// Dump the Chunk Data in Debug Mode
#ifdef _WIN32
	const char* srcfilename = strrchr(srcfile, '\\');
#else
	const char* srcfilename = strrchr(srcfile, '/');
#endif
	if (srcfilename == NULL) {
		srcfilename = srcfile;
	} else {
		srcfilename++;
	}
	fprintf(stderr, "Skipped Chunk %02X (%d byte) in lcf at %X (%s)\n",
			chunk_info.ID, chunk_info.length,  Tell(),
			srcfilename);
	for (uint32_t i = 0; i < chunk_info.length; ++i) {
		uint8_t byte;
		LcfReader::Read(byte);
		fprintf(stderr, "%02X ", byte);
		if ((i+1) % 16 == 0) {
			fprintf(stderr, "\n");
		}
		if (Eof()) {
			break;
		}
	}
	fprintf(stderr, "\n");
}
#else
void LcfReader::Skip(const struct LcfReader::Chunk& chunk_info) {
	Seek((size_t)chunk_info.length, FromCurrent);
}
#endif

void LcfReader::SetError(const char* fmt, ...) {
	va_list args;
	va_start(args, fmt);

	char str[256];
	vsprintf(str, fmt, args);

	error_str = str;
	//Output::ErrorStr((std::string)str);

	va_end(args);
}

const std::string& LcfReader::GetError() {
	return error_str;
}

std::string LcfReader::Encode(const std::string& str_to_encode) {
	return ReaderUtil::Recode(str_to_encode, encoding, "UTF-8");
}

int LcfReader::IntSize(unsigned int x) {
	int result = 0;
	do {
		x >>= 7;
		result++;
	} while (x != 0);
	return result;
}

#ifdef WORDS_BIGENDIAN
void LcfReader::SwapByteOrder(uint16_t& us)
{
	us =	(us >> 8) |
			(us << 8);
}

void LcfReader::SwapByteOrder(uint32_t& ui)
{
	ui =	(ui >> 24) |
			((ui<<8) & 0x00FF0000) |
			((ui>>8) & 0x0000FF00) |
			(ui << 24);
}

void LcfReader::SwapByteOrder(double& d)
{
	uint32_t *p = reinterpret_cast<uint32_t *>(&d);
	SwapByteOrder(p[0]);
	SwapByteOrder(p[1]);
	uint32_t tmp = p[0];
	p[0] = p[1];
	p[1] = tmp;
}
#else
void LcfReader::SwapByteOrder(uint16_t& /* us */) {}
void LcfReader::SwapByteOrder(uint32_t& /* ui */) {}
void LcfReader::SwapByteOrder(double& /* d */) {}
#endif

void LcfReader::SwapByteOrder(int16_t& s)
{
	SwapByteOrder((uint16_t&) s);
}

void LcfReader::SwapByteOrder(int32_t& s)
{
	SwapByteOrder((uint32_t&) s);
}
<commit_msg> Merge pull request #230 from BSzili/master<commit_after>/*
 * This file is part of liblcf. Copyright (c) 2017 liblcf authors.
 * https://github.com/EasyRPG/liblcf - https://easyrpg.org
 *
 * liblcf is Free/Libre Open Source Software, released under the MIT License.
 * For the full copyright and license information, please view the COPYING
 * file that was distributed with this source code.
 */

#include <cstdarg>
#include <cstdio>
#include <istream>

#include "reader_lcf.h"

// Statics

std::string LcfReader::error_str;

LcfReader::LcfReader(std::istream& filestream, std::string encoding) :
	encoding(encoding),
	stream(filestream)
{
}

LcfReader::~LcfReader() {
}

size_t LcfReader::Read0(void *ptr, size_t size, size_t nmemb) {
	if (size == 0) { //avoid division by 0
		return 0;
	}
	//Read nmemb elements of size and return the number of read elements
	stream.read(reinterpret_cast<char*>(ptr), size*nmemb);
	size_t result = stream.gcount() / size;
#ifdef NDEBUG
	if (result != nmemb && !Eof()) {
		perror("Reading error: ");
	}
#endif
	return result;
}

void LcfReader::Read(void *ptr, size_t size, size_t nmemb) {
#ifdef NDEBUG
	Read0(ptr, size, nmemb);
#else
	if (Read0(ptr, size, nmemb) != nmemb) {
		fprintf(stderr, "Read error at %d. The file is probably corrupted\n", Tell());
	}
#endif
}

template <>
void LcfReader::Read<bool>(bool& ref) {
	ref = ReadInt() > 0;
}

template <>
void LcfReader::Read<uint8_t>(uint8_t& ref) {
	Read(&ref, 1, 1);
}

template <>
void LcfReader::Read<int16_t>(int16_t& ref) {
	Read(&ref, 2, 1);
	SwapByteOrder(ref);
}

template <>
void LcfReader::Read<uint32_t>(uint32_t& ref) {
	Read(&ref, 4, 1);
	SwapByteOrder(ref);
}

int LcfReader::ReadInt() {
	int value = 0;
	unsigned char temp = 0;
	int loops = 0;
	do {
		value <<= 7;
		if (Read0(&temp, 1, 1) == 0) {
			assert(value == 0);
			return 0;
		}
		value |= temp & 0x7F;

		if (loops > 5) {
			fprintf(stderr, "Invalid compressed integer at %d\n", Tell());
		}
		++loops;
	} while (temp & 0x80);

	return loops > 5 ? 0 : value;
}

template <>
void LcfReader::Read<int32_t>(int32_t& ref) {
	ref = ReadInt();
}

template <>
void LcfReader::Read<double>(double& ref) {
	Read(&ref, 8, 1);
	SwapByteOrder(ref);
}

template <>
void LcfReader::Read<bool>(std::vector<bool> &buffer, size_t size) {
	buffer.clear();

	for (unsigned i = 0; i < size; ++i) {
		uint8_t val;
		Read(&val, 1, 1);
		buffer.push_back(val > 0);
	}
}

template <>
void LcfReader::Read<uint8_t>(std::vector<uint8_t> &buffer, size_t size) {
	buffer.clear();

	for (unsigned int i = 0; i < size; ++i) {
		uint8_t val;
		Read(&val, 1, 1);
		buffer.push_back(val);
	}
}

template <>
void LcfReader::Read<int16_t>(std::vector<int16_t> &buffer, size_t size) {
	buffer.clear();
	size_t items = size / 2;
	for (unsigned int i = 0; i < items; ++i) {
		int16_t val;
		Read(&val, 2, 1);
		SwapByteOrder(val);
		buffer.push_back(val);
	}
	if (size % 2 != 0) {
		Seek(1, FromCurrent);
		buffer.push_back(0);
	}
}

template <>
void LcfReader::Read<int32_t>(std::vector<int32_t> &buffer, size_t size) {
	buffer.clear();
	size_t items = size / 4;
	for (unsigned int i = 0; i < items; ++i) {
		int32_t val;
		Read(&val, 4, 1);
		SwapByteOrder(val);
		buffer.push_back(val);
	}
	if (size % 4 != 0) {
		Seek(size % 4, FromCurrent);
		buffer.push_back(0);
	}
}

template <>
void LcfReader::Read<uint32_t>(std::vector<uint32_t> &buffer, size_t size) {
	buffer.clear();
	size_t items = size / 4;
	for (unsigned int i = 0; i < items; ++i) {
		uint32_t val;
		Read(&val, 4, 1);
		SwapByteOrder(val);
		buffer.push_back(val);
	}
	if (size % 4 != 0) {
		Seek(size % 4, FromCurrent);
		buffer.push_back(0);
	}
}

void LcfReader::ReadString(std::string& ref, size_t size) {
	char* chars = new char[size];
	Read(chars, 1, size);
	ref = Encode(std::string(chars, size));
	delete[] chars;
}

bool LcfReader::IsOk() const {
	return (stream.good());
}

bool LcfReader::Eof() const {
	return stream.eof();
}

void LcfReader::Seek(size_t pos, SeekMode mode) {
	switch (mode) {
	case LcfReader::FromStart:
		stream.seekg(pos, std::ios_base::beg);
		break;
	case LcfReader::FromCurrent:
		stream.seekg(pos, std::ios_base::cur);
		break;
	case LcfReader::FromEnd:
		stream.seekg(pos, std::ios_base::end);
		break;
	default:
		assert(false && "Invalid SeekMode");
	}
}

uint32_t LcfReader::Tell() {
	return (uint32_t)stream.tellg();
}

int LcfReader::Peek() {
	return stream.peek();
}

#ifdef _DEBUG
void LcfReader::SkipDebug(const struct LcfReader::Chunk& chunk_info, const char* srcfile) {
	// Dump the Chunk Data in Debug Mode
#ifdef _WIN32
	const char* srcfilename = strrchr(srcfile, '\\');
#else
	const char* srcfilename = strrchr(srcfile, '/');
#endif
	if (srcfilename == NULL) {
		srcfilename = srcfile;
	} else {
		srcfilename++;
	}
	fprintf(stderr, "Skipped Chunk %02X (%d byte) in lcf at %X (%s)\n",
			chunk_info.ID, chunk_info.length,  Tell(),
			srcfilename);
	for (uint32_t i = 0; i < chunk_info.length; ++i) {
		uint8_t byte;
		LcfReader::Read(byte);
		fprintf(stderr, "%02X ", byte);
		if ((i+1) % 16 == 0) {
			fprintf(stderr, "\n");
		}
		if (Eof()) {
			break;
		}
	}
	fprintf(stderr, "\n");
}
#else
void LcfReader::Skip(const struct LcfReader::Chunk& chunk_info) {
	Seek((size_t)chunk_info.length, FromCurrent);
}
#endif

void LcfReader::SetError(const char* fmt, ...) {
	va_list args;
	va_start(args, fmt);

	char str[256];
	vsprintf(str, fmt, args);

	error_str = str;
	//Output::ErrorStr((std::string)str);

	va_end(args);
}

const std::string& LcfReader::GetError() {
	return error_str;
}

std::string LcfReader::Encode(const std::string& str_to_encode) {
	return ReaderUtil::Recode(str_to_encode, encoding, "UTF-8");
}

int LcfReader::IntSize(unsigned int x) {
	int result = 0;
	do {
		x >>= 7;
		result++;
	} while (x != 0);
	return result;
}

#ifdef WORDS_BIGENDIAN
void LcfReader::SwapByteOrder(uint16_t& us)
{
	us =	(us >> 8) |
			(us << 8);
}

void LcfReader::SwapByteOrder(uint32_t& ui)
{
	ui =	(ui >> 24) |
			((ui<<8) & 0x00FF0000) |
			((ui>>8) & 0x0000FF00) |
			(ui << 24);
}

void LcfReader::SwapByteOrder(double& d)
{
	uint32_t *p = reinterpret_cast<uint32_t *>(&d);
	SwapByteOrder(p[0]);
	SwapByteOrder(p[1]);
	uint32_t tmp = p[0];
	p[0] = p[1];
	p[1] = tmp;
}
#else
void LcfReader::SwapByteOrder(uint16_t& /* us */) {}
void LcfReader::SwapByteOrder(uint32_t& /* ui */) {}
void LcfReader::SwapByteOrder(double& /* d */) {}
#endif

void LcfReader::SwapByteOrder(int16_t& s)
{
	SwapByteOrder((uint16_t&) s);
}

void LcfReader::SwapByteOrder(int32_t& s)
{
	SwapByteOrder((uint32_t&) s);
}
<|endoftext|>