<commit_before>/*
 * gameMgr.cpp
 *
 *  Created on: Mar 11, 2017
 *      Author: sushil
 */

#include <gameMgr.h>
#include <engine.h>
#include <OgreMeshManager.h>

GameMgr::GameMgr(Engine *engine): Mgr(engine){
	floor = Ogre::Plane(Ogre::Vector3::UNIT_Y, 0);
    ceiling = new Ogre::MovablePlane("ceiling");
    ceiling->d = 0;
    ceiling->normal = Ogre::Vector3::UNIT_Y;
}

GameMgr::~GameMgr(){

}

void GameMgr::init(){

}

void GameMgr::loadLevel(){
	this->loadLevel("level001.txt");

}

void GameMgr::stop(){

}

void GameMgr::tick(float dt){

}

void GameMgr::createGround(int &width, int &heigth, std::string &material)
{
	// Create Plane //////////////////////////////////////////////////////////////////////////////////////////
	Ogre::MeshManager::getSingleton().createPlane(
	    "ground",
	    Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
	    floor,
		width, heigth, 20, 20,
	    true,
	    1, 5, 5,
	    Ogre::Vector3::UNIT_Z);
	//////////////////////////////////////////////////////////////////////////////////////////////////////////

	// Create Ground Entity //////////////////////////////////////////////////////////////////////////////////
	Ogre::Entity* groundEntity = engine->gfxMgr->ogreSceneManager->createEntity("ground");
	engine->gfxMgr->ogreSceneManager->getRootSceneNode()->createChildSceneNode()->attachObject(groundEntity);
	groundEntity->setCastShadows(false);
	groundEntity->setMaterialName(material);
	//////////////////////////////////////////////////////////////////////////////////////////////////////////

	// Create Separated Water Ground ////////////////////////////////////////////////////////////////////////
	Ogre::Entity* groundEntity2 = engine->gfxMgr->ogreSceneManager->createEntity("ground");
	engine->gfxMgr->ogreSceneManager->getRootSceneNode()->createChildSceneNode()->attachObject(groundEntity2);
	groundEntity2->setCastShadows(false);
	groundEntity2->setMaterialName("Examples/WaterStream");
	//////////////////////////////////////////////////////////////////////////////////////////////////////////
}

void GameMgr::createCeiling()
{
	Ogre::MovablePlane plane(Ogre::Vector3::UNIT_Y, 50);

	// Create Ceiling ///////////////////////////////////////////////////////////////////////////////////////
	Ogre::MeshManager::getSingleton().createPlane(
	    "ceiling",
	    Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
		plane,
		4000, 3400, 20, 20,
	    true,
	    1, 5, 5,
	    Ogre::Vector3::UNIT_Z);
	//////////////////////////////////////////////////////////////////////////////////////////////////////////

	// Create Ceiling Entity //////////////////////////////////////////////////////////////////////////////////
	Ogre::Entity* ceiling = engine->gfxMgr->ogreSceneManager->createEntity("ceiling");
	engine->gfxMgr->ogreSceneManager->getRootSceneNode()->createChildSceneNode()->attachObject(ceiling);
	ceiling->setCastShadows(false);
	ceiling->setMaterialName("Examples/Rockwall");
}

void GameMgr::createSky(){

	engine->gfxMgr->ogreSceneManager->setSkyBox(true, "Examples/SpaceSkyBox");

}

void GameMgr::loadLevel(std::string levelFilename)
{
	// Load the environment, objects, and characters
	this->loadEnvironment(levelFilename);
	this->setupEnvironment();
	this->loadObjects();
	this->loadCharacters();
}

void GameMgr::loadEnvironment(std::string levelFilename)
{
	// Variables
	std::ifstream fin;
	int x, z;
	float x_offset, y_offset, z_offset;
	float scale, orientation;
	std::string groundMaterial, objectMesh, characterMesh;
	std::string buffer;
	char objectChar;

	// Open File
	fin.open(levelFilename);

	// Check for bad file
	if(!fin.is_open())
	{
		std::cerr << "ERROR, FILE CANNOT BE OPENED" << std::endl;
		return;
	}

	// First block is world dimensions and material name
	fin >> x >> z;
	fin >> groundMaterial;

	// TESTING FILE READ ////////////////////////////////////////////
	std::cerr << "Ground Dimensions: " << x << " x " << z << std::endl;
	std::cerr << "Ground Material: " << groundMaterial << std::endl;
	/////////////////////////////////////////////////////////////////

	// Create floor mesh with read in dimensions
	createGround( x, z, groundMaterial);

	// Create Ceiling
	// createCeiling(); DEBUG THIS

	// Second block reads in location of you and enemies
	// Check for Objects line
	fin >> buffer;

	if( buffer != "Objects" )
	{
		std::cerr << "FILE NOT FORMATTED CORRECTLY" << std::endl;
	}

	// Read Objects and positions
	fin >> objectChar >> objectMesh;
	fin >> x_offset >> y_offset >> z_offset;
	fin >> orientation >> scale;

	// Testing Second Box Readin ///////////////////////////////////
	std::cerr << "Objects" << std::endl;
	std::cerr << objectChar << " " << objectMesh << std::endl;
	std::cerr << "Located at: " << x_offset << ", " << y_offset << ", " << z_offset << std::endl;
	std::cerr << "Scaled at: " << orientation << " " << scale << std::endl;
	///////////////////////////////////////////////////////////////

	// Check for Characters line /////////////////////////////////////////////////////////////////
	fin >> buffer;

	if( buffer != "Characters" )
	{
		std::cerr << "FILE NOT FORMATTED CORRECTLY" << std::endl;
	}

	// Read in Characters
	fin >> objectChar >> characterMesh;
	fin >> x_offset >> y_offset >> z_offset;
	fin >> orientation >> scale;

	// Testing Third Box Readin ///////////////////////////////////
	std::cerr << "Characters" << std::endl;
	std::cerr << objectChar << " " << characterMesh << std::endl;
	std::cerr << "Located at: " << x_offset << ", " << y_offset << ", " << z_offset << std::endl;
	std::cerr << "Scaled at: " << orientation << " " << scale << std::endl;
	///////////////////////////////////////////////////////////////

	// Read the World Placement //////////////////////////////////////////////////////////////////
	char c;

	// Start to see if world is in file
	fin >> buffer;

	if( buffer != "World" )
	{
		std::cerr << "FILE NOT FORMATTED CORRECTLY" << std::endl;
	}

	// Pre Conditions for World setup
	Ogre::Vector3 wallPosition;
	wallPosition = Ogre::Vector3(-1850, 50, 1200);

	Ogre::Vector3 archPosition;
	archPosition = Ogre::Vector3(0, 0, 0);

	Ogre::Vector3 enemyPosition;
	enemyPosition = Ogre::Vector3(-1200, 0, 1000);

	/*
	Ogre::ManualObject test;
	test.convertToMesh(objectMesh, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
	*/

	// Loop through map dimensions
	for( int row = 0; row < ROW_SIZE; row++ )
	{
		for( int col = 0; col < COL_SIZE; col++ )
		{
			fin >> c;
			std::cerr << c << std::endl;

			// Check for walls (Not player or enemy nodes)
			if( c == 'W' )
			{
				std::cerr << "Creating Wall" << std::endl;

				engine->entityMgr->CreateEntity(EntityType::WALL, wallPosition, 0);
				//engine->entityMgr->

				// Create a Wall
				/*
				Ogre::Entity* wallEntity = engine->gfxMgr->ogreSceneManager->createEntity(getNewName(), objectMesh);
				wallEntity->setMaterialName("Examples/RustySteel");
				engine->gfxMgr->wallNode = engine->gfxMgr->ogreSceneManager->getRootSceneNode()->createChildSceneNode(wallPosition);
				engine->gfxMgr->wallNode->attachObject(wallEntity);
				*/

				// Set Scale and position
				//engine->gfxMgr->ogreSceneManager->getRootSceneNode()->setScale(0.1f, 1.0f, 0.1f);
				//engine->gfxMgr->ogreSceneManager->getRootSceneNode()->setPosition(wallPosition);

				// Check wall position to prevent going outside of map
				if( wallPosition.x < 1800 ||
					wallPosition.x > -1800 ||
					wallPosition.z > -3000 ||
					wallPosition.z < 3000 )
				{
					// reset position
					//wallPosition.x = 0;
					//wallPosition.z = 0;

					// Increment Positions to prevent overlap from reset
					wallPosition.x += 25;
					//wallPosition.z += 25;
				}

				//wallPosition.z += 50;

				// Set blocked area
			}

			// Check for Arch
			else if( c == 'A' )
			{
				std::cerr << "Spawning Arch" << std::endl;
				engine->entityMgr->CreateEntity(EntityType::ARCH, archPosition, 0);
				archPosition.x += 50;

			}

			else if( c == 'C' )
			{
				// Spawn Enemy
				std::cerr << "Spawning Enemy" << std::endl;

				loadCharacters();
/*
				// Create Test Enemy
				Ogre::Entity* enemyEntity = engine->gfxMgr->ogreSceneManager->createEntity(getNewName(), characterMesh);
				// enemyEntity->setMaterialName("Examples/RustySteel");

				engine->gfxMgr->ogreSceneManager->getRootSceneNode()->createChildSceneNode(enemyPosition)->attachObject(enemyEntity);

				// Set Scale and position
				engine->gfxMgr->ogreSceneManager->getRootSceneNode()->setScale(0.1f, 0.02f, 0.1f);
				//engine->gfxMgr->ogreSceneManager->getRootSceneNode()->setPosition(position);

				enemyPosition.x += 10; // Increment Positions to prevent overlap
				//enemyPosition.z += 50;
*/
			}
		}
	}

	// Create the Entities

	// Create Skybox for the hell of it
	createSky();
}

void GameMgr::setupEnvironment()
{
	//We know graphicsMgr is ready and initialized
	engine->gfxMgr->ogreSceneManager->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));
	Ogre::Light* light = engine->gfxMgr->ogreSceneManager->createLight("MainLight");
	light->setType(Ogre::Light::LT_POINT);
	light->setPosition(100.0, 800.0, 100.0);
	light->setDiffuseColour(Ogre::ColourValue::White);
	light->setSpecularColour(Ogre::ColourValue::White);
}

void GameMgr::loadObjects()
{

}

void GameMgr::loadCharacters()
{
	//Creating the entities
	engine->entityMgr->CreateEntity(EntityType::HEARNO, Ogre::Vector3(0, 10, -1000), 0);
	engine->entityMgr->CreateEntity(EntityType::SEENO, Ogre::Vector3(500, 0, -500), Ogre::Math::HALF_PI / 2);
	engine->entityMgr->CreateEntity(EntityType::SPEAKNO, Ogre::Vector3(-500, 20, -500), Ogre::Math::HALF_PI / -2);

}

std::string GameMgr:: getNewName()
{
	static int count = 0;

	std::string s;
	std::stringstream out;
	out << count ++;
	s = out.str();

	return "object_" + s;
}

<commit_msg>Removed Ceiling Call<commit_after>/*
 * gameMgr.cpp
 *
 *  Created on: Mar 11, 2017
 *      Author: sushil
 */

#include <gameMgr.h>
#include <engine.h>
#include <OgreMeshManager.h>

GameMgr::GameMgr(Engine *engine): Mgr(engine){
	floor = Ogre::Plane(Ogre::Vector3::UNIT_Y, 0);
    ceiling = new Ogre::MovablePlane("ceiling");
    ceiling->d = 0;
    ceiling->normal = Ogre::Vector3::UNIT_Y;
}

GameMgr::~GameMgr(){

}

void GameMgr::init(){

}

void GameMgr::loadLevel(){
	this->loadLevel("level001.txt");

}

void GameMgr::stop(){

}

void GameMgr::tick(float dt){

}

void GameMgr::createGround(int &width, int &heigth, std::string &material)
{
	// Create Plane //////////////////////////////////////////////////////////////////////////////////////////
	Ogre::MeshManager::getSingleton().createPlane(
	    "ground",
	    Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
	    floor,
		width, heigth, 20, 20,
	    true,
	    1, 5, 5,
	    Ogre::Vector3::UNIT_Z);
	//////////////////////////////////////////////////////////////////////////////////////////////////////////

	// Create Ground Entity //////////////////////////////////////////////////////////////////////////////////
	Ogre::Entity* groundEntity = engine->gfxMgr->ogreSceneManager->createEntity("ground");
	engine->gfxMgr->ogreSceneManager->getRootSceneNode()->createChildSceneNode()->attachObject(groundEntity);
	groundEntity->setCastShadows(false);
	groundEntity->setMaterialName(material);
	//////////////////////////////////////////////////////////////////////////////////////////////////////////

	// Create Separated Water Ground ////////////////////////////////////////////////////////////////////////
	Ogre::Entity* groundEntity2 = engine->gfxMgr->ogreSceneManager->createEntity("ground");
	engine->gfxMgr->ogreSceneManager->getRootSceneNode()->createChildSceneNode()->attachObject(groundEntity2);
	groundEntity2->setCastShadows(false);
	groundEntity2->setMaterialName("Examples/WaterStream");
	//////////////////////////////////////////////////////////////////////////////////////////////////////////
}

void GameMgr::createCeiling()
{
	Ogre::MovablePlane plane(Ogre::Vector3::UNIT_Y, 50);

	// Create Ceiling ///////////////////////////////////////////////////////////////////////////////////////
	Ogre::MeshManager::getSingleton().createPlane(
	    "ceiling",
	    Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
		plane,
		4000, 3400, 20, 20,
	    true,
	    1, 5, 5,
	    Ogre::Vector3::UNIT_Z);
	//////////////////////////////////////////////////////////////////////////////////////////////////////////

	// Create Ceiling Entity //////////////////////////////////////////////////////////////////////////////////
	Ogre::Entity* ceiling = engine->gfxMgr->ogreSceneManager->createEntity("ceiling");
	engine->gfxMgr->ogreSceneManager->getRootSceneNode()->createChildSceneNode()->attachObject(ceiling);
	ceiling->setCastShadows(false);
	ceiling->setMaterialName("Examples/Rockwall");
}

void GameMgr::createSky(){

	engine->gfxMgr->ogreSceneManager->setSkyBox(true, "Examples/SpaceSkyBox");

}

void GameMgr::loadLevel(std::string levelFilename)
{
	// Load the environment, objects, and characters
	this->loadEnvironment(levelFilename);
	this->setupEnvironment();
	this->loadObjects();
	this->loadCharacters();
}

void GameMgr::loadEnvironment(std::string levelFilename)
{
	// Variables
	std::ifstream fin;
	int x, z;
	float x_offset, y_offset, z_offset;
	float scale, orientation;
	std::string groundMaterial, objectMesh, characterMesh;
	std::string buffer;
	char objectChar;

	// Open File
	fin.open(levelFilename);

	// Check for bad file
	if(!fin.is_open())
	{
		std::cerr << "ERROR, FILE CANNOT BE OPENED" << std::endl;
		return;
	}

	// First block is world dimensions and material name
	fin >> x >> z;
	fin >> groundMaterial;

	// TESTING FILE READ ////////////////////////////////////////////
	std::cerr << "Ground Dimensions: " << x << " x " << z << std::endl;
	std::cerr << "Ground Material: " << groundMaterial << std::endl;
	/////////////////////////////////////////////////////////////////

	// Create floor mesh with read in dimensions
	createGround( x, z, groundMaterial);

	// Create Ceiling
	// createCeiling(); DEBUG THIS LATER

	// Second block reads in location of you and enemies
	// Check for Objects line
	fin >> buffer;

	if( buffer != "Objects" )
	{
		std::cerr << "FILE NOT FORMATTED CORRECTLY" << std::endl;
	}

	// Read Objects and positions
	fin >> objectChar >> objectMesh;
	fin >> x_offset >> y_offset >> z_offset;
	fin >> orientation >> scale;

	// Testing Second Box Readin ///////////////////////////////////
	std::cerr << "Objects" << std::endl;
	std::cerr << objectChar << " " << objectMesh << std::endl;
	std::cerr << "Located at: " << x_offset << ", " << y_offset << ", " << z_offset << std::endl;
	std::cerr << "Scaled at: " << orientation << " " << scale << std::endl;
	///////////////////////////////////////////////////////////////

	// Check for Characters line /////////////////////////////////////////////////////////////////
	fin >> buffer;

	if( buffer != "Characters" )
	{
		std::cerr << "FILE NOT FORMATTED CORRECTLY" << std::endl;
	}

	// Read in Characters
	fin >> objectChar >> characterMesh;
	fin >> x_offset >> y_offset >> z_offset;
	fin >> orientation >> scale;

	// Testing Third Box Readin ///////////////////////////////////
	std::cerr << "Characters" << std::endl;
	std::cerr << objectChar << " " << characterMesh << std::endl;
	std::cerr << "Located at: " << x_offset << ", " << y_offset << ", " << z_offset << std::endl;
	std::cerr << "Scaled at: " << orientation << " " << scale << std::endl;
	///////////////////////////////////////////////////////////////

	// Read the World Placement //////////////////////////////////////////////////////////////////
	char c;

	// Start to see if world is in file
	fin >> buffer;

	if( buffer != "World" )
	{
		std::cerr << "FILE NOT FORMATTED CORRECTLY" << std::endl;
	}

	// Pre Conditions for World setup
	Ogre::Vector3 wallPosition;
	wallPosition = Ogre::Vector3(-1850, 50, 1200);

	Ogre::Vector3 archPosition;
	archPosition = Ogre::Vector3(0, 0, 0);

	Ogre::Vector3 enemyPosition;
	enemyPosition = Ogre::Vector3(-1200, 0, 1000);

	/*
	Ogre::ManualObject test;
	test.convertToMesh(objectMesh, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
	*/

	// Loop through map dimensions
	for( int row = 0; row < ROW_SIZE; row++ )
	{
		for( int col = 0; col < COL_SIZE; col++ )
		{
			fin >> c;
			std::cerr << c << std::endl;

			// Check for walls (Not player or enemy nodes)
			if( c == 'W' )
			{
				std::cerr << "Creating Wall" << std::endl;

				engine->entityMgr->CreateEntity(EntityType::WALL, wallPosition, 0);
				//engine->entityMgr->

				// Create a Wall
				/*
				Ogre::Entity* wallEntity = engine->gfxMgr->ogreSceneManager->createEntity(getNewName(), objectMesh);
				wallEntity->setMaterialName("Examples/RustySteel");
				engine->gfxMgr->wallNode = engine->gfxMgr->ogreSceneManager->getRootSceneNode()->createChildSceneNode(wallPosition);
				engine->gfxMgr->wallNode->attachObject(wallEntity);
				*/

				// Set Scale and position
				//engine->gfxMgr->ogreSceneManager->getRootSceneNode()->setScale(0.1f, 1.0f, 0.1f);
				//engine->gfxMgr->ogreSceneManager->getRootSceneNode()->setPosition(wallPosition);

				// Check wall position to prevent going outside of map
				if( wallPosition.x < 1800 ||
					wallPosition.x > -1800 ||
					wallPosition.z > -3000 ||
					wallPosition.z < 3000 )
				{
					// reset position
					//wallPosition.x = 0;
					//wallPosition.z = 0;

					// Increment Positions to prevent overlap from reset
					wallPosition.x += 25;
					//wallPosition.z += 25;
				}

				//wallPosition.z += 50;

				// Set blocked area
			}

			// Check for Arch
			else if( c == 'A' )
			{
				std::cerr << "Spawning Arch" << std::endl;
				engine->entityMgr->CreateEntity(EntityType::ARCH, archPosition, 0);
				archPosition.x += 50;

			}

			else if( c == 'C' )
			{
				// Spawn Enemy
				std::cerr << "Spawning Enemy" << std::endl;

				loadCharacters();
/*
				// Create Test Enemy
				Ogre::Entity* enemyEntity = engine->gfxMgr->ogreSceneManager->createEntity(getNewName(), characterMesh);
				// enemyEntity->setMaterialName("Examples/RustySteel");

				engine->gfxMgr->ogreSceneManager->getRootSceneNode()->createChildSceneNode(enemyPosition)->attachObject(enemyEntity);

				// Set Scale and position
				engine->gfxMgr->ogreSceneManager->getRootSceneNode()->setScale(0.1f, 0.02f, 0.1f);
				//engine->gfxMgr->ogreSceneManager->getRootSceneNode()->setPosition(position);

				enemyPosition.x += 10; // Increment Positions to prevent overlap
				//enemyPosition.z += 50;
*/
			}
		}
	}

	// Create the Entities

	// Create Skybox for the hell of it
	createSky();
}

void GameMgr::setupEnvironment()
{
	//We know graphicsMgr is ready and initialized
	engine->gfxMgr->ogreSceneManager->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));
	Ogre::Light* light = engine->gfxMgr->ogreSceneManager->createLight("MainLight");
	light->setType(Ogre::Light::LT_POINT);
	light->setPosition(100.0, 800.0, 100.0);
	light->setDiffuseColour(Ogre::ColourValue::White);
	light->setSpecularColour(Ogre::ColourValue::White);
}

void GameMgr::loadObjects()
{

}

void GameMgr::loadCharacters()
{
	//Creating the entities
	engine->entityMgr->CreateEntity(EntityType::HEARNO, Ogre::Vector3(0, 10, -1000), 0);
	engine->entityMgr->CreateEntity(EntityType::SEENO, Ogre::Vector3(500, 0, -500), Ogre::Math::HALF_PI / 2);
	engine->entityMgr->CreateEntity(EntityType::SPEAKNO, Ogre::Vector3(-500, 20, -500), Ogre::Math::HALF_PI / -2);

}

std::string GameMgr:: getNewName()
{
	static int count = 0;

	std::string s;
	std::stringstream out;
	out << count ++;
	s = out.str();

	return "object_" + s;
}

<|endoftext|>


<commit_before>#define PGDLLIMPORT "C"

#include <cstdlib>

#include "postgres.h"
#include "funcapi.h"

#include "access/extprotocol.h"
#include "catalog/pg_proc.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "fmgr.h"

#include "S3ExtWrapper.h"
#include "S3Common.h"
#include "S3Log.h"
#include "utils.h"

#include "gps3ext.h"
#include "gps3conf.h"

#include <signal.h>
#include <pthread.h>
#include <openssl/err.h>

/* Do the module magic dance */

PG_MODULE_MAGIC;
PG_FUNCTION_INFO_V1(s3_export);
PG_FUNCTION_INFO_V1(s3_import);
PG_FUNCTION_INFO_V1(s3_validate_urls);

extern "C" {
Datum s3_export(PG_FUNCTION_ARGS);
Datum s3_import(PG_FUNCTION_ARGS);
Datum s3_validate_urls(PG_FUNCTION_ARGS);
}

#define MUTEX_TYPE pthread_mutex_t
#define MUTEX_SETUP(x) pthread_mutex_init(&(x), NULL)
#define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x))
#define MUTEX_LOCK(x) pthread_mutex_lock(&(x))
#define MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x))
#define THREAD_ID pthread_self()

/* This array will store all of the mutexes available to OpenSSL. */
static MUTEX_TYPE *mutex_buf = NULL;

static void locking_function(int mode, int n, const char *file, int line) {
    if (mode & CRYPTO_LOCK)
        MUTEX_LOCK(mutex_buf[n]);
    else
        MUTEX_UNLOCK(mutex_buf[n]);
}

static unsigned long id_function(void) { return ((unsigned long)THREAD_ID); }

int thread_setup(void) {
    int i;

    mutex_buf =
        (pthread_mutex_t *)palloc(CRYPTO_num_locks() * sizeof(MUTEX_TYPE));
    if (!mutex_buf) return 0;
    for (i = 0; i < CRYPTO_num_locks(); i++) MUTEX_SETUP(mutex_buf[i]);
    CRYPTO_set_id_callback(id_function);
    CRYPTO_set_locking_callback(locking_function);
    return 1;
}

int thread_cleanup(void) {
    int i;

    if (!mutex_buf) return 0;
    CRYPTO_set_id_callback(NULL);
    CRYPTO_set_locking_callback(NULL);
    for (i = 0; i < CRYPTO_num_locks(); i++) MUTEX_CLEANUP(mutex_buf[i]);
    pfree(mutex_buf);
    mutex_buf = NULL;
    return 1;
}

/*
 * Import data into GPDB.
 * invoked by GPDB, be careful with C++ exceptions.
 */
Datum s3_import(PG_FUNCTION_ARGS) {
    S3ExtBase *myData;
    char *data;
    int data_len;
    size_t nread = 0;

    /* Must be called via the external table format manager */
    if (!CALLED_AS_EXTPROTOCOL(fcinfo))
        elog(ERROR,
             "extprotocol_import: not called by external protocol manager");

    /* Get our internal description of the protocol */
    myData = (S3ExtBase *)EXTPROTOCOL_GET_USER_CTX(fcinfo);

    if (EXTPROTOCOL_IS_LAST_CALL(fcinfo)) {
        if (myData) {
            thread_cleanup();
            try {
                if (!myData->Destroy()) {
                    ereport(ERROR,
                            (0, errmsg("Failed to cleanup S3 extention")));
                }
            } catch (...) {
                ereport(ERROR, (0, errmsg("Failed to cleanup S3 extention")));
            }
            delete myData;
        }
        PG_RETURN_INT32(0);
    }

    if (myData == NULL) {
        /* first call. do any desired init */
        curl_global_init(CURL_GLOBAL_ALL);
        thread_setup();

        const char *p_name = "s3";
        char *url_with_options = EXTPROTOCOL_GET_URL(fcinfo);

        // clean C func, no exception risk here
        char *url = truncate_options(url_with_options);

        // clean C func, no exception risk here
        char *config_path = get_opt_s3(url_with_options, "config");
        if (!config_path) {
            // no config path in url, use default value
            // data_folder/gpseg0/s3/s3.conf
            config_path = strdup("s3/s3.conf");
        }

        bool result = 0;
        try {
            result = InitConfig(config_path, "");
        } catch (...) {
            result = 0;
        }
        if (!result) {
            free(config_path);
            ereport(ERROR, (0, errmsg("Can't find config file, please check")));
        } else {
            try {
                ClearConfig();
            } catch (...) {
            }
            free(config_path);
        }

        try {
            InitLog();
        } catch (...) {
        }

        if (s3ext_accessid == "") {
            ereport(ERROR, (0, errmsg("ERROR: access id is empty")));
        }

        if (s3ext_secret == "") {
            ereport(ERROR, (0, errmsg("ERROR: secret is empty")));
        }

        if ((s3ext_segnum == -1) || (s3ext_segid == -1)) {
            ereport(ERROR, (0, errmsg("ERROR: segment id is invalid")));
        }

        try {
            myData = CreateExtWrapper(url);

            if (!myData ||
                !myData->Init(s3ext_segid, s3ext_segnum, s3ext_chunksize)) {
                if (myData) delete myData;
                ereport(ERROR,
                        (0, errmsg("Failed to init S3 extension, segid = "
                                   "%d, segnum = %d, please check your "
                                   "configurations and net connection",
                                   s3ext_segid, s3ext_segnum)));
            }
        } catch (...) {
            if (myData) delete myData;
            ereport(ERROR, (0, errmsg("Failed to init S3 extension, segid = "
                                      "%d, segnum = %d, please check your "
                                      "configurations and net connection",
                                      s3ext_segid, s3ext_segnum)));
        }

        EXTPROTOCOL_SET_USER_CTX(fcinfo, myData);

        free(url);
    }

    /* =======================================================================
     *                            DO THE IMPORT
     * =======================================================================
     */

    data = EXTPROTOCOL_GET_DATABUF(fcinfo);
    data_len = EXTPROTOCOL_GET_DATALEN(fcinfo);
    uint64_t readlen = 0;
    if (data_len > 0) {
        readlen = data_len;
        try {
            if (!myData->TransferData(data, readlen)) {
                ereport(ERROR, (0, errmsg("s3_import: could not read data")));
            }
            nread = (size_t)readlen;
        } catch (...) {
            ereport(ERROR, (0, errmsg("s3_import: could not read data")));
        }
        // S3DEBUG("read %d data from S3", nread);
    }

    PG_RETURN_INT32((int)nread);
}

/*
 * Export data out of GPDB.
 * invoked by GPDB, be careful with C++ exceptions.
 */
Datum s3_export(PG_FUNCTION_ARGS) { PG_RETURN_INT32(0); }

Datum s3_validate_urls(PG_FUNCTION_ARGS) {
    int nurls;
    int i;
    ValidatorDirection direction;
    PG_RETURN_VOID();
}
<commit_msg>Revert "catch any exceptions thrown by C++ functions"<commit_after>#define PGDLLIMPORT "C"

#include <cstdlib>

#include "postgres.h"
#include "funcapi.h"

#include "access/extprotocol.h"
#include "catalog/pg_proc.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "fmgr.h"

#include "S3ExtWrapper.h"
#include "S3Common.h"
#include "S3Log.h"
#include "utils.h"

#include "gps3ext.h"
#include "gps3conf.h"

#include <signal.h>
#include <pthread.h>
#include <openssl/err.h>

/* Do the module magic dance */

PG_MODULE_MAGIC;
PG_FUNCTION_INFO_V1(s3_export);
PG_FUNCTION_INFO_V1(s3_import);
PG_FUNCTION_INFO_V1(s3_validate_urls);

extern "C" {
Datum s3_export(PG_FUNCTION_ARGS);
Datum s3_import(PG_FUNCTION_ARGS);
Datum s3_validate_urls(PG_FUNCTION_ARGS);
}

#define MUTEX_TYPE pthread_mutex_t
#define MUTEX_SETUP(x) pthread_mutex_init(&(x), NULL)
#define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x))
#define MUTEX_LOCK(x) pthread_mutex_lock(&(x))
#define MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x))
#define THREAD_ID pthread_self()

/* This array will store all of the mutexes available to OpenSSL. */
static MUTEX_TYPE *mutex_buf = NULL;

static void locking_function(int mode, int n, const char *file, int line) {
    if (mode & CRYPTO_LOCK)
        MUTEX_LOCK(mutex_buf[n]);
    else
        MUTEX_UNLOCK(mutex_buf[n]);
}

static unsigned long id_function(void) { return ((unsigned long)THREAD_ID); }

int thread_setup(void) {
    int i;

    mutex_buf =
        (pthread_mutex_t *)palloc(CRYPTO_num_locks() * sizeof(MUTEX_TYPE));
    if (!mutex_buf) return 0;
    for (i = 0; i < CRYPTO_num_locks(); i++) MUTEX_SETUP(mutex_buf[i]);
    CRYPTO_set_id_callback(id_function);
    CRYPTO_set_locking_callback(locking_function);
    return 1;
}

int thread_cleanup(void) {
    int i;

    if (!mutex_buf) return 0;
    CRYPTO_set_id_callback(NULL);
    CRYPTO_set_locking_callback(NULL);
    for (i = 0; i < CRYPTO_num_locks(); i++) MUTEX_CLEANUP(mutex_buf[i]);
    pfree(mutex_buf);
    mutex_buf = NULL;
    return 1;
}

/*
 * Import data into GPDB.
 */
Datum s3_import(PG_FUNCTION_ARGS) {
    S3ExtBase *myData;
    char *data;
    int data_len;
    size_t nread = 0;

    /* Must be called via the external table format manager */
    if (!CALLED_AS_EXTPROTOCOL(fcinfo))
        elog(ERROR,
             "extprotocol_import: not called by external protocol manager");

    /* Get our internal description of the protocol */
    myData = (S3ExtBase *)EXTPROTOCOL_GET_USER_CTX(fcinfo);

    if (EXTPROTOCOL_IS_LAST_CALL(fcinfo)) {
        if (myData) {
            thread_cleanup();
            if (!myData->Destroy()) {
                ereport(ERROR, (0, errmsg("Cleanup S3 extention failed")));
            }
            delete myData;
        }
        PG_RETURN_INT32(0);
    }

    if (myData == NULL) {
        /* first call. do any desired init */
        curl_global_init(CURL_GLOBAL_ALL);
        thread_setup();

        const char *p_name = "s3";
        char *url_with_options = EXTPROTOCOL_GET_URL(fcinfo);
        char *url = truncate_options(url_with_options);

        char *config_path = get_opt_s3(url_with_options, "config");
        if (!config_path) {
            // no config path in url, use default value
            // data_folder/gpseg0/s3/s3.conf
            config_path = strdup("s3/s3.conf");
        }

        bool result = InitConfig(config_path, "");
        if (!result) {
            free(config_path);
            ereport(ERROR, (0, errmsg("Can't find config file, please check")));
        } else {
            ClearConfig();
            free(config_path);
        }

        InitLog();

        if (s3ext_accessid == "") {
            ereport(ERROR, (0, errmsg("ERROR: access id is empty")));
        }

        if (s3ext_secret == "") {
            ereport(ERROR, (0, errmsg("ERROR: secret is empty")));
        }

        if ((s3ext_segnum == -1) || (s3ext_segid == -1)) {
            ereport(ERROR, (0, errmsg("ERROR: segment id is invalid")));
        }

        myData = CreateExtWrapper(url);

        if (!myData ||
            !myData->Init(s3ext_segid, s3ext_segnum, s3ext_chunksize)) {
            if (myData) delete myData;
            ereport(ERROR, (0, errmsg("Failed to init S3 extension, segid = "
                                      "%d, segnum = %d, please check your "
                                      "configurations and net connection",
                                      s3ext_segid, s3ext_segnum)));
        }
        /*
                  if(strcasecmp(parsed_url->protocol, p_name) != 0) {
                  elog(ERROR, "internal error: s3prot called with a different
                  protocol
                  (%s)",
                  parsed_url->protocol);
                  }
        */

        EXTPROTOCOL_SET_USER_CTX(fcinfo, myData);

        free(url);
    }

    /* =======================================================================
     *                            DO THE IMPORT
     * =======================================================================
     */

    data = EXTPROTOCOL_GET_DATABUF(fcinfo);
    data_len = EXTPROTOCOL_GET_DATALEN(fcinfo);
    uint64_t readlen = 0;
    if (data_len > 0) {
        readlen = data_len;
        if (!myData->TransferData(data, readlen))
            ereport(ERROR, (0, errmsg("s3_import: could not read data")));
        nread = (size_t)readlen;
        // S3DEBUG("read %d data from S3", nread);
    }

    PG_RETURN_INT32((int)nread);
}

/*
 * Export data out of GPDB.
 */
Datum s3_export(PG_FUNCTION_ARGS) { PG_RETURN_INT32(0); }

Datum s3_validate_urls(PG_FUNCTION_ARGS) {
    int nurls;
    int i;
    ValidatorDirection direction;
    PG_RETURN_VOID();
}
<|endoftext|>


<commit_before>/* This file is part of the Pangolin Project.
 * http://github.com/stevenlovegrove/Pangolin
 *
 * Copyright (c) 2013 Steven Lovegrove
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include <pangolin/handler.h>
#include <pangolin/display_internal.h>
#include <pangolin/view.h>

namespace pangolin
{

// Pointer to context defined in display.cpp
extern __thread PangolinGl* context;

void Handler::Keyboard(View& d, unsigned char key, int x, int y, bool pressed)
{
    View* child = d.FindChild(x,y);
    if( child)
    {
        context->activeDisplay = child;
        if( child->handler)
            child->handler->Keyboard(*child,key,x,y,pressed);
    }
}

void Handler::Mouse(View& d, MouseButton button, int x, int y, bool pressed, int button_state)
{
    View* child = d.FindChild(x,y);
    if( child )
    {
        context->activeDisplay = child;
        if( child->handler)
            child->handler->Mouse(*child,button,x,y,pressed,button_state);
    }
}

void Handler::MouseMotion(View& d, int x, int y, int button_state)
{
    View* child = d.FindChild(x,y);
    if( child )
    {
        context->activeDisplay = child;
        if( child->handler)
            child->handler->MouseMotion(*child,x,y,button_state);
    }
}

void Handler::PassiveMouseMotion(View& d, int x, int y, int button_state)
{
    View* child = d.FindChild(x,y);
    if( child )
    {
        if( child->handler)
            child->handler->PassiveMouseMotion(*child,x,y,button_state);
    }
}

void Handler::Special(View& d, InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4, int button_state)
{
    View* child = d.FindChild(x,y);
    if( child )
    {
        context->activeDisplay = child;
        if( child->handler)
            child->handler->Special(*child,inType, x,y, p1, p2, p3, p4, button_state);
    }
}

void HandlerScroll::Mouse(View& d, MouseButton button, int x, int y, bool pressed, int button_state)
{
    if( button == button_state && (button == MouseWheelUp || button == MouseWheelDown) )
    {
        if( button == MouseWheelUp) d.scroll_offset   -= 1;
        if( button == MouseWheelDown) d.scroll_offset += 1;
        d.scroll_offset = std::max(0, std::min(d.scroll_offset, (int)d.views.size()) );
        d.ResizeChildren();
    }else{
        Handler::Mouse(d,button,x,y,pressed,button_state);
    }
}

void HandlerScroll::Special(View& d, InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4, int button_state)
{
    if( inType == InputSpecialScroll )
    {
        d.scroll_offset -= p2 / abs(p2);
        d.scroll_offset = std::max(0, std::min(d.scroll_offset, (int)d.views.size()) );
        d.ResizeChildren();
    }else{
        Handler::Special(d,inType,x,y,p1,p2,p3,p4,button_state);
    }
}

Handler3D::Handler3D(OpenGlRenderState& cam_state, AxisDirection enforce_up, float trans_scale, float zoom_fraction)
    : cam_state(&cam_state), enforce_up(enforce_up), tf(trans_scale), zf(zoom_fraction), cameraspec(CameraSpecOpenGl), last_z(1.0)
{
    SetZero<3,1>(rot_center);
}

void Handler3D::Keyboard(View&, unsigned char key, int x, int y, bool pressed)
{
    // TODO: hooks for reset / changing mode (perspective / ortho etc)
}

void Handler3D::GetPosNormal(pangolin::View& view, int x, int y, double p[3], double Pw[3], double Pc[3], double n[3], double default_z)
{
    const GLint viewport[4] = {view.v.l,view.v.b,view.v.w,view.v.h};
    const pangolin::OpenGlMatrix proj = cam_state->GetProjectionMatrix();
    const pangolin::OpenGlMatrix mv = cam_state->GetModelViewMatrix();
    //      const pangolin::OpenGlMatrix id = IdentityMatrix();

    glReadBuffer(GL_FRONT);
    const int zl = (hwin*2+1);
    const int zsize = zl*zl;
    GLfloat zs[zsize];
    glReadPixels(x-hwin,y-hwin,zl,zl,GL_DEPTH_COMPONENT,GL_FLOAT,zs);
    GLfloat mindepth = *(std::min_element(zs,zs+zsize));
    if(mindepth == 1) mindepth = default_z;

    p[0] = x; p[1] = y; p[2] = mindepth;
    gluUnProject(x, y, mindepth, mv.m, proj.m, viewport, &Pw[0], &Pw[1], &Pw[2]);
    //      gluUnProject(x, y, mindepth, id.m, proj.m, viewport, &Pc[0], &Pc[1], &Pc[2]);
    LieApplySE34x4vec3(Pc, mv.m, Pw);

    double Pl[3]; double Pr[3]; double Pb[3]; double Pt[3];
    gluUnProject(x-hwin, y, zs[hwin*zl + 0],    mv.m, proj.m, viewport, &Pl[0], &Pl[1], &Pl[2]);
    gluUnProject(x+hwin, y, zs[hwin*zl + zl-1], mv.m, proj.m, viewport, &Pr[0], &Pr[1], &Pr[2]);
    gluUnProject(x, y-hwin, zs[hwin+1],         mv.m, proj.m, viewport, &Pb[0], &Pb[1], &Pb[2]);
    gluUnProject(x, y+hwin, zs[zsize-(hwin+1)], mv.m, proj.m, viewport, &Pt[0], &Pt[1], &Pt[2]);

    //      n = ((Pr-Pl).cross(Pt-Pb)).normalized();
    double PrmPl[3]; double PtmPb[3];
    MatSub<3,1>(PrmPl,Pr,Pl);
    MatSub<3,1>(PtmPb,Pt,Pb);
    CrossProduct(n, PrmPl, PtmPb);
    Normalise<3>(n);
}

void Handler3D::Mouse(View& display, MouseButton button, int x, int y, bool pressed, int button_state)
{
    // mouse down
    last_pos[0] = x;
    last_pos[1] = y;

    double T_nc[3*4];
    LieSetIdentity(T_nc);

    if( pressed ) {
        GetPosNormal(display,x,y,p,Pw,Pc,n,last_z);
        if(p[2] < 1.0) {
            last_z = p[2];
            std::copy(Pc,Pc+3,rot_center);
        }

        if( button == MouseWheelUp || button == MouseWheelDown)
        {
            LieSetIdentity(T_nc);
            const double t[] = { 0,0,(button==MouseWheelUp?1:-1)*100*tf};
            LieSetTranslation<>(T_nc,t);
            if( !(button_state & MouseButtonRight) && !(rot_center[0]==0 && rot_center[1]==0 && rot_center[2]==0) )
            {
                LieSetTranslation<>(T_nc,rot_center);
                MatMul<3,1>(T_nc+(3*3),(button==MouseWheelUp?-1.0:1.0) * zf);
            }
            OpenGlMatrix& spec = cam_state->GetModelViewMatrix();
            LieMul4x4bySE3<>(spec.m,T_nc,spec.m);
        }
    }
}

void Handler3D::MouseMotion(View& display, int x, int y, int button_state)
{
    const int delta[2] = {(x-last_pos[0]),(y-last_pos[1])};
    const float mag = delta[0]*delta[0] + delta[1]*delta[1];

    // TODO: convert delta to degrees based of fov
    // TODO: make transformation with respect to cam spec

    if( mag < 50*50 )
    {
        OpenGlMatrix& mv = cam_state->GetModelViewMatrix();
        const GLdouble* up = AxisDirectionVector[enforce_up];
        double T_nc[3*4];
        LieSetIdentity(T_nc);
        bool rotation_changed = false;

        if( button_state == MouseButtonMiddle )
        {
            // Middle Drag: in plane translate
            Rotation<>(T_nc,-delta[1]*0.01, -delta[0]*0.01, 0.0);
        }else if( button_state == MouseButtonLeft )
        {
            // Left Drag: in plane translate
            if( last_z != 1 )
            {
                GLdouble np[3];
                display.GetCamCoordinates(*cam_state,x,y,last_z, np[0], np[1], np[2]);
                const double t[] = { np[0] - rot_center[0], np[1] - rot_center[1], 0};
                LieSetTranslation<>(T_nc,t);
                std::copy(np,np+3,rot_center);
            }else{
                const double t[] = { -10*delta[0]*tf, 10*delta[1]*tf, 0};
                LieSetTranslation<>(T_nc,t);
            }
        }else if( button_state == (MouseButtonLeft | MouseButtonRight) )
        {
            // Left and Right Drag: in plane rotate about object
            //        Rotation<>(T_nc,0.0,0.0, delta[0]*0.01);

            double T_2c[3*4];
            Rotation<>(T_2c,0.0,0.0, delta[0]*0.01);
            double mrotc[3];
            MatMul<3,1>(mrotc, rot_center, -1.0);
            LieApplySO3<>(T_2c+(3*3),T_2c,mrotc);
            double T_n2[3*4];
            LieSetIdentity<>(T_n2);
            LieSetTranslation<>(T_n2,rot_center);
            LieMulSE3(T_nc, T_n2, T_2c );
            rotation_changed = true;
        }else if( button_state == MouseButtonRight)
        {
            // Correct for OpenGL Camera.
            double aboutx = -0.01 * delta[1];
            double abouty =  0.01 * delta[0];

            // Try to correct for different coordinate conventions.
            OpenGlMatrix& pm = cam_state->GetProjectionMatrix();
            abouty *= -pm.m[2*4+3];

            if(enforce_up) {
                // Special case if view direction is parallel to up vector
                const double updotz = mv.m[2]*up[0] + mv.m[6]*up[1] + mv.m[10]*up[2];
                if(updotz > 0.98) aboutx = std::min(aboutx,0.0);
                if(updotz <-0.98) aboutx = std::max(aboutx,0.0);
                // Module rotation around y so we don't spin too fast!
                abouty *= (1-0.6*abs(updotz));
            }

            // Right Drag: object centric rotation
            double T_2c[3*4];
            Rotation<>(T_2c, aboutx, abouty, 0.0);
            double mrotc[3];
            MatMul<3,1>(mrotc, rot_center, -1.0);
            LieApplySO3<>(T_2c+(3*3),T_2c,mrotc);
            double T_n2[3*4];
            LieSetIdentity<>(T_n2);
            LieSetTranslation<>(T_n2,rot_center);
            LieMulSE3(T_nc, T_n2, T_2c );
            rotation_changed = true;
        }

        LieMul4x4bySE3<>(mv.m,T_nc,mv.m);

        if(enforce_up != AxisNone && rotation_changed) {
            EnforceUpT_cw(mv.m, up);
        }
    }

    last_pos[0] = x;
    last_pos[1] = y;
}

void Handler3D::Special(View& display, InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4, int button_state)
{
    if( !(inType == InputSpecialScroll || inType == InputSpecialRotate) )
        return;

    // mouse down
    last_pos[0] = x;
    last_pos[1] = y;

    double T_nc[3*4];
    LieSetIdentity(T_nc);

    GetPosNormal(display,x,y,p,Pw,Pc,n,last_z);
    if(p[2] < 1.0) {
        last_z = p[2];
        std::copy(Pc,Pc+3,rot_center);
    }

    if( inType == InputSpecialScroll ) {
        if(button_state & KeyModifierCmd) {
            const double rx = -p2 / 1000;
            const double ry = -p1 / 1000;

            Rotation<>(T_nc,rx, ry, 0.0);
            OpenGlMatrix& spec = cam_state->GetModelViewMatrix();
            LieMul4x4bySE3<>(spec.m,T_nc,spec.m);
        }else{
            const double scrolly = p2/10;

            LieSetIdentity(T_nc);
            const double t[] = { 0,0, -scrolly*100*tf};
            LieSetTranslation<>(T_nc,t);
            if( !(button_state & MouseButtonRight) && !(rot_center[0]==0 && rot_center[1]==0 && rot_center[2]==0) )
            {
                LieSetTranslation<>(T_nc,rot_center);
                MatMul<3,1>(T_nc+(3*3), -scrolly * zf);
            }
            OpenGlMatrix& spec = cam_state->GetModelViewMatrix();
            LieMul4x4bySE3<>(spec.m,T_nc,spec.m);
        }
    }else if(inType == InputSpecialRotate) {
        const double r = p1 / 20;

        double T_2c[3*4];
        Rotation<>(T_2c,0.0,0.0, r);
        double mrotc[3];
        MatMul<3,1>(mrotc, rot_center, -1.0);
        LieApplySO3<>(T_2c+(3*3),T_2c,mrotc);
        double T_n2[3*4];
        LieSetIdentity<>(T_n2);
        LieSetTranslation<>(T_n2,rot_center);
        LieMulSE3(T_nc, T_n2, T_2c );
        OpenGlMatrix& spec = cam_state->GetModelViewMatrix();
        LieMul4x4bySE3<>(spec.m,T_nc,spec.m);
    }

}

}
<commit_msg>Pull out rotation factor constant.<commit_after>/* This file is part of the Pangolin Project.
 * http://github.com/stevenlovegrove/Pangolin
 *
 * Copyright (c) 2013 Steven Lovegrove
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include <pangolin/handler.h>
#include <pangolin/display_internal.h>
#include <pangolin/view.h>

namespace pangolin
{

// Pointer to context defined in display.cpp
extern __thread PangolinGl* context;

void Handler::Keyboard(View& d, unsigned char key, int x, int y, bool pressed)
{
    View* child = d.FindChild(x,y);
    if( child)
    {
        context->activeDisplay = child;
        if( child->handler)
            child->handler->Keyboard(*child,key,x,y,pressed);
    }
}

void Handler::Mouse(View& d, MouseButton button, int x, int y, bool pressed, int button_state)
{
    View* child = d.FindChild(x,y);
    if( child )
    {
        context->activeDisplay = child;
        if( child->handler)
            child->handler->Mouse(*child,button,x,y,pressed,button_state);
    }
}

void Handler::MouseMotion(View& d, int x, int y, int button_state)
{
    View* child = d.FindChild(x,y);
    if( child )
    {
        context->activeDisplay = child;
        if( child->handler)
            child->handler->MouseMotion(*child,x,y,button_state);
    }
}

void Handler::PassiveMouseMotion(View& d, int x, int y, int button_state)
{
    View* child = d.FindChild(x,y);
    if( child )
    {
        if( child->handler)
            child->handler->PassiveMouseMotion(*child,x,y,button_state);
    }
}

void Handler::Special(View& d, InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4, int button_state)
{
    View* child = d.FindChild(x,y);
    if( child )
    {
        context->activeDisplay = child;
        if( child->handler)
            child->handler->Special(*child,inType, x,y, p1, p2, p3, p4, button_state);
    }
}

void HandlerScroll::Mouse(View& d, MouseButton button, int x, int y, bool pressed, int button_state)
{
    if( button == button_state && (button == MouseWheelUp || button == MouseWheelDown) )
    {
        if( button == MouseWheelUp) d.scroll_offset   -= 1;
        if( button == MouseWheelDown) d.scroll_offset += 1;
        d.scroll_offset = std::max(0, std::min(d.scroll_offset, (int)d.views.size()) );
        d.ResizeChildren();
    }else{
        Handler::Mouse(d,button,x,y,pressed,button_state);
    }
}

void HandlerScroll::Special(View& d, InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4, int button_state)
{
    if( inType == InputSpecialScroll )
    {
        d.scroll_offset -= p2 / abs(p2);
        d.scroll_offset = std::max(0, std::min(d.scroll_offset, (int)d.views.size()) );
        d.ResizeChildren();
    }else{
        Handler::Special(d,inType,x,y,p1,p2,p3,p4,button_state);
    }
}

Handler3D::Handler3D(OpenGlRenderState& cam_state, AxisDirection enforce_up, float trans_scale, float zoom_fraction)
    : cam_state(&cam_state), enforce_up(enforce_up), tf(trans_scale), zf(zoom_fraction), cameraspec(CameraSpecOpenGl), last_z(1.0)
{
    SetZero<3,1>(rot_center);
}

void Handler3D::Keyboard(View&, unsigned char key, int x, int y, bool pressed)
{
    // TODO: hooks for reset / changing mode (perspective / ortho etc)
}

void Handler3D::GetPosNormal(pangolin::View& view, int x, int y, double p[3], double Pw[3], double Pc[3], double n[3], double default_z)
{
    const GLint viewport[4] = {view.v.l,view.v.b,view.v.w,view.v.h};
    const pangolin::OpenGlMatrix proj = cam_state->GetProjectionMatrix();
    const pangolin::OpenGlMatrix mv = cam_state->GetModelViewMatrix();
    //      const pangolin::OpenGlMatrix id = IdentityMatrix();

    glReadBuffer(GL_FRONT);
    const int zl = (hwin*2+1);
    const int zsize = zl*zl;
    GLfloat zs[zsize];
    glReadPixels(x-hwin,y-hwin,zl,zl,GL_DEPTH_COMPONENT,GL_FLOAT,zs);
    GLfloat mindepth = *(std::min_element(zs,zs+zsize));
    if(mindepth == 1) mindepth = default_z;

    p[0] = x; p[1] = y; p[2] = mindepth;
    gluUnProject(x, y, mindepth, mv.m, proj.m, viewport, &Pw[0], &Pw[1], &Pw[2]);
    //      gluUnProject(x, y, mindepth, id.m, proj.m, viewport, &Pc[0], &Pc[1], &Pc[2]);
    LieApplySE34x4vec3(Pc, mv.m, Pw);

    double Pl[3]; double Pr[3]; double Pb[3]; double Pt[3];
    gluUnProject(x-hwin, y, zs[hwin*zl + 0],    mv.m, proj.m, viewport, &Pl[0], &Pl[1], &Pl[2]);
    gluUnProject(x+hwin, y, zs[hwin*zl + zl-1], mv.m, proj.m, viewport, &Pr[0], &Pr[1], &Pr[2]);
    gluUnProject(x, y-hwin, zs[hwin+1],         mv.m, proj.m, viewport, &Pb[0], &Pb[1], &Pb[2]);
    gluUnProject(x, y+hwin, zs[zsize-(hwin+1)], mv.m, proj.m, viewport, &Pt[0], &Pt[1], &Pt[2]);

    //      n = ((Pr-Pl).cross(Pt-Pb)).normalized();
    double PrmPl[3]; double PtmPb[3];
    MatSub<3,1>(PrmPl,Pr,Pl);
    MatSub<3,1>(PtmPb,Pt,Pb);
    CrossProduct(n, PrmPl, PtmPb);
    Normalise<3>(n);
}

void Handler3D::Mouse(View& display, MouseButton button, int x, int y, bool pressed, int button_state)
{
    // mouse down
    last_pos[0] = x;
    last_pos[1] = y;

    double T_nc[3*4];
    LieSetIdentity(T_nc);

    if( pressed ) {
        GetPosNormal(display,x,y,p,Pw,Pc,n,last_z);
        if(p[2] < 1.0) {
            last_z = p[2];
            std::copy(Pc,Pc+3,rot_center);
        }

        if( button == MouseWheelUp || button == MouseWheelDown)
        {
            LieSetIdentity(T_nc);
            const double t[] = { 0,0,(button==MouseWheelUp?1:-1)*100*tf};
            LieSetTranslation<>(T_nc,t);
            if( !(button_state & MouseButtonRight) && !(rot_center[0]==0 && rot_center[1]==0 && rot_center[2]==0) )
            {
                LieSetTranslation<>(T_nc,rot_center);
                MatMul<3,1>(T_nc+(3*3),(button==MouseWheelUp?-1.0:1.0) * zf);
            }
            OpenGlMatrix& spec = cam_state->GetModelViewMatrix();
            LieMul4x4bySE3<>(spec.m,T_nc,spec.m);
        }
    }
}

void Handler3D::MouseMotion(View& display, int x, int y, int button_state)
{
    const double rf = 0.01;
    const int delta[2] = {(x-last_pos[0]),(y-last_pos[1])};
    const float mag = delta[0]*delta[0] + delta[1]*delta[1];

    // TODO: convert delta to degrees based of fov
    // TODO: make transformation with respect to cam spec

    if( mag < 50*50 )
    {
        OpenGlMatrix& mv = cam_state->GetModelViewMatrix();
        const GLdouble* up = AxisDirectionVector[enforce_up];
        double T_nc[3*4];
        LieSetIdentity(T_nc);
        bool rotation_changed = false;

        if( button_state == MouseButtonMiddle )
        {
            // Middle Drag: in plane translate
            Rotation<>(T_nc,-delta[1]*rf, -delta[0]*rf, 0.0);
        }else if( button_state == MouseButtonLeft )
        {
            // Left Drag: in plane translate
            if( last_z != 1 )
            {
                GLdouble np[3];
                display.GetCamCoordinates(*cam_state,x,y,last_z, np[0], np[1], np[2]);
                const double t[] = { np[0] - rot_center[0], np[1] - rot_center[1], 0};
                LieSetTranslation<>(T_nc,t);
                std::copy(np,np+3,rot_center);
            }else{
                const double t[] = { -10*delta[0]*tf, 10*delta[1]*tf, 0};
                LieSetTranslation<>(T_nc,t);
            }
        }else if( button_state == (MouseButtonLeft | MouseButtonRight) )
        {
            // Left and Right Drag: in plane rotate about object
            //        Rotation<>(T_nc,0.0,0.0, delta[0]*0.01);

            double T_2c[3*4];
            Rotation<>(T_2c,0.0,0.0, delta[0]*rf);
            double mrotc[3];
            MatMul<3,1>(mrotc, rot_center, -1.0);
            LieApplySO3<>(T_2c+(3*3),T_2c,mrotc);
            double T_n2[3*4];
            LieSetIdentity<>(T_n2);
            LieSetTranslation<>(T_n2,rot_center);
            LieMulSE3(T_nc, T_n2, T_2c );
            rotation_changed = true;
        }else if( button_state == MouseButtonRight)
        {
            // Correct for OpenGL Camera.
            double aboutx = -rf * delta[1];
            double abouty =  rf * delta[0];

            // Try to correct for different coordinate conventions.
            OpenGlMatrix& pm = cam_state->GetProjectionMatrix();
            abouty *= -pm.m[2*4+3];

            if(enforce_up) {
                // Special case if view direction is parallel to up vector
                const double updotz = mv.m[2]*up[0] + mv.m[6]*up[1] + mv.m[10]*up[2];
                if(updotz > 0.98) aboutx = std::min(aboutx,0.0);
                if(updotz <-0.98) aboutx = std::max(aboutx,0.0);
                // Module rotation around y so we don't spin too fast!
                abouty *= (1-0.6*abs(updotz));
            }

            // Right Drag: object centric rotation
            double T_2c[3*4];
            Rotation<>(T_2c, aboutx, abouty, 0.0);
            double mrotc[3];
            MatMul<3,1>(mrotc, rot_center, -1.0);
            LieApplySO3<>(T_2c+(3*3),T_2c,mrotc);
            double T_n2[3*4];
            LieSetIdentity<>(T_n2);
            LieSetTranslation<>(T_n2,rot_center);
            LieMulSE3(T_nc, T_n2, T_2c );
            rotation_changed = true;
        }

        LieMul4x4bySE3<>(mv.m,T_nc,mv.m);

        if(enforce_up != AxisNone && rotation_changed) {
            EnforceUpT_cw(mv.m, up);
        }
    }

    last_pos[0] = x;
    last_pos[1] = y;
}

void Handler3D::Special(View& display, InputSpecial inType, float x, float y, float p1, float p2, float p3, float p4, int button_state)
{
    if( !(inType == InputSpecialScroll || inType == InputSpecialRotate) )
        return;

    // mouse down
    last_pos[0] = x;
    last_pos[1] = y;

    double T_nc[3*4];
    LieSetIdentity(T_nc);

    GetPosNormal(display,x,y,p,Pw,Pc,n,last_z);
    if(p[2] < 1.0) {
        last_z = p[2];
        std::copy(Pc,Pc+3,rot_center);
    }

    if( inType == InputSpecialScroll ) {
        if(button_state & KeyModifierCmd) {
            const double rx = -p2 / 1000;
            const double ry = -p1 / 1000;

            Rotation<>(T_nc,rx, ry, 0.0);
            OpenGlMatrix& spec = cam_state->GetModelViewMatrix();
            LieMul4x4bySE3<>(spec.m,T_nc,spec.m);
        }else{
            const double scrolly = p2/10;

            LieSetIdentity(T_nc);
            const double t[] = { 0,0, -scrolly*100*tf};
            LieSetTranslation<>(T_nc,t);
            if( !(button_state & MouseButtonRight) && !(rot_center[0]==0 && rot_center[1]==0 && rot_center[2]==0) )
            {
                LieSetTranslation<>(T_nc,rot_center);
                MatMul<3,1>(T_nc+(3*3), -scrolly * zf);
            }
            OpenGlMatrix& spec = cam_state->GetModelViewMatrix();
            LieMul4x4bySE3<>(spec.m,T_nc,spec.m);
        }
    }else if(inType == InputSpecialRotate) {
        const double r = p1 / 20;

        double T_2c[3*4];
        Rotation<>(T_2c,0.0,0.0, r);
        double mrotc[3];
        MatMul<3,1>(mrotc, rot_center, -1.0);
        LieApplySO3<>(T_2c+(3*3),T_2c,mrotc);
        double T_n2[3*4];
        LieSetIdentity<>(T_n2);
        LieSetTranslation<>(T_n2,rot_center);
        LieMulSE3(T_nc, T_n2, T_2c );
        OpenGlMatrix& spec = cam_state->GetModelViewMatrix();
        LieMul4x4bySE3<>(spec.m,T_nc,spec.m);
    }

}

}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011-2013 libwallet developers (see AUTHORS)
 *
 * This file is part of libwallet.
 *
 * libwallet is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
#include <wallet/hd_keys.hpp>

#include <algorithm>
#include <openssl/bn.h>
#include <openssl/hmac.h>
#include <bitcoin/format.hpp>
#include <bitcoin/utility/base58.hpp>
#include <bitcoin/utility/ripemd.hpp>
#include <bitcoin/utility/sha256.hpp>

namespace libwallet {

template<typename T, void destroy(T* p)>
class auto_free
{
public:
    auto_free(T* p)
      : ptr(p)
    {}
    ~auto_free()
    {
        destroy(ptr);
    }
    operator T*()
    {
        return ptr;
    }
    T* ptr;
};
typedef auto_free<BIGNUM, BN_free> ssl_bignum;
typedef auto_free<BN_CTX, BN_CTX_free> ssl_bn_ctx;
typedef auto_free<EC_GROUP, EC_GROUP_free> ssl_ec_group;
typedef auto_free<EC_POINT, EC_POINT_free> ssl_ec_point;

constexpr uint32_t mainnet_private_prefix = 0x0488ADE4;
constexpr uint32_t mainnet_public_prefix  = 0x0488B21E;
constexpr uint32_t testnet_private_prefix = 0x04358394;
constexpr uint32_t testnet_public_prefix  = 0x043587CF;

secret_parameter secp256k1_n{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
                              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
                              0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
                              0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41}};

static data_chunk secret_to_public_key(const secret_parameter& secret)
{
    elliptic_curve_key key;
    key.set_secret(secret, true);
    return key.public_key();
}

/**
 * Corresponds to a split HMAC-SHA256 result, as used in BIP 32.
 */
struct split_hmac {
    std::array<uint8_t, 32> IL;
    std::array<uint8_t, 32> IR;
};
static split_hmac hmac_sha512(const void* key, int key_len, const data_chunk& data)
{
    std::array<uint8_t, 64> hmac;
    HMAC(EVP_sha512(), key, key_len, data.data(), data.size(),
        hmac.data(), nullptr);
    split_hmac I;
    std::copy(hmac.begin(), hmac.begin() + 32, I.IL.begin());
    std::copy(hmac.begin() + 32, hmac.end(), I.IR.begin());
    return I;
}

static ser32_type ser32(uint32_t i)
{
    ser32_type out;
    out[0] = 0xff & (i >> 24);
    out[1] = 0xff & (i >> 16);
    out[2] = 0xff & (i >> 8);
    out[3] = 0xff & i;
    return out;
}

hd_public_key::hd_public_key()
  : valid_(false)
{
}

hd_public_key::hd_public_key(const data_chunk& public_key,
    const chain_code_type& chain_code, hd_key_lineage lineage)
  : valid_(true), K_(public_key), c_(chain_code), lineage_(lineage)
{
}

bool hd_public_key::valid() const
{
    return valid_;
}

const data_chunk& hd_public_key::public_key() const
{
    return K_;
}

const chain_code_type& hd_public_key::chain_code() const
{
    return c_;
}

const hd_key_lineage& hd_public_key::lineage() const
{
    return lineage_;
}

std::string hd_public_key::serialize() const
{
    data_chunk data;
    data.reserve(4 + 1 + 4 + 4 + 32 + 33 + 4);

    extend_data(data, ser32(lineage_.testnet ?
        testnet_public_prefix : mainnet_public_prefix));
    data.push_back(lineage_.depth);
    extend_data(data, lineage_.parent_fingerprint);
    extend_data(data, ser32(lineage_.child_number));
    extend_data(data, c_);
    extend_data(data, K_);

    extend_data(data, uncast_type(generate_sha256_checksum(data)));
    return encode_base58(data);
}

ser32_type hd_public_key::fingerprint() const
{
    short_hash md = generate_ripemd_hash(K_);
    return ser32_type{md[0], md[1], md[2], md[3]};
}

payment_address hd_public_key::address() const
{
    payment_address address;
    set_public_key(address, K_);
    return address;
}

hd_public_key hd_public_key::generate_public_key(uint32_t i)
{
    if (!valid_)
        return hd_private_key();
    if (first_hardened_key <= i)
        return hd_public_key();

    data_chunk data;
    data.reserve(33 + 4);
    extend_data(data, K_);
    extend_data(data, ser32(i));
    auto I = hmac_sha512(c_.data(), c_.size(), data);

    //The returned child key Ki is point(parse256(IL)) + Kpar.
    ssl_ec_group group = EC_GROUP_new_by_curve_name(NID_secp256k1);
    if (!group)
        return hd_public_key();
    ssl_bn_ctx ctx = BN_CTX_new();
    ssl_ec_point Ki = EC_POINT_new(group);
    ssl_ec_point Kpar = EC_POINT_new(group);
    ssl_ec_point IL = EC_POINT_new(group);
    ssl_bignum il = BN_bin2bn(I.IL.data(), I.IL.size(), nullptr);
    ssl_bignum n = BN_bin2bn(secp256k1_n.data(), secp256k1_n.size(), nullptr);
    if (!ctx || !Ki || !Kpar || !IL || !il || !n)
        return hd_public_key();
    if (!EC_POINT_oct2point(group, Kpar, K_.data(), K_.size(), ctx))
        return hd_public_key();
    if (!EC_POINT_mul(group, IL, il, nullptr, nullptr, ctx))
        return hd_public_key();
    if (!EC_POINT_add(group, Ki, IL, Kpar, ctx))
        return hd_public_key();

    // The key is invalid if parse256(IL) >= n or Ki is at infinity:
    if (0 <= BN_cmp(il, n) || EC_POINT_is_at_infinity(group, Ki))
        return hd_private_key();

    size_t Ki_size = EC_POINT_point2oct(group, Ki,
        POINT_CONVERSION_COMPRESSED, NULL, 0, ctx);
    data_chunk out(Ki_size);
    if (!EC_POINT_point2oct(group, Ki,
        POINT_CONVERSION_COMPRESSED, out.data(), out.size(), ctx))
        return hd_public_key();

    return hd_public_key(out, I.IR, hd_key_lineage{lineage_.testnet,
        static_cast<uint8_t>(lineage_.depth + 1), fingerprint(), i});
}

hd_private_key::hd_private_key()
  : hd_public_key()
{
}

hd_private_key::hd_private_key(const secret_parameter& private_key,
    const chain_code_type& chain_code, hd_key_lineage lineage)
  : hd_public_key(secret_to_public_key(private_key), chain_code, lineage),
    k_(private_key)
{
}

hd_private_key::hd_private_key(const data_chunk& seed, bool testnet)
  : hd_public_key()
{
    const char hmac_key[] = "Bitcoin seed";
    split_hmac I = hmac_sha512(hmac_key, strlen(hmac_key), seed);

    // The key is invalid if parse256(IL) >= n or 0:
    ssl_bignum il = BN_bin2bn(I.IL.data(), I.IL.size(), nullptr);
    ssl_bignum n = BN_bin2bn(secp256k1_n.data(), secp256k1_n.size(), nullptr);
    if (0 <= BN_cmp(il, n) || BN_is_zero(il.ptr))
        return;

    *this = hd_private_key(I.IL, I.IR, hd_key_lineage{testnet, 0, {0}, 0});
}

const secret_parameter& hd_private_key::private_key() const
{
    return k_;
}

std::string hd_private_key::serialize() const
{
    data_chunk data;
    data.reserve(4 + 1 + 4 + 4 + 32 + 33 + 4);

    extend_data(data, ser32(lineage_.testnet ?
        testnet_private_prefix : mainnet_private_prefix));
    data.push_back(lineage_.depth);
    extend_data(data, lineage_.parent_fingerprint);
    extend_data(data, ser32(lineage_.child_number));
    extend_data(data, c_);
    data.push_back(0x00);
    extend_data(data, k_);

    extend_data(data, uncast_type(generate_sha256_checksum(data)));
    return encode_base58(data);
}

hd_private_key hd_private_key::generate_private_key(uint32_t i)
{
    if (!valid_)
        return hd_private_key();

    data_chunk data;
    data.reserve(33 + 4);
    if (first_hardened_key <= i)
    {
        data.push_back(0x00);
        extend_data(data, k_);
        extend_data(data, ser32(i));
    }
    else
    {
        extend_data(data, K_);
        extend_data(data, ser32(i));
    }
    auto I = hmac_sha512(c_.data(), c_.size(), data);

    // The child key ki is (parse256(IL) + kpar) mod n:
    ssl_bn_ctx ctx = BN_CTX_new();
    ssl_bignum ki = BN_new();
    ssl_bignum kpar = BN_bin2bn(k_.data(), k_.size(), nullptr);
    ssl_bignum il = BN_bin2bn(I.IL.data(), I.IL.size(), nullptr);
    ssl_bignum n = BN_bin2bn(secp256k1_n.data(), secp256k1_n.size(), nullptr);
    if (!ctx || !ki || !kpar || !il || !n)
        return hd_private_key();
    if (!BN_mod_add(ki, kpar, il, n, ctx))
        return hd_private_key();

    // The key is invalid if parse256(IL) >= n or ki == 0:
    if (0 <= BN_cmp(il, n) || BN_is_zero(ki.ptr))
        return hd_private_key();

    secret_parameter out{{0}};
    int ki_size = BN_num_bytes(ki);
    if (ki_size != BN_bn2bin(ki, &out[out.size() - ki_size]))
        return hd_private_key();

    return hd_private_key(out, I.IR, hd_key_lineage{lineage_.testnet,
        static_cast<uint8_t>(lineage_.depth + 1), fingerprint(), i});
}

hd_public_key hd_private_key::generate_public_key(uint32_t i)
{
    return generate_private_key(i);
}

} // libwallet

<commit_msg>Fix C++11 language violations<commit_after>/*
 * Copyright (c) 2011-2013 libwallet developers (see AUTHORS)
 *
 * This file is part of libwallet.
 *
 * libwallet is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
#include <wallet/hd_keys.hpp>

#include <algorithm>
#include <openssl/bn.h>
#include <openssl/hmac.h>
#include <bitcoin/format.hpp>
#include <bitcoin/utility/base58.hpp>
#include <bitcoin/utility/ripemd.hpp>
#include <bitcoin/utility/sha256.hpp>

namespace libwallet {

template<typename T, void destroy(T* p)>
class auto_free
{
public:
    auto_free(T* p)
      : ptr(p)
    {}
    ~auto_free()
    {
        destroy(ptr);
    }
    operator T*()
    {
        return ptr;
    }
    T* ptr;
};
typedef auto_free<BIGNUM, BN_free> ssl_bignum;
typedef auto_free<BN_CTX, BN_CTX_free> ssl_bn_ctx;
typedef auto_free<EC_GROUP, EC_GROUP_free> ssl_ec_group;
typedef auto_free<EC_POINT, EC_POINT_free> ssl_ec_point;

constexpr uint32_t mainnet_private_prefix = 0x0488ADE4;
constexpr uint32_t mainnet_public_prefix  = 0x0488B21E;
constexpr uint32_t testnet_private_prefix = 0x04358394;
constexpr uint32_t testnet_public_prefix  = 0x043587CF;

secret_parameter secp256k1_n{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
                              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
                              0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
                              0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41}};

static data_chunk secret_to_public_key(const secret_parameter& secret)
{
    elliptic_curve_key key;
    key.set_secret(secret, true);
    return key.public_key();
}

/**
 * Corresponds to a split HMAC-SHA256 result, as used in BIP 32.
 */
struct split_hmac {
    std::array<uint8_t, 32> IL;
    std::array<uint8_t, 32> IR;
};
static split_hmac hmac_sha512(const void* key, int key_len, const data_chunk& data)
{
    std::array<uint8_t, 64> hmac;
    HMAC(EVP_sha512(), key, key_len, data.data(), data.size(),
        hmac.data(), nullptr);
    split_hmac I;
    std::copy(hmac.begin(), hmac.begin() + 32, I.IL.begin());
    std::copy(hmac.begin() + 32, hmac.end(), I.IR.begin());
    return I;
}

static ser32_type ser32(uint32_t i)
{
    ser32_type out;
    out[0] = 0xff & (i >> 24);
    out[1] = 0xff & (i >> 16);
    out[2] = 0xff & (i >> 8);
    out[3] = 0xff & i;
    return out;
}

hd_public_key::hd_public_key()
  : valid_(false)
{
}

hd_public_key::hd_public_key(const data_chunk& public_key,
    const chain_code_type& chain_code, hd_key_lineage lineage)
  : valid_(true), K_(public_key), c_(chain_code), lineage_(lineage)
{
}

bool hd_public_key::valid() const
{
    return valid_;
}

const data_chunk& hd_public_key::public_key() const
{
    return K_;
}

const chain_code_type& hd_public_key::chain_code() const
{
    return c_;
}

const hd_key_lineage& hd_public_key::lineage() const
{
    return lineage_;
}

std::string hd_public_key::serialize() const
{
    data_chunk data;
    data.reserve(4 + 1 + 4 + 4 + 32 + 33 + 4);

    extend_data(data, ser32(lineage_.testnet ?
        testnet_public_prefix : mainnet_public_prefix));
    data.push_back(lineage_.depth);
    extend_data(data, lineage_.parent_fingerprint);
    extend_data(data, ser32(lineage_.child_number));
    extend_data(data, c_);
    extend_data(data, K_);

    extend_data(data, uncast_type(generate_sha256_checksum(data)));
    return encode_base58(data);
}

ser32_type hd_public_key::fingerprint() const
{
    short_hash md = generate_ripemd_hash(K_);
    return ser32_type{{md[0], md[1], md[2], md[3]}};
}

payment_address hd_public_key::address() const
{
    payment_address address;
    set_public_key(address, K_);
    return address;
}

hd_public_key hd_public_key::generate_public_key(uint32_t i)
{
    if (!valid_)
        return hd_private_key();
    if (first_hardened_key <= i)
        return hd_public_key();

    data_chunk data;
    data.reserve(33 + 4);
    extend_data(data, K_);
    extend_data(data, ser32(i));
    auto I = hmac_sha512(c_.data(), c_.size(), data);

    //The returned child key Ki is point(parse256(IL)) + Kpar.
    ssl_ec_group group = EC_GROUP_new_by_curve_name(NID_secp256k1);
    if (!group)
        return hd_public_key();
    ssl_bn_ctx ctx = BN_CTX_new();
    ssl_ec_point Ki = EC_POINT_new(group);
    ssl_ec_point Kpar = EC_POINT_new(group);
    ssl_ec_point IL = EC_POINT_new(group);
    ssl_bignum il = BN_bin2bn(I.IL.data(), I.IL.size(), nullptr);
    ssl_bignum n = BN_bin2bn(secp256k1_n.data(), secp256k1_n.size(), nullptr);
    if (!ctx || !Ki || !Kpar || !IL || !il || !n)
        return hd_public_key();
    if (!EC_POINT_oct2point(group, Kpar, K_.data(), K_.size(), ctx))
        return hd_public_key();
    if (!EC_POINT_mul(group, IL, il, nullptr, nullptr, ctx))
        return hd_public_key();
    if (!EC_POINT_add(group, Ki, IL, Kpar, ctx))
        return hd_public_key();

    // The key is invalid if parse256(IL) >= n or Ki is at infinity:
    if (0 <= BN_cmp(il, n) || EC_POINT_is_at_infinity(group, Ki))
        return hd_private_key();

    size_t Ki_size = EC_POINT_point2oct(group, Ki,
        POINT_CONVERSION_COMPRESSED, NULL, 0, ctx);
    data_chunk out(Ki_size);
    if (!EC_POINT_point2oct(group, Ki,
        POINT_CONVERSION_COMPRESSED, out.data(), out.size(), ctx))
        return hd_public_key();

    return hd_public_key(out, I.IR, hd_key_lineage{lineage_.testnet,
        static_cast<uint8_t>(lineage_.depth + 1), fingerprint(), i});
}

hd_private_key::hd_private_key()
  : hd_public_key()
{
}

hd_private_key::hd_private_key(const secret_parameter& private_key,
    const chain_code_type& chain_code, hd_key_lineage lineage)
  : hd_public_key(secret_to_public_key(private_key), chain_code, lineage),
    k_(private_key)
{
}

hd_private_key::hd_private_key(const data_chunk& seed, bool testnet)
  : hd_public_key()
{
    const char hmac_key[] = "Bitcoin seed";
    split_hmac I = hmac_sha512(hmac_key, strlen(hmac_key), seed);

    // The key is invalid if parse256(IL) >= n or 0:
    ssl_bignum il = BN_bin2bn(I.IL.data(), I.IL.size(), nullptr);
    ssl_bignum n = BN_bin2bn(secp256k1_n.data(), secp256k1_n.size(), nullptr);
    if (0 <= BN_cmp(il, n) || BN_is_zero(il.ptr))
        return;

    *this = hd_private_key(I.IL, I.IR, hd_key_lineage{testnet, 0, {{0}}, 0});
}

const secret_parameter& hd_private_key::private_key() const
{
    return k_;
}

std::string hd_private_key::serialize() const
{
    data_chunk data;
    data.reserve(4 + 1 + 4 + 4 + 32 + 33 + 4);

    extend_data(data, ser32(lineage_.testnet ?
        testnet_private_prefix : mainnet_private_prefix));
    data.push_back(lineage_.depth);
    extend_data(data, lineage_.parent_fingerprint);
    extend_data(data, ser32(lineage_.child_number));
    extend_data(data, c_);
    data.push_back(0x00);
    extend_data(data, k_);

    extend_data(data, uncast_type(generate_sha256_checksum(data)));
    return encode_base58(data);
}

hd_private_key hd_private_key::generate_private_key(uint32_t i)
{
    if (!valid_)
        return hd_private_key();

    data_chunk data;
    data.reserve(33 + 4);
    if (first_hardened_key <= i)
    {
        data.push_back(0x00);
        extend_data(data, k_);
        extend_data(data, ser32(i));
    }
    else
    {
        extend_data(data, K_);
        extend_data(data, ser32(i));
    }
    auto I = hmac_sha512(c_.data(), c_.size(), data);

    // The child key ki is (parse256(IL) + kpar) mod n:
    ssl_bn_ctx ctx = BN_CTX_new();
    ssl_bignum ki = BN_new();
    ssl_bignum kpar = BN_bin2bn(k_.data(), k_.size(), nullptr);
    ssl_bignum il = BN_bin2bn(I.IL.data(), I.IL.size(), nullptr);
    ssl_bignum n = BN_bin2bn(secp256k1_n.data(), secp256k1_n.size(), nullptr);
    if (!ctx || !ki || !kpar || !il || !n)
        return hd_private_key();
    if (!BN_mod_add(ki, kpar, il, n, ctx))
        return hd_private_key();

    // The key is invalid if parse256(IL) >= n or ki == 0:
    if (0 <= BN_cmp(il, n) || BN_is_zero(ki.ptr))
        return hd_private_key();

    secret_parameter out{{0}};
    int ki_size = BN_num_bytes(ki);
    if (ki_size != BN_bn2bin(ki, &out[out.size() - ki_size]))
        return hd_private_key();

    return hd_private_key(out, I.IR, hd_key_lineage{lineage_.testnet,
        static_cast<uint8_t>(lineage_.depth + 1), fingerprint(), i});
}

hd_public_key hd_private_key::generate_public_key(uint32_t i)
{
    return generate_private_key(i);
}

} // libwallet

<|endoftext|>


<commit_before>// Scintilla source code edit control
/** @file LexInno.cxx
 ** Lexer for Inno Setup scripts.
 **/
// Written by Friedrich Vedder <fvedd@t-online.de>, using code from LexOthers.cxx.
// The License.txt file describes the conditions under which this software may be distributed.

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

#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"

#include "WordList.h"
#include "LexAccessor.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

static void ColouriseInnoDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *keywordLists[], Accessor &styler) {
	int state = SCE_INNO_DEFAULT;
	char chPrev;
	char ch = 0;
	char chNext = styler[startPos];
	Sci_Position lengthDoc = startPos + length;
	char *buffer = new char[length];
	Sci_Position bufferCount = 0;
	bool isBOL, isEOL, isWS, isBOLWS = 0;
	bool isCStyleComment = false;

	WordList &sectionKeywords = *keywordLists[0];
	WordList &standardKeywords = *keywordLists[1];
	WordList &parameterKeywords = *keywordLists[2];
	WordList &preprocessorKeywords = *keywordLists[3];
	WordList &pascalKeywords = *keywordLists[4];
	WordList &userKeywords = *keywordLists[5];

	Sci_Position curLine = styler.GetLine(startPos);
	int curLineState = curLine > 0 ? styler.GetLineState(curLine - 1) : 0;
	bool isCode = (curLineState == 1);

	// Go through all provided text segment
	// using the hand-written state machine shown below
	styler.StartAt(startPos);
	styler.StartSegment(startPos);
	for (Sci_Position i = startPos; i < lengthDoc; i++) {
		chPrev = ch;
		ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);

		if (styler.IsLeadByte(ch)) {
			chNext = styler.SafeGetCharAt(i + 2);
			i++;
			continue;
		}

		isBOL = (chPrev == 0) || (chPrev == '\n') || (chPrev == '\r' && ch != '\n');
		isBOLWS = (isBOL) ? 1 : (isBOLWS && (chPrev == ' ' || chPrev == '\t'));
		isEOL = (ch == '\n' || ch == '\r');
		isWS = (ch == ' ' || ch == '\t');

		if ((ch == '\r' && chNext != '\n') || (ch == '\n')) {
			// Remember the line state for future incremental lexing
			curLine = styler.GetLine(i);
			styler.SetLineState(curLine, (isCode ? 1 : 0));
		}

		switch(state) {
			case SCE_INNO_DEFAULT:
				if (!isCode && ch == ';' && isBOLWS) {
					// Start of a comment
					state = SCE_INNO_COMMENT;
				} else if (ch == '[' && isBOLWS) {
					// Start of a section name
					bufferCount = 0;
					state = SCE_INNO_SECTION;
				} else if (ch == '#' && isBOLWS) {
					// Start of a preprocessor directive
					state = SCE_INNO_PREPROC;
				} else if (!isCode && ch == '{' && chNext != '{' && chPrev != '{') {
					// Start of an inline expansion
					state = SCE_INNO_INLINE_EXPANSION;
				} else if (isCode && (ch == '{' || (ch == '(' && chNext == '*'))) {
					// Start of a Pascal comment
					state = SCE_INNO_COMMENT_PASCAL;
					isCStyleComment = false;
				} else if (isCode && ch == '/' && chNext == '/') {
					// Apparently, C-style comments are legal, too
					state = SCE_INNO_COMMENT_PASCAL;
					isCStyleComment = true;
				} else if (ch == '"') {
					// Start of a double-quote string
					state = SCE_INNO_STRING_DOUBLE;
				} else if (ch == '\'') {
					// Start of a single-quote string
					state = SCE_INNO_STRING_SINGLE;
				} else if (IsASCII(ch) && (isalpha(ch) || (ch == '_'))) {
					// Start of an identifier
					bufferCount = 0;
					buffer[bufferCount++] = static_cast<char>(tolower(ch));
					state = SCE_INNO_IDENTIFIER;
				} else {
					// Style it the default style
					styler.ColourTo(i,SCE_INNO_DEFAULT);
				}
				break;

			case SCE_INNO_COMMENT:
				if (isEOL) {
					state = SCE_INNO_DEFAULT;
					styler.ColourTo(i,SCE_INNO_COMMENT);
				}
				break;

			case SCE_INNO_IDENTIFIER:
				if (IsASCII(ch) && (isalnum(ch) || (ch == '_'))) {
					buffer[bufferCount++] = static_cast<char>(tolower(ch));
				} else {
					state = SCE_INNO_DEFAULT;
					buffer[bufferCount] = '\0';

					// Check if the buffer contains a keyword
					if (!isCode && standardKeywords.InList(buffer)) {
						styler.ColourTo(i-1,SCE_INNO_KEYWORD);
					} else if (!isCode && parameterKeywords.InList(buffer)) {
						styler.ColourTo(i-1,SCE_INNO_PARAMETER);
					} else if (isCode && pascalKeywords.InList(buffer)) {
						styler.ColourTo(i-1,SCE_INNO_KEYWORD_PASCAL);
					} else if (!isCode && userKeywords.InList(buffer)) {
						styler.ColourTo(i-1,SCE_INNO_KEYWORD_USER);
					} else {
						styler.ColourTo(i-1,SCE_INNO_DEFAULT);
					}

					// Push back the faulty character
					chNext = styler[i--];
					ch = chPrev;
				}
				break;

			case SCE_INNO_SECTION:
				if (ch == ']') {
					state = SCE_INNO_DEFAULT;
					buffer[bufferCount] = '\0';

					// Check if the buffer contains a section name
					if (sectionKeywords.InList(buffer)) {
						styler.ColourTo(i,SCE_INNO_SECTION);
						isCode = !CompareCaseInsensitive(buffer, "code");
					} else {
						styler.ColourTo(i,SCE_INNO_DEFAULT);
					}
				} else if (IsASCII(ch) && (isalnum(ch) || (ch == '_'))) {
					buffer[bufferCount++] = static_cast<char>(tolower(ch));
				} else {
					state = SCE_INNO_DEFAULT;
					styler.ColourTo(i,SCE_INNO_DEFAULT);
				}
				break;

			case SCE_INNO_PREPROC:
				if (isWS || isEOL) {
					if (IsASCII(chPrev) && isalpha(chPrev)) {
						state = SCE_INNO_DEFAULT;
						buffer[bufferCount] = '\0';

						// Check if the buffer contains a preprocessor directive
						if (preprocessorKeywords.InList(buffer)) {
							styler.ColourTo(i-1,SCE_INNO_PREPROC);
						} else {
							styler.ColourTo(i-1,SCE_INNO_DEFAULT);
						}

						// Push back the faulty character
						chNext = styler[i--];
						ch = chPrev;
					}
				} else if (IsASCII(ch) && isalpha(ch)) {
					if (chPrev == '#' || chPrev == ' ' || chPrev == '\t')
						bufferCount = 0;
					buffer[bufferCount++] = static_cast<char>(tolower(ch));
				}
				break;

			case SCE_INNO_STRING_DOUBLE:
				if (ch == '"' || isEOL) {
					state = SCE_INNO_DEFAULT;
					styler.ColourTo(i,SCE_INNO_STRING_DOUBLE);
				}
				break;

			case SCE_INNO_STRING_SINGLE:
				if (ch == '\'' || isEOL) {
					state = SCE_INNO_DEFAULT;
					styler.ColourTo(i,SCE_INNO_STRING_SINGLE);
				}
				break;

			case SCE_INNO_INLINE_EXPANSION:
				if (ch == '}') {
					state = SCE_INNO_DEFAULT;
					styler.ColourTo(i,SCE_INNO_INLINE_EXPANSION);
				} else if (isEOL) {
					state = SCE_INNO_DEFAULT;
					styler.ColourTo(i,SCE_INNO_DEFAULT);
				}
				break;

			case SCE_INNO_COMMENT_PASCAL:
				if (isCStyleComment) {
					if (isEOL) {
						state = SCE_INNO_DEFAULT;
						styler.ColourTo(i,SCE_INNO_COMMENT_PASCAL);
					}
				} else {
					if (ch == '}' || (ch == ')' && chPrev == '*')) {
						state = SCE_INNO_DEFAULT;
						styler.ColourTo(i,SCE_INNO_COMMENT_PASCAL);
					} else if (isEOL) {
						state = SCE_INNO_DEFAULT;
						styler.ColourTo(i,SCE_INNO_DEFAULT);
					}
				}
				break;

		}
	}
	delete []buffer;
}

static const char * const innoWordListDesc[] = {
	"Sections",
	"Keywords",
	"Parameters",
	"Preprocessor directives",
	"Pascal keywords",
	"User defined keywords",
	0
};

static void FoldInnoDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[], Accessor &styler) {
	Sci_PositionU endPos = startPos + length;
	char chNext = styler[startPos];

	Sci_Position lineCurrent = styler.GetLine(startPos);

	bool sectionFlag = false;
	int levelPrev = lineCurrent > 0 ? styler.LevelAt(lineCurrent - 1) : SC_FOLDLEVELBASE;
	int level;

	for (Sci_PositionU i = startPos; i < endPos; i++) {
		char ch = chNext;
		chNext = styler[i+1];
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		int style = styler.StyleAt(i);

		if (style == SCE_INNO_SECTION)
			sectionFlag = true;

		if (atEOL || i == endPos - 1) {
			if (sectionFlag) {
				level = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG;
				if (level == levelPrev)
					styler.SetLevel(lineCurrent - 1, levelPrev & ~SC_FOLDLEVELHEADERFLAG);
			} else {
				level = levelPrev & SC_FOLDLEVELNUMBERMASK;
				if (levelPrev & SC_FOLDLEVELHEADERFLAG)
					level++;
			}

			styler.SetLevel(lineCurrent, level);

			levelPrev = level;
			lineCurrent++;
			sectionFlag = false;
		}
	}
}

LexerModule lmInno(SCLEX_INNOSETUP, ColouriseInnoDoc, "inno", FoldInnoDoc, innoWordListDesc);
<commit_msg>Minor increase in allocation size prevents warning from VC++ analyze.<commit_after>// Scintilla source code edit control
/** @file LexInno.cxx
 ** Lexer for Inno Setup scripts.
 **/
// Written by Friedrich Vedder <fvedd@t-online.de>, using code from LexOthers.cxx.
// The License.txt file describes the conditions under which this software may be distributed.

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

#include "ILexer.h"
#include "Scintilla.h"
#include "SciLexer.h"

#include "WordList.h"
#include "LexAccessor.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "CharacterSet.h"
#include "LexerModule.h"

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

static void ColouriseInnoDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *keywordLists[], Accessor &styler) {
	int state = SCE_INNO_DEFAULT;
	char chPrev;
	char ch = 0;
	char chNext = styler[startPos];
	Sci_Position lengthDoc = startPos + length;
	char *buffer = new char[length+1];
	Sci_Position bufferCount = 0;
	bool isBOL, isEOL, isWS, isBOLWS = 0;
	bool isCStyleComment = false;

	WordList &sectionKeywords = *keywordLists[0];
	WordList &standardKeywords = *keywordLists[1];
	WordList &parameterKeywords = *keywordLists[2];
	WordList &preprocessorKeywords = *keywordLists[3];
	WordList &pascalKeywords = *keywordLists[4];
	WordList &userKeywords = *keywordLists[5];

	Sci_Position curLine = styler.GetLine(startPos);
	int curLineState = curLine > 0 ? styler.GetLineState(curLine - 1) : 0;
	bool isCode = (curLineState == 1);

	// Go through all provided text segment
	// using the hand-written state machine shown below
	styler.StartAt(startPos);
	styler.StartSegment(startPos);
	for (Sci_Position i = startPos; i < lengthDoc; i++) {
		chPrev = ch;
		ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);

		if (styler.IsLeadByte(ch)) {
			chNext = styler.SafeGetCharAt(i + 2);
			i++;
			continue;
		}

		isBOL = (chPrev == 0) || (chPrev == '\n') || (chPrev == '\r' && ch != '\n');
		isBOLWS = (isBOL) ? 1 : (isBOLWS && (chPrev == ' ' || chPrev == '\t'));
		isEOL = (ch == '\n' || ch == '\r');
		isWS = (ch == ' ' || ch == '\t');

		if ((ch == '\r' && chNext != '\n') || (ch == '\n')) {
			// Remember the line state for future incremental lexing
			curLine = styler.GetLine(i);
			styler.SetLineState(curLine, (isCode ? 1 : 0));
		}

		switch(state) {
			case SCE_INNO_DEFAULT:
				if (!isCode && ch == ';' && isBOLWS) {
					// Start of a comment
					state = SCE_INNO_COMMENT;
				} else if (ch == '[' && isBOLWS) {
					// Start of a section name
					bufferCount = 0;
					state = SCE_INNO_SECTION;
				} else if (ch == '#' && isBOLWS) {
					// Start of a preprocessor directive
					state = SCE_INNO_PREPROC;
				} else if (!isCode && ch == '{' && chNext != '{' && chPrev != '{') {
					// Start of an inline expansion
					state = SCE_INNO_INLINE_EXPANSION;
				} else if (isCode && (ch == '{' || (ch == '(' && chNext == '*'))) {
					// Start of a Pascal comment
					state = SCE_INNO_COMMENT_PASCAL;
					isCStyleComment = false;
				} else if (isCode && ch == '/' && chNext == '/') {
					// Apparently, C-style comments are legal, too
					state = SCE_INNO_COMMENT_PASCAL;
					isCStyleComment = true;
				} else if (ch == '"') {
					// Start of a double-quote string
					state = SCE_INNO_STRING_DOUBLE;
				} else if (ch == '\'') {
					// Start of a single-quote string
					state = SCE_INNO_STRING_SINGLE;
				} else if (IsASCII(ch) && (isalpha(ch) || (ch == '_'))) {
					// Start of an identifier
					bufferCount = 0;
					buffer[bufferCount++] = static_cast<char>(tolower(ch));
					state = SCE_INNO_IDENTIFIER;
				} else {
					// Style it the default style
					styler.ColourTo(i,SCE_INNO_DEFAULT);
				}
				break;

			case SCE_INNO_COMMENT:
				if (isEOL) {
					state = SCE_INNO_DEFAULT;
					styler.ColourTo(i,SCE_INNO_COMMENT);
				}
				break;

			case SCE_INNO_IDENTIFIER:
				if (IsASCII(ch) && (isalnum(ch) || (ch == '_'))) {
					buffer[bufferCount++] = static_cast<char>(tolower(ch));
				} else {
					state = SCE_INNO_DEFAULT;
					buffer[bufferCount] = '\0';

					// Check if the buffer contains a keyword
					if (!isCode && standardKeywords.InList(buffer)) {
						styler.ColourTo(i-1,SCE_INNO_KEYWORD);
					} else if (!isCode && parameterKeywords.InList(buffer)) {
						styler.ColourTo(i-1,SCE_INNO_PARAMETER);
					} else if (isCode && pascalKeywords.InList(buffer)) {
						styler.ColourTo(i-1,SCE_INNO_KEYWORD_PASCAL);
					} else if (!isCode && userKeywords.InList(buffer)) {
						styler.ColourTo(i-1,SCE_INNO_KEYWORD_USER);
					} else {
						styler.ColourTo(i-1,SCE_INNO_DEFAULT);
					}

					// Push back the faulty character
					chNext = styler[i--];
					ch = chPrev;
				}
				break;

			case SCE_INNO_SECTION:
				if (ch == ']') {
					state = SCE_INNO_DEFAULT;
					buffer[bufferCount] = '\0';

					// Check if the buffer contains a section name
					if (sectionKeywords.InList(buffer)) {
						styler.ColourTo(i,SCE_INNO_SECTION);
						isCode = !CompareCaseInsensitive(buffer, "code");
					} else {
						styler.ColourTo(i,SCE_INNO_DEFAULT);
					}
				} else if (IsASCII(ch) && (isalnum(ch) || (ch == '_'))) {
					buffer[bufferCount++] = static_cast<char>(tolower(ch));
				} else {
					state = SCE_INNO_DEFAULT;
					styler.ColourTo(i,SCE_INNO_DEFAULT);
				}
				break;

			case SCE_INNO_PREPROC:
				if (isWS || isEOL) {
					if (IsASCII(chPrev) && isalpha(chPrev)) {
						state = SCE_INNO_DEFAULT;
						buffer[bufferCount] = '\0';

						// Check if the buffer contains a preprocessor directive
						if (preprocessorKeywords.InList(buffer)) {
							styler.ColourTo(i-1,SCE_INNO_PREPROC);
						} else {
							styler.ColourTo(i-1,SCE_INNO_DEFAULT);
						}

						// Push back the faulty character
						chNext = styler[i--];
						ch = chPrev;
					}
				} else if (IsASCII(ch) && isalpha(ch)) {
					if (chPrev == '#' || chPrev == ' ' || chPrev == '\t')
						bufferCount = 0;
					buffer[bufferCount++] = static_cast<char>(tolower(ch));
				}
				break;

			case SCE_INNO_STRING_DOUBLE:
				if (ch == '"' || isEOL) {
					state = SCE_INNO_DEFAULT;
					styler.ColourTo(i,SCE_INNO_STRING_DOUBLE);
				}
				break;

			case SCE_INNO_STRING_SINGLE:
				if (ch == '\'' || isEOL) {
					state = SCE_INNO_DEFAULT;
					styler.ColourTo(i,SCE_INNO_STRING_SINGLE);
				}
				break;

			case SCE_INNO_INLINE_EXPANSION:
				if (ch == '}') {
					state = SCE_INNO_DEFAULT;
					styler.ColourTo(i,SCE_INNO_INLINE_EXPANSION);
				} else if (isEOL) {
					state = SCE_INNO_DEFAULT;
					styler.ColourTo(i,SCE_INNO_DEFAULT);
				}
				break;

			case SCE_INNO_COMMENT_PASCAL:
				if (isCStyleComment) {
					if (isEOL) {
						state = SCE_INNO_DEFAULT;
						styler.ColourTo(i,SCE_INNO_COMMENT_PASCAL);
					}
				} else {
					if (ch == '}' || (ch == ')' && chPrev == '*')) {
						state = SCE_INNO_DEFAULT;
						styler.ColourTo(i,SCE_INNO_COMMENT_PASCAL);
					} else if (isEOL) {
						state = SCE_INNO_DEFAULT;
						styler.ColourTo(i,SCE_INNO_DEFAULT);
					}
				}
				break;

		}
	}
	delete []buffer;
}

static const char * const innoWordListDesc[] = {
	"Sections",
	"Keywords",
	"Parameters",
	"Preprocessor directives",
	"Pascal keywords",
	"User defined keywords",
	0
};

static void FoldInnoDoc(Sci_PositionU startPos, Sci_Position length, int, WordList *[], Accessor &styler) {
	Sci_PositionU endPos = startPos + length;
	char chNext = styler[startPos];

	Sci_Position lineCurrent = styler.GetLine(startPos);

	bool sectionFlag = false;
	int levelPrev = lineCurrent > 0 ? styler.LevelAt(lineCurrent - 1) : SC_FOLDLEVELBASE;
	int level;

	for (Sci_PositionU i = startPos; i < endPos; i++) {
		char ch = chNext;
		chNext = styler[i+1];
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		int style = styler.StyleAt(i);

		if (style == SCE_INNO_SECTION)
			sectionFlag = true;

		if (atEOL || i == endPos - 1) {
			if (sectionFlag) {
				level = SC_FOLDLEVELBASE | SC_FOLDLEVELHEADERFLAG;
				if (level == levelPrev)
					styler.SetLevel(lineCurrent - 1, levelPrev & ~SC_FOLDLEVELHEADERFLAG);
			} else {
				level = levelPrev & SC_FOLDLEVELNUMBERMASK;
				if (levelPrev & SC_FOLDLEVELHEADERFLAG)
					level++;
			}

			styler.SetLevel(lineCurrent, level);

			levelPrev = level;
			lineCurrent++;
			sectionFlag = false;
		}
	}
}

LexerModule lmInno(SCLEX_INNOSETUP, ColouriseInnoDoc, "inno", FoldInnoDoc, innoWordListDesc);
<|endoftext|>