<commit_before>#include <kernel/timer.hpp>

#include <map>
#include <vector>
#include <kernel/os.hpp>

using namespace std::chrono;
typedef Timers::id_t       id_t;
typedef Timers::duration_t duration_t;
typedef Timers::handler_t  handler_t;

static void sched_timer(duration_t when, id_t id);

struct Timer
{
  Timer(duration_t p, handler_t cb)
    : period(p), callback(cb), deferred_destruct(false) {}

  bool is_alive() const noexcept {
    return deferred_destruct == false;
  }

  bool is_oneshot() const noexcept {
    return period.count() == 0;
  }

  void reset() {
    callback.reset();
    deferred_destruct = false;
  }

  duration_t period;
  handler_t  callback;
  bool deferred_destruct = false;
};

/**
 * 1. There are no restrictions on when timers can be started or stopped
 * 2. A period of 0 means start a one-shot timer
 * 3. Each timer is a separate object living in a "fixed" vector
 * 4. A dead timer is simply a timer which has its handler reset, as well as
 *     having been removed from schedule
 * 5. No timer may be scheduled more than once at a time, as that will needlessly
 *     inflate the schedule container, as well as complicate stopping timers
 * 6. Free timer IDs are retrieved from a stack of free timer IDs (or through
 *     expanding the "fixed" vector)
**/

static std::vector<Timer>  timers;
static std::vector<id_t>   free_timers;
static bool   signal_ready = false;
static bool   is_running = false;
static Timers::start_func_t arch_start_func;
static Timers::stop_func_t  arch_stop_func;

// timers sorted by timestamp
static std::multimap<duration_t, id_t> scheduled;

void Timers::init(const start_func_t& start, const stop_func_t& stop)
{
  // architecture specific start and stop functions
  arch_start_func = start;
  arch_stop_func  = stop;
}

void Timers::ready()
{
  signal_ready = true;
  // begin processing timers if any are queued
  if (is_running == false) {
    timers_handler();
  }
}

static id_t create_timer(
    duration_t when, duration_t period, const handler_t& handler)
{
  id_t id;

  if (free_timers.empty()) {
    id = timers.size();

    // occupy new slot
    timers.emplace_back(period, handler);
  }
  else {
    // get free timer slot
    id = free_timers.back();
    free_timers.pop_back();

    // occupy free slot
    new (&timers[id]) Timer(period, handler);
  }

  // immediately schedule timer
  sched_timer(when, id);
  return id;
}
id_t Timers::oneshot(duration_t when, const handler_t& handler)
{
  return create_timer(when, milliseconds(0), handler);
}
id_t Timers::periodic(duration_t when, duration_t period, const handler_t& handler)
{
  return create_timer(when, period, handler);
}

void Timers::stop(id_t id)
{
  // mark as dead already
  timers[id].deferred_destruct = true;
  // free resources immediately
  timers[id].callback.reset();
}

size_t Timers::active()
{
  return scheduled.size();
}

/// time functions ///

inline std::chrono::microseconds now() noexcept
{
  return microseconds(OS::micros_since_boot());
}

/// scheduling ///

void Timers::timers_handler()
{
  // lets assume the timer is not running anymore
  is_running = false;

  while (!scheduled.empty())
  {
    auto it = scheduled.begin();
    auto when   = it->first;
    auto ts_now = now();
    id_t id = it->second;

    if (ts_now >= when) {
      // erase immediately
      scheduled.erase(it);

      // only process timer if still alive
      if (timers[id].is_alive()) {
        // call the users callback function
        timers[id].callback(id);
        // if the timers struct was modified in callback, eg. due to
        // creating a timer, then the timer reference below would have
        // been invalidated, hence why its BELOW, AND MUST STAY THERE
        auto& timer = timers[id];

        // oneshot timers are automatically freed
        if (timer.deferred_destruct || timer.is_oneshot())
        {
          timer.reset();
          free_timers.push_back(id);
        }
        else if (timer.is_oneshot() == false)
        {
          // if the timer is recurring, we will simply reschedule it
          // NOTE: we are carefully using (when + period) to avoid drift
          scheduled.emplace(std::piecewise_construct,
                    std::forward_as_tuple(when + timer.period),
                    std::forward_as_tuple(id));
        }
      } else {
        // timer was already dead
        timers[id].reset();
        free_timers.push_back(id);
      }

    } else {
      // not yet time, so schedule it for later
      is_running = true;
      arch_start_func(when - ts_now);
      // exit early, because we have nothing more to do, and there is a deferred handler
      return;
    }
  }
  //arch_stop_func();
}
static void sched_timer(duration_t when, id_t id)
{
  scheduled.emplace(std::piecewise_construct,
            std::forward_as_tuple(now() + when),
            std::forward_as_tuple(id));

  // dont start any hardware until after calibration
  if (!signal_ready) return;

  // if the hardware timer is not running, try starting it
  if (is_running == false) {
    Timers::timers_handler();
  }
  // or, if the scheduled timer is the new front, restart timer
  else if (scheduled.begin()->second == id) {
    Timers::timers_handler();
  }
}
<commit_msg>timer: Optimize branching slightly<commit_after>#include <kernel/timer.hpp>

#include <map>
#include <vector>
#include <kernel/os.hpp>

using namespace std::chrono;
typedef Timers::id_t       id_t;
typedef Timers::duration_t duration_t;
typedef Timers::handler_t  handler_t;

static void sched_timer(duration_t when, id_t id);

struct Timer
{
  Timer(duration_t p, handler_t cb)
    : period(p), callback(cb), deferred_destruct(false) {}

  bool is_alive() const noexcept {
    return deferred_destruct == false;
  }

  bool is_oneshot() const noexcept {
    return period.count() == 0;
  }

  void reset() {
    callback.reset();
    deferred_destruct = false;
  }

  duration_t period;
  handler_t  callback;
  bool deferred_destruct = false;
};

/**
 * 1. There are no restrictions on when timers can be started or stopped
 * 2. A period of 0 means start a one-shot timer
 * 3. Each timer is a separate object living in a "fixed" vector
 * 4. A dead timer is simply a timer which has its handler reset, as well as
 *     having been removed from schedule
 * 5. No timer may be scheduled more than once at a time, as that will needlessly
 *     inflate the schedule container, as well as complicate stopping timers
 * 6. Free timer IDs are retrieved from a stack of free timer IDs (or through
 *     expanding the "fixed" vector)
**/

static std::vector<Timer>  timers;
static std::vector<id_t>   free_timers;
static bool   signal_ready = false;
static bool   is_running = false;
static Timers::start_func_t arch_start_func;
static Timers::stop_func_t  arch_stop_func;

// timers sorted by timestamp
static std::multimap<duration_t, id_t> scheduled;

void Timers::init(const start_func_t& start, const stop_func_t& stop)
{
  // architecture specific start and stop functions
  arch_start_func = start;
  arch_stop_func  = stop;
}

void Timers::ready()
{
  signal_ready = true;
  // begin processing timers if any are queued
  if (is_running == false) {
    timers_handler();
  }
}

static id_t create_timer(
    duration_t when, duration_t period, const handler_t& handler)
{
  id_t id;

  if (UNLIKELY(free_timers.empty())) {
    id = timers.size();

    // occupy new slot
    timers.emplace_back(period, handler);
  }
  else {
    // get free timer slot
    id = free_timers.back();
    free_timers.pop_back();

    // occupy free slot
    new (&timers[id]) Timer(period, handler);
  }

  // immediately schedule timer
  sched_timer(when, id);
  return id;
}
id_t Timers::oneshot(duration_t when, const handler_t& handler)
{
  return create_timer(when, milliseconds(0), handler);
}
id_t Timers::periodic(duration_t when, duration_t period, const handler_t& handler)
{
  return create_timer(when, period, handler);
}

void Timers::stop(id_t id)
{
  // mark as dead already
  timers[id].deferred_destruct = true;
  // free resources immediately
  timers[id].callback.reset();
}

size_t Timers::active()
{
  return scheduled.size();
}

/// time functions ///

inline std::chrono::microseconds now() noexcept
{
  return microseconds(OS::micros_since_boot());
}

/// scheduling ///

void Timers::timers_handler()
{
  // lets assume the timer is not running anymore
  is_running = false;

  while (!scheduled.empty())
  {
    auto it = scheduled.begin();
    auto when   = it->first;
    auto ts_now = now();
    id_t id = it->second;

    if (ts_now >= when) {
      // erase immediately
      scheduled.erase(it);

      // only process timer if still alive
      if (timers[id].is_alive()) {
        // call the users callback function
        timers[id].callback(id);
        // if the timers struct was modified in callback, eg. due to
        // creating a timer, then the timer reference below would have
        // been invalidated, hence why its BELOW, AND MUST STAY THERE
        auto& timer = timers[id];

        // oneshot timers are automatically freed
        if (timer.deferred_destruct || timer.is_oneshot())
        {
          timer.reset();
          free_timers.push_back(id);
        }
        else if (timer.is_oneshot() == false)
        {
          // if the timer is recurring, we will simply reschedule it
          // NOTE: we are carefully using (when + period) to avoid drift
          scheduled.emplace(std::piecewise_construct,
                    std::forward_as_tuple(when + timer.period),
                    std::forward_as_tuple(id));
        }
      } else {
        // timer was already dead
        timers[id].reset();
        free_timers.push_back(id);
      }

    } else {
      // not yet time, so schedule it for later
      is_running = true;
      arch_start_func(when - ts_now);
      // exit early, because we have nothing more to do, and there is a deferred handler
      return;
    }
  }
  //arch_stop_func();
}
static void sched_timer(duration_t when, id_t id)
{
  scheduled.emplace(std::piecewise_construct,
            std::forward_as_tuple(now() + when),
            std::forward_as_tuple(id));

  // dont start any hardware until after calibration
  if (UNLIKELY(!signal_ready)) return;

  // if the hardware timer is not running, try starting it
  if (UNLIKELY(is_running == false)) {
    Timers::timers_handler();
  }
  // or, if the scheduled timer is the new front, restart timer
  else if (scheduled.begin()->second == id) {
    Timers::timers_handler();
  }
}
<|endoftext|>


<commit_before>/*
  Copyright (c) 2014
  Author: Jeff Weisberg <jaw @ solvemedia.com>
  Created: 2014-Mar-14 15:57 (EDT)
  Function:

*/

#define CURRENT_SUBSYSTEM	'k'

#include "defs.h"
#include "diag.h"
#include "config.h"
#include "misc.h"
#include "runmode.h"
#include "network.h"
#include "hrtime.h"

#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/resource.h>
#include <sys/statvfs.h>
#include <sys/loadavg.h>

#include "std_ipport.pb.h"
#include "mrmagoo.pb.h"

#include <strings.h>

#define BOOTTIME	60

static hrtime_t starttime = 0;
static char pinhost[256];
static uint32_t pinip4 = 0;

bool
NetAddr::is_self(void){

    if( ipv4 == pinip4 ) return 1;
    if( ipv4 == myipv4 ) return 1;

    return 0;
}

void
myself_init(void){
    struct hostent *he;

    starttime = lr_now();

    // find private internal network info
    snprintf(pinhost, sizeof(pinhost), "pin-%s", myhostname);
    he = gethostbyname( pinhost );
    if( he && he->h_length ){
        pinip4 = ((struct in_addr *)*he->h_addr_list)->s_addr;
    }else{
        VERBOSE("no private network found: %s", pinhost);
    }
}

void
about_myself(ACPMRMStatus *g){
    hrtime_t now = lr_now();
    ACPIPPort *ip;
    double load[3];
    struct statvfs vfs;

    getloadavg( load, 3 );

    g->set_hostname( myhostname );
    g->set_server_id( myserver_id.c_str() );
    g->set_datacenter( mydatacenter.c_str() );
    g->set_environment( config->environment.c_str() );
    g->set_subsystem( MYNAME );
    g->set_via( myserver_id.c_str() );
    g->set_path( "." );
    if( config->available && (runmode.mode() == RUN_MODE_RUN) ){
        g->set_status( (now > starttime + BOOTTIME) ? 200 : 102 );
    }else{
        g->set_status( 102 );
    }
    g->set_timestamp( now );
    g->set_lastup( now );
    g->set_boottime( starttime );

    g->set_sort_metric( current_load() );

    // determine disk space
    if( ! statvfs( config->basedir.c_str(), &vfs ) ){
        g->set_capacity_metric( vfs.f_bavail / 2048 );	// MB avail
    }

    // ip info
    ip = g->add_ip();
    ip->set_ipv4( ntohl(myipv4) );
    ip->set_port( myport );

    if( pinip4 ){
        ip = g->add_ip();
        ip->set_ipv4( ntohl(pinip4) );
        ip->set_port( myport );
        ip->set_natdom( mydatacenter.c_str() );
    }
}

<commit_msg>cleanup<commit_after>/*
  Copyright (c) 2014
  Author: Jeff Weisberg <jaw @ solvemedia.com>
  Created: 2014-Mar-14 15:57 (EDT)
  Function:

*/

#define CURRENT_SUBSYSTEM	'k'

#include "defs.h"
#include "diag.h"
#include "config.h"
#include "misc.h"
#include "runmode.h"
#include "network.h"
#include "hrtime.h"

#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/resource.h>
#include <sys/statvfs.h>
#include <sys/loadavg.h>

#include "std_ipport.pb.h"
#include "mrmagoo.pb.h"

#include <strings.h>

#define BOOTTIME	60

static hrtime_t starttime = 0;
static char pinhost[256];
static uint32_t pinip4 = 0;

bool
NetAddr::is_self(void){

    if( ipv4 == pinip4 ) return 1;
    if( ipv4 == myipv4 ) return 1;

    return 0;
}

void
myself_init(void){
    struct hostent *he;

    starttime = lr_now();

    // find private internal network info
    // we name the private internal address "pin-$hostname"
    // you may need to adjust this for your network

    snprintf(pinhost, sizeof(pinhost), "pin-%s", myhostname);
    he = gethostbyname( pinhost );
    if( he && he->h_length ){
        pinip4 = ((struct in_addr *)*he->h_addr_list)->s_addr;
    }else{
        VERBOSE("no private network found: %s", pinhost);
    }
}

void
about_myself(ACPMRMStatus *g){
    hrtime_t now = lr_now();
    ACPIPPort *ip;
    struct statvfs vfs;

    g->set_hostname( myhostname );
    g->set_server_id( myserver_id.c_str() );
    g->set_datacenter( mydatacenter.c_str() );
    g->set_environment( config->environment.c_str() );
    g->set_subsystem( MYNAME );
    g->set_via( myserver_id.c_str() );
    g->set_path( "." );
    if( config->available && (runmode.mode() == RUN_MODE_RUN) ){
        g->set_status( (now > starttime + BOOTTIME) ? 200 : 102 );
    }else{
        g->set_status( 102 );
    }
    g->set_timestamp( now );
    g->set_lastup( now );
    g->set_boottime( starttime );

    g->set_sort_metric( current_load() );

    // determine disk space
    if( ! statvfs( config->basedir.c_str(), &vfs ) ){
        g->set_capacity_metric( vfs.f_bavail / 2048 );	// MB avail
    }

    // ip info
    ip = g->add_ip();
    ip->set_ipv4( ntohl(myipv4) );
    ip->set_port( myport );

    if( pinip4 ){
        ip = g->add_ip();
        ip->set_ipv4( ntohl(pinip4) );
        ip->set_port( myport );
        ip->set_natdom( mydatacenter.c_str() );
    }
}

<|endoftext|>


<commit_before><commit_msg>Disabled Toolbar5ImporterTest.BookmarkParse due to failing valgrind/purify tests.<commit_after><|endoftext|>


<commit_before>#include "../USB.h"
#include "../configuration.h"
#include "../deviceproxy.h"
#include "../usb-pad/config.h"
#include "../usb-pad/padproxy.h"
#include "../usb-mic/audiosourceproxy.h"

#include <sstream>
#include <map>
#include <vector>
#include <string>

#include "ini.h"
#include "config.h"

//libjoyrumble used as an example
//Hopefully PCSX2 has inited all the GTK stuff already
using namespace std;

static std::string usb_path;
std::string IniDir;
std::string LogDir;
const char* iniFile = "USBqemu-wheel.ini";

void SysMessage(const char *fmt, ...)
{
	va_list arglist;

	va_start(arglist, fmt);
	vfprintf(stderr, fmt, arglist);
	va_end(arglist);
}

void CALLBACK USBsetSettingsDir( const char* dir )
{
	fprintf(stderr, "USBsetSettingsDir: %s\n", dir);
	IniDir = dir;
}

void CALLBACK USBsetLogDir( const char* dir )
{
	printf("USBsetLogDir: %s\n", dir);
	LogDir = dir;
}

template<typename T>
bool LoadSettingValue(const std::string& ini, const std::string& section, const char* param, T& value);
template<typename T>
bool SaveSettingValue(const std::string& ini, const std::string& section, const char* param, T& value);

template<>
bool LoadSettingValue(const std::string& ini, const std::string& section, const char* param, std::string& value)
{
	char tmp[4096] = {0};
	INILoadString(ini.c_str(), section.c_str(), param, tmp);
	value = tmp;
	return true;
}

template<>
bool LoadSettingValue(const std::string& ini, const std::string& section, const char* param, int64_t& value)
{
	INILoadUInt(ini.c_str(), section.c_str(), param, (unsigned int *)value);
	return true;
}

template<>
bool SaveSettingValue(const std::string& ini, const std::string& section, const char* param, std::string& value)
{
	INISaveString(ini.c_str(), section.c_str(), param, value.c_str());
	return true;
}

template<>
bool SaveSettingValue(const std::string& ini, const std::string& section, const char* param, int64_t& value)
{
	INISaveUInt(ini.c_str(), section.c_str(), param, (unsigned int)value);
	return true;
}

bool LoadSetting(int port, const std::string& key, CONFIGVARIANT& var)
{
	fprintf(stderr, "USBqemu load \"%s\" from %s\n", var.name, key.c_str());

	std::stringstream section;
	section << key << " " << port;

	std::string ini(IniDir);
	ini.append(iniFile);

	switch(var.type)
	{
		case CONFIG_TYPE_INT:
			return LoadSettingValue(ini, section.str(), var.name, var.intValue);
		//case CONFIG_TYPE_DOUBLE:
		//	return LoadSettingValue(ini, section.str(), var.name, var.doubleValue);
		case CONFIG_TYPE_TCHAR:
			return LoadSettingValue(ini, section.str(), var.name, var.strValue);
		case CONFIG_TYPE_CHAR:
			return LoadSettingValue(ini, section.str(), var.name, var.strValue);
		//case CONFIG_TYPE_WCHAR:
		//	return LoadSettingValue(ini, section.str(), var.name, var.wstrValue);
		break;
		default:
			fprintf(stderr, "Invalid config type %d for %s\n", var.type, var.name);
			break;
	};
	return false;
}

/**
 *
 * [devices]
 * portX = pad
 *
 * [pad X]
 * api = joydev
 *
 * [joydev X]
 * button0 = 1
 * button1 = 2
 * ...
 *
 * */
bool SaveSetting(int port, const std::string& key, CONFIGVARIANT& var)
{
	fprintf(stderr, "USBqemu save \"%s\" to %s\n", var.name, key.c_str());

	std::stringstream section;
	section << key << " " << port;

	std::string ini(IniDir);
	ini.append(iniFile);

	switch(var.type)
	{
		case CONFIG_TYPE_INT:
			return SaveSettingValue(ini, section.str(), var.name, var.intValue);
		case CONFIG_TYPE_TCHAR:
			return LoadSettingValue(ini, section.str(), var.name, var.strValue);
		case CONFIG_TYPE_CHAR:
			return SaveSettingValue(ini, section.str(), var.name, var.strValue);
		break;
		default:
			fprintf(stderr, "Invalid config type %d for %s\n", var.type, var.name);
			break;
	};
	return false;
}

void SaveConfig() {
	fprintf(stderr, "USB save config\n");
	//char* envptr = getenv("HOME");
	//if(envptr == NULL)
	//	return;
	//char path[1024];
	//snprintf(path, sizeof(path), "%s/.config/PCSX2/inis/USBqemu-wheel.ini", envptr);
	std::string iniPath(IniDir);
	iniPath.append(iniFile);
	const char *path = iniPath.c_str();

	//fprintf(stderr, "%s\n", path);

	INISaveString(path, N_DEVICES, N_DEVICE_PORT0, conf.Port0.c_str());
	INISaveString(path, N_DEVICES, N_DEVICE_PORT1, conf.Port1.c_str());
	INISaveUInt(path, N_DEVICES, N_WHEEL_TYPE0, conf.WheelType[0]);
	INISaveUInt(path, N_DEVICES, N_WHEEL_TYPE1, conf.WheelType[1]);

	for (auto& k : changedAPIs)
	{
		CONFIGVARIANT var(N_DEVICE_API, CONFIG_TYPE_CHAR);
		var.strValue = k.second;
		fprintf(stderr, "Save apis: %s %s\n", k.first.second.c_str(), k.second.c_str());
		SaveSetting(k.first.first, k.first.second, var);
	}
}

void LoadConfig() {
	char tmp[1024] = {0};
	fprintf(stderr, "USB load config\n");
	//char* envptr = getenv("HOME");
	//if(envptr == NULL)
	//	return;
	//char path[1024];
	//sprintf(path, "%s/.config/PCSX2/inis/USBqemu-wheel.ini", envptr);
	std::string iniPath(IniDir);
	iniPath.append(iniFile);
	const char *path = iniPath.c_str();

	INILoadString(path, N_DEVICES, N_DEVICE_PORT0, tmp);
	conf.Port0 = tmp;
	INILoadString(path, N_DEVICES, N_DEVICE_PORT1, tmp);
	conf.Port1 = tmp;
	INILoadUInt(path, N_DEVICES, N_WHEEL_TYPE0, (u32*)&conf.WheelType[0]);
	INILoadUInt(path, N_DEVICES, N_WHEEL_TYPE1, (u32*)&conf.WheelType[1]);

	{
		auto instance = RegisterDevice::instance();
		CONFIGVARIANT tmpVar(N_DEVICE_API, CONFIG_TYPE_CHAR);
		LoadSetting(0, conf.Port0, tmpVar);
		std::string api = tmpVar.strValue;
		auto dev = instance.Device(conf.Port0);

		if (dev && !dev->IsValidAPI(api))
		{
			auto apis = dev->APIs();
			if (!apis.empty())
				api = *apis.begin();
		}

		if(api.size())
			changedAPIs[std::make_pair(0, conf.Port0)] = api;

		LoadSetting(1, conf.Port1, tmpVar);
		api = tmpVar.strValue;

		dev = instance.Device(conf.Port1);
		if (dev && !dev->IsValidAPI(api))
		{
			auto apis = dev->APIs();
			if (!apis.empty())
				api = *apis.begin();
		}

		if(api.size())
			changedAPIs[std::make_pair(1, conf.Port1)] = api;
	}
}
<commit_msg>linux/config.cpp: print key/port formatted as section name.<commit_after>#include "../USB.h"
#include "../configuration.h"
#include "../deviceproxy.h"
#include "../usb-pad/config.h"
#include "../usb-pad/padproxy.h"
#include "../usb-mic/audiosourceproxy.h"

#include <sstream>
#include <map>
#include <vector>
#include <string>

#include "ini.h"
#include "config.h"

//libjoyrumble used as an example
//Hopefully PCSX2 has inited all the GTK stuff already
using namespace std;

static std::string usb_path;
std::string IniDir;
std::string LogDir;
const char* iniFile = "USBqemu-wheel.ini";

void SysMessage(const char *fmt, ...)
{
	va_list arglist;

	va_start(arglist, fmt);
	vfprintf(stderr, fmt, arglist);
	va_end(arglist);
}

void CALLBACK USBsetSettingsDir( const char* dir )
{
	fprintf(stderr, "USBsetSettingsDir: %s\n", dir);
	IniDir = dir;
}

void CALLBACK USBsetLogDir( const char* dir )
{
	printf("USBsetLogDir: %s\n", dir);
	LogDir = dir;
}

template<typename T>
bool LoadSettingValue(const std::string& ini, const std::string& section, const char* param, T& value);
template<typename T>
bool SaveSettingValue(const std::string& ini, const std::string& section, const char* param, T& value);

template<>
bool LoadSettingValue(const std::string& ini, const std::string& section, const char* param, std::string& value)
{
	char tmp[4096] = {0};
	INILoadString(ini.c_str(), section.c_str(), param, tmp);
	value = tmp;
	return true;
}

template<>
bool LoadSettingValue(const std::string& ini, const std::string& section, const char* param, int64_t& value)
{
	INILoadUInt(ini.c_str(), section.c_str(), param, (unsigned int *)value);
	return true;
}

template<>
bool SaveSettingValue(const std::string& ini, const std::string& section, const char* param, std::string& value)
{
	INISaveString(ini.c_str(), section.c_str(), param, value.c_str());
	return true;
}

template<>
bool SaveSettingValue(const std::string& ini, const std::string& section, const char* param, int64_t& value)
{
	INISaveUInt(ini.c_str(), section.c_str(), param, (unsigned int)value);
	return true;
}

bool LoadSetting(int port, const std::string& key, CONFIGVARIANT& var)
{
	fprintf(stderr, "USBqemu load \"%s\" from [%s %d]\n", var.name, key.c_str(), port);

	std::stringstream section;
	section << key << " " << port;

	std::string ini(IniDir);
	ini.append(iniFile);

	switch(var.type)
	{
		case CONFIG_TYPE_INT:
			return LoadSettingValue(ini, section.str(), var.name, var.intValue);
		//case CONFIG_TYPE_DOUBLE:
		//	return LoadSettingValue(ini, section.str(), var.name, var.doubleValue);
		case CONFIG_TYPE_TCHAR:
			return LoadSettingValue(ini, section.str(), var.name, var.strValue);
		case CONFIG_TYPE_CHAR:
			return LoadSettingValue(ini, section.str(), var.name, var.strValue);
		//case CONFIG_TYPE_WCHAR:
		//	return LoadSettingValue(ini, section.str(), var.name, var.wstrValue);
		break;
		default:
			fprintf(stderr, "Invalid config type %d for %s\n", var.type, var.name);
			break;
	};
	return false;
}

/**
 *
 * [devices]
 * portX = pad
 *
 * [pad X]
 * api = joydev
 *
 * [joydev X]
 * button0 = 1
 * button1 = 2
 * ...
 *
 * */
bool SaveSetting(int port, const std::string& key, CONFIGVARIANT& var)
{
	fprintf(stderr, "USBqemu save \"%s\" to [%s %d]\n", var.name, key.c_str(), port);

	std::stringstream section;
	section << key << " " << port;

	std::string ini(IniDir);
	ini.append(iniFile);

	switch(var.type)
	{
		case CONFIG_TYPE_INT:
			return SaveSettingValue(ini, section.str(), var.name, var.intValue);
		case CONFIG_TYPE_TCHAR:
			return LoadSettingValue(ini, section.str(), var.name, var.strValue);
		case CONFIG_TYPE_CHAR:
			return SaveSettingValue(ini, section.str(), var.name, var.strValue);
		break;
		default:
			fprintf(stderr, "Invalid config type %d for %s\n", var.type, var.name);
			break;
	};
	return false;
}

void SaveConfig() {
	fprintf(stderr, "USB save config\n");
	//char* envptr = getenv("HOME");
	//if(envptr == NULL)
	//	return;
	//char path[1024];
	//snprintf(path, sizeof(path), "%s/.config/PCSX2/inis/USBqemu-wheel.ini", envptr);
	std::string iniPath(IniDir);
	iniPath.append(iniFile);
	const char *path = iniPath.c_str();

	//fprintf(stderr, "%s\n", path);

	INISaveString(path, N_DEVICES, N_DEVICE_PORT0, conf.Port0.c_str());
	INISaveString(path, N_DEVICES, N_DEVICE_PORT1, conf.Port1.c_str());
	INISaveUInt(path, N_DEVICES, N_WHEEL_TYPE0, conf.WheelType[0]);
	INISaveUInt(path, N_DEVICES, N_WHEEL_TYPE1, conf.WheelType[1]);

	for (auto& k : changedAPIs)
	{
		CONFIGVARIANT var(N_DEVICE_API, CONFIG_TYPE_CHAR);
		var.strValue = k.second;
		fprintf(stderr, "Save apis: %s %s\n", k.first.second.c_str(), k.second.c_str());
		SaveSetting(k.first.first, k.first.second, var);
	}
}

void LoadConfig() {
	char tmp[1024] = {0};
	fprintf(stderr, "USB load config\n");
	//char* envptr = getenv("HOME");
	//if(envptr == NULL)
	//	return;
	//char path[1024];
	//sprintf(path, "%s/.config/PCSX2/inis/USBqemu-wheel.ini", envptr);
	std::string iniPath(IniDir);
	iniPath.append(iniFile);
	const char *path = iniPath.c_str();

	INILoadString(path, N_DEVICES, N_DEVICE_PORT0, tmp);
	conf.Port0 = tmp;
	INILoadString(path, N_DEVICES, N_DEVICE_PORT1, tmp);
	conf.Port1 = tmp;
	INILoadUInt(path, N_DEVICES, N_WHEEL_TYPE0, (u32*)&conf.WheelType[0]);
	INILoadUInt(path, N_DEVICES, N_WHEEL_TYPE1, (u32*)&conf.WheelType[1]);

	{
		auto instance = RegisterDevice::instance();
		CONFIGVARIANT tmpVar(N_DEVICE_API, CONFIG_TYPE_CHAR);
		LoadSetting(0, conf.Port0, tmpVar);
		std::string api = tmpVar.strValue;
		auto dev = instance.Device(conf.Port0);

		if (dev && !dev->IsValidAPI(api))
		{
			auto apis = dev->APIs();
			if (!apis.empty())
				api = *apis.begin();
		}

		if(api.size())
			changedAPIs[std::make_pair(0, conf.Port0)] = api;

		LoadSetting(1, conf.Port1, tmpVar);
		api = tmpVar.strValue;

		dev = instance.Device(conf.Port1);
		if (dev && !dev->IsValidAPI(api))
		{
			auto apis = dev->APIs();
			if (!apis.empty())
				api = *apis.begin();
		}

		if(api.size())
			changedAPIs[std::make_pair(1, conf.Port1)] = api;
	}
}
<|endoftext|>


<commit_before>/***************************************************************************
*   Copyright (C) 2005 by                                                 *
*   Jason Kivlighn (jkivlighn@gmail.com)                                  *
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
***************************************************************************/

#include "plaintextexporter.h"

#include <kconfig.h>
#include <kglobal.h>
#include <klocale.h>

#include "backends/recipedb.h"

PlainTextExporter::PlainTextExporter( const QString& filename, const QString& format ) :
		BaseExporter( filename, format )
{}

PlainTextExporter::~PlainTextExporter()
{}

int PlainTextExporter::supportedItems() const
{
	return RecipeDB::All ^ RecipeDB::Photo;
}

QString PlainTextExporter::generateIngredient( const IngredientData &ing, MixedNumber::Format number_format )
{
	KConfig *config = KGlobal::config();

	QString content;

	QString amount_str = MixedNumber( ing.amount ).toString( number_format );

	if ( ing.amount_offset > 0 )
		amount_str += "-"+MixedNumber( ing.amount + ing.amount_offset ).toString( number_format );
	else if ( ing.amount <= 1e-10 )
		amount_str = "";

	content += amount_str;
	if ( !amount_str.isEmpty() )
		content += " ";

	QString unit_str = ing.units.determineName( ing.amount + ing.amount_offset, config->readBoolEntry("AbbreviateUnits") );

	content += unit_str;
	if ( !unit_str.isEmpty() )
		content += " ";

	content += ing.name;

	if ( ing.prepMethodList.count() > 0 )
		content += "; "+ing.prepMethodList.join(", ");

	return content;
}

QString PlainTextExporter::createContent( const RecipeList& recipes )
{
	KConfig *config = KGlobal::config();
	config->setGroup( "Formatting" );

	MixedNumber::Format number_format = ( config->readBoolEntry( "Fraction" ) ) ? MixedNumber::MixedNumberFormat : MixedNumber::DecimalFormat;

	QString content;

	RecipeList::const_iterator recipe_it;
	for ( recipe_it = recipes.begin(); recipe_it != recipes.end(); ++recipe_it ) {
		content += ( *recipe_it ).title + "\n\n";

		if ( ( *recipe_it ).authorList.count() > 0 ) {
			content += QString("%1: ").arg(i18n("Authors"));
			content += ( *recipe_it ).authorList.join(", ");
			content += "\n";
		}

		if ( ( *recipe_it ).categoryList.count() > 0 ) {
			content += QString("%1: ").arg(i18n("Categories"));
			content += ( *recipe_it ).categoryList.join(", ");
			content += "\n";
		}

		if ( ( *recipe_it ).yield.amount > 0 ) {
			content += QString("%1: ").arg(i18n("Yields"));
			content += ( *recipe_it ).yield.toString();
			content += "\n";
		}

		if ( !( *recipe_it ).prepTime.isNull() ) {
			content += QString("%1: ").arg(i18n("Preparation Time"));
			content += ( *recipe_it ).prepTime.toString( "hh:mm" );
			content += "\n";
		}

		content += "\n";

		IngredientList list_copy = ( *recipe_it ).ingList;
		for ( IngredientList group_list = list_copy.firstGroup(); group_list.count() != 0; group_list = list_copy.nextGroup() ) {
			QString group = group_list[ 0 ].group; //just use the first's name... they're all the same
			if ( !group.isEmpty() )
				content += group + ":\n";

			for ( IngredientList::const_iterator ing_it = group_list.begin(); ing_it != group_list.end(); ++ing_it ) {
				if ( !group.isEmpty() )
					content += "  ";

				content += generateIngredient(*ing_it,number_format);

				if ( (*ing_it).substitutes.count() > 0 )
					content += ", "+i18n("or");

				for ( QValueList<IngredientData>::const_iterator sub_it = (*ing_it).substitutes.begin(); sub_it != (*ing_it).substitutes.end(); ) {
					content += "  "+generateIngredient(*sub_it,number_format);
					sub_it++;
					if ( sub_it != (*ing_it).substitutes.end() )
						content += ", "+i18n("or");
					content += "\n";
				}

				content += "\n";
			}
		}

		content += "\n";

		/// @todo add ingredient properties

		content += ( *recipe_it ).instructions;

		content += "\n\n";

		if ( (*recipe_it).ratingList.count() > 0 )
			content += "----------"+i18n("Ratings")+"----------\n";

		for ( RatingList::const_iterator rating_it = (*recipe_it).ratingList.begin(); rating_it != (*recipe_it).ratingList.end(); ++rating_it ) {
			if ( !( *rating_it ).rater.isEmpty() )
				content += "  "+( *rating_it ).rater+"\n";

			if ( (*rating_it).ratingCriteriaList.size() > 0 )
				content += "\n";

			for ( RatingCriteriaList::const_iterator rc_it = (*rating_it).ratingCriteriaList.begin(); rc_it != (*rating_it).ratingCriteriaList.end(); ++rc_it ) {
				//FIXME: This is an ugly hack, but I don't know how else to be i18n friendly (if this is even that)
				// and still be able to display the amount as a fraction
				QString starsTrans = i18n("1 star","%n stars",qRound((*rc_it).stars));
				starsTrans.replace(QString::number(qRound((*rc_it).stars)),MixedNumber((*rc_it).stars).toString());

				content +=  "  "+(*rc_it).name+": "+starsTrans+"\n";
			}

			if ( (*rating_it).ratingCriteriaList.size() > 0 )
				content += "\n";

			if ( !( *rating_it ).comment.isEmpty() )
				content += "  "+( *rating_it ).comment+"\n";

			content += "\n";
		}

		if ( (*recipe_it).ratingList.size() > 0 )
			content += "\n";

		content += "-----\n\n"; //end of recipe indicator
	}

	return content;
}

<commit_msg>Slight improvement on how to show substitutes in the text exporter<commit_after>/***************************************************************************
*   Copyright (C) 2005 by                                                 *
*   Jason Kivlighn (jkivlighn@gmail.com)                                  *
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
***************************************************************************/

#include "plaintextexporter.h"

#include <kconfig.h>
#include <kglobal.h>
#include <klocale.h>

#include "backends/recipedb.h"

PlainTextExporter::PlainTextExporter( const QString& filename, const QString& format ) :
		BaseExporter( filename, format )
{}

PlainTextExporter::~PlainTextExporter()
{}

int PlainTextExporter::supportedItems() const
{
	return RecipeDB::All ^ RecipeDB::Photo;
}

QString PlainTextExporter::generateIngredient( const IngredientData &ing, MixedNumber::Format number_format )
{
	KConfig *config = KGlobal::config();

	QString content;

	QString amount_str = MixedNumber( ing.amount ).toString( number_format );

	if ( ing.amount_offset > 0 )
		amount_str += "-"+MixedNumber( ing.amount + ing.amount_offset ).toString( number_format );
	else if ( ing.amount <= 1e-10 )
		amount_str = "";

	content += amount_str;
	if ( !amount_str.isEmpty() )
		content += " ";

	QString unit_str = ing.units.determineName( ing.amount + ing.amount_offset, config->readBoolEntry("AbbreviateUnits") );

	content += unit_str;
	if ( !unit_str.isEmpty() )
		content += " ";

	content += ing.name;

	if ( ing.prepMethodList.count() > 0 )
		content += "; "+ing.prepMethodList.join(", ");

	return content;
}

QString PlainTextExporter::createContent( const RecipeList& recipes )
{
	KConfig *config = KGlobal::config();
	config->setGroup( "Formatting" );

	MixedNumber::Format number_format = ( config->readBoolEntry( "Fraction" ) ) ? MixedNumber::MixedNumberFormat : MixedNumber::DecimalFormat;

	QString content;

	RecipeList::const_iterator recipe_it;
	for ( recipe_it = recipes.begin(); recipe_it != recipes.end(); ++recipe_it ) {
		content += ( *recipe_it ).title + "\n\n";

		if ( ( *recipe_it ).authorList.count() > 0 ) {
			content += QString("%1: ").arg(i18n("Authors"));
			content += ( *recipe_it ).authorList.join(", ");
			content += "\n";
		}

		if ( ( *recipe_it ).categoryList.count() > 0 ) {
			content += QString("%1: ").arg(i18n("Categories"));
			content += ( *recipe_it ).categoryList.join(", ");
			content += "\n";
		}

		if ( ( *recipe_it ).yield.amount > 0 ) {
			content += QString("%1: ").arg(i18n("Yields"));
			content += ( *recipe_it ).yield.toString();
			content += "\n";
		}

		if ( !( *recipe_it ).prepTime.isNull() ) {
			content += QString("%1: ").arg(i18n("Preparation Time"));
			content += ( *recipe_it ).prepTime.toString( "hh:mm" );
			content += "\n";
		}

		content += "\n";

		IngredientList list_copy = ( *recipe_it ).ingList;
		for ( IngredientList group_list = list_copy.firstGroup(); group_list.count() != 0; group_list = list_copy.nextGroup() ) {
			QString group = group_list[ 0 ].group; //just use the first's name... they're all the same
			if ( !group.isEmpty() )
				content += group + ":\n";

			for ( IngredientList::const_iterator ing_it = group_list.begin(); ing_it != group_list.end(); ++ing_it ) {
				if ( !group.isEmpty() )
					content += "  ";

				content += generateIngredient(*ing_it,number_format);

				if ( (*ing_it).substitutes.count() > 0 )
					content += ", "+i18n("or");
				content += "\n";

				for ( QValueList<IngredientData>::const_iterator sub_it = (*ing_it).substitutes.begin(); sub_it != (*ing_it).substitutes.end(); ) {
					if ( !group.isEmpty() )
						content += "  ";

					content += generateIngredient(*sub_it,number_format);
					sub_it++;
					if ( sub_it != (*ing_it).substitutes.end() )
						content += ", "+i18n("or");
					content += "\n";
				}
			}
		}

		content += "\n";

		/// @todo add ingredient properties

		content += ( *recipe_it ).instructions;

		content += "\n\n";

		if ( (*recipe_it).ratingList.count() > 0 )
			content += "----------"+i18n("Ratings")+"----------\n";

		for ( RatingList::const_iterator rating_it = (*recipe_it).ratingList.begin(); rating_it != (*recipe_it).ratingList.end(); ++rating_it ) {
			if ( !( *rating_it ).rater.isEmpty() )
				content += "  "+( *rating_it ).rater+"\n";

			if ( (*rating_it).ratingCriteriaList.size() > 0 )
				content += "\n";

			for ( RatingCriteriaList::const_iterator rc_it = (*rating_it).ratingCriteriaList.begin(); rc_it != (*rating_it).ratingCriteriaList.end(); ++rc_it ) {
				//FIXME: This is an ugly hack, but I don't know how else to be i18n friendly (if this is even that)
				// and still be able to display the amount as a fraction
				QString starsTrans = i18n("1 star","%n stars",qRound((*rc_it).stars));
				starsTrans.replace(QString::number(qRound((*rc_it).stars)),MixedNumber((*rc_it).stars).toString());

				content +=  "  "+(*rc_it).name+": "+starsTrans+"\n";
			}

			if ( (*rating_it).ratingCriteriaList.size() > 0 )
				content += "\n";

			if ( !( *rating_it ).comment.isEmpty() )
				content += "  "+( *rating_it ).comment+"\n";

			content += "\n";
		}

		if ( (*recipe_it).ratingList.size() > 0 )
			content += "\n";

		content += "-----\n\n"; //end of recipe indicator
	}

	return content;
}

<|endoftext|>


<commit_before>/**
 * Copyright (c) 2017, Loic Blot <loic.blot@unix-experience.fr>
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "l_string.h"
#include <luaengine.h>
#include <utils/base64.h>
#include <utils/hmac.h>
#include <json/json.h>
#include <sstream>

int LuaString::l_base64_decode(lua_State *L)
{
	std::string to_decode = read<std::string>(L, 1);
	write<std::string>(L, base64_decode(to_decode));
	return 1;
}

int LuaString::l_base64_encode(lua_State *L)
{
	std::string to_encode = read<std::string>(L, 1);
	write<std::string>(L, base64_encode(to_encode));
	return 1;
}

int LuaString::l_hmac_sha1(lua_State *L)
{
	std::string key = read<std::string>(L, 1);
	std::string to_hash = read<std::string>(L, 2);
	write<std::string>(L, hmac_sha1(key, to_hash));
}

int LuaString::l_read_json(lua_State *L)
{
	const char *jsonstr = luaL_checkstring(L, 1);

	// Use passed nullvalue or default to nil
	int nullindex = 2;
	if (lua_isnone(L, nullindex)) {
		lua_pushnil(L);
		// nullindex = lua_gettop(L);
	}

	Json::Value root;
	Json::Reader reader;
	std::istringstream stream(jsonstr);

	if (!reader.parse(stream, root)) {
		lua_pushnil(L);
		return 1;
	}

	if (!write<Json::Value>(L, root)) {
		lua_pushnil(L);
	}
	return 1;

}

int LuaString::l_write_json(lua_State *L)
{
	bool styled = false;
	if (!lua_isnone(L, 2)) {
		styled = read<bool>(L, 2);
		lua_pop(L, 1);
	}

	Json::Value root;
	if (!read<Json::Value>(L, 1, root)) {
		lua_pushnil(L);
		lua_pushstring(L, "failed to parse json");
		return 2;
	}

	std::string out;
	if (styled) {
		Json::StyledWriter writer;
		out = writer.write(root);
	} else {
		Json::FastWriter writer;
		out = writer.write(root);
	}
	write<std::string>(L, out);
	return 1;

}

void LuaString::register_functions(LuaEngine *engine, int top)
{
	engine->REGISTER_LUA_FCT(base64_encode);
	engine->REGISTER_LUA_FCT(base64_decode);
	engine->REGISTER_LUA_FCT(hmac_sha1);
	engine->REGISTER_LUA_FCT(read_json);
	engine->REGISTER_LUA_FCT(write_json);
}
<commit_msg>Add missing return on hmac_sha1 function<commit_after>/**
 * Copyright (c) 2017, Loic Blot <loic.blot@unix-experience.fr>
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "l_string.h"
#include <luaengine.h>
#include <utils/base64.h>
#include <utils/hmac.h>
#include <json/json.h>
#include <sstream>

int LuaString::l_base64_decode(lua_State *L)
{
	std::string to_decode = read<std::string>(L, 1);
	write<std::string>(L, base64_decode(to_decode));
	return 1;
}

int LuaString::l_base64_encode(lua_State *L)
{
	std::string to_encode = read<std::string>(L, 1);
	write<std::string>(L, base64_encode(to_encode));
	return 1;
}

int LuaString::l_hmac_sha1(lua_State *L)
{
	std::string key = read<std::string>(L, 1);
	std::string to_hash = read<std::string>(L, 2);
	write<std::string>(L, hmac_sha1(key, to_hash));
	return 1;
}

int LuaString::l_read_json(lua_State *L)
{
	const char *jsonstr = luaL_checkstring(L, 1);

	// Use passed nullvalue or default to nil
	int nullindex = 2;
	if (lua_isnone(L, nullindex)) {
		lua_pushnil(L);
		// nullindex = lua_gettop(L);
	}

	Json::Value root;
	Json::Reader reader;
	std::istringstream stream(jsonstr);

	if (!reader.parse(stream, root)) {
		lua_pushnil(L);
		return 1;
	}

	if (!write<Json::Value>(L, root)) {
		lua_pushnil(L);
	}
	return 1;

}

int LuaString::l_write_json(lua_State *L)
{
	bool styled = false;
	if (!lua_isnone(L, 2)) {
		styled = read<bool>(L, 2);
		lua_pop(L, 1);
	}

	Json::Value root;
	if (!read<Json::Value>(L, 1, root)) {
		lua_pushnil(L);
		lua_pushstring(L, "failed to parse json");
		return 2;
	}

	std::string out;
	if (styled) {
		Json::StyledWriter writer;
		out = writer.write(root);
	} else {
		Json::FastWriter writer;
		out = writer.write(root);
	}
	write<std::string>(L, out);
	return 1;

}

void LuaString::register_functions(LuaEngine *engine, int top)
{
	engine->REGISTER_LUA_FCT(base64_encode);
	engine->REGISTER_LUA_FCT(base64_decode);
	engine->REGISTER_LUA_FCT(hmac_sha1);
	engine->REGISTER_LUA_FCT(read_json);
	engine->REGISTER_LUA_FCT(write_json);
}
<|endoftext|>


<commit_before>#ifndef ITER_ZIP_HPP_
#define ITER_ZIP_HPP_

#include "iterbase.hpp"

#include <iterator>
#include <tuple>
#include <utility>
#include <algorithm>

namespace iter {

    template <typename... Ts>
    void absorb(Ts&&...) { }

    template <typename... RestContainers>
    class Zipped;

    template <typename... Containers>
    Zipped<Containers...> zip(Containers&&...);

    // specialization for at least 1 template argument
    template <typename... Containers>
    class Zipped {
        private:
            std::tuple<Containers...> containers;
            std::make_index_sequence<sizeof...(Containers)> indices;

        public:
            Zipped(Containers... in_containers)
                : containers{std::forward<Containers>(in_containers)...}
            { }

            class Iterator {
                private:
                    std::tuple<iterator_type<Containers>...> iters;
                    std::make_index_sequence<sizeof...(Containers)> indices;

                    bool not_equal(
                            const Iterator&, std::index_sequence<>) const {
                        return false;
                    }

                    template <std::size_t... Is>
                    bool not_equal(const Iterator& other,
                                   std::index_sequence<Is...>) const {
                        bool results[] = { true,
                            (std::get<Is>(this->iters) !=
                             std::get<Is>(other.iters))...
                        };
                        return std::all_of(
                                std::begin(results), std::end(results),
                                [](bool b){ return b; } );
                    }

                    template <std::size_t... Is>
                    void increment(std::index_sequence<Is...>) {
                        absorb(++std::get<Is>(this->iters)...);
                    }

                    template <std::size_t... Is>
                    auto deref(std::index_sequence<Is...>) {
                        return std::tuple<iterator_deref<Containers>...>{
                            (*std::get<Is>(this->iters))...};
                    }

                public:
                    Iterator(iterator_type<Containers>... its)
                        : iters{its...}
                    { }

                    Iterator& operator++() {
                        this->increment(this->indices);
                        return *this;
                    }

                    bool operator!=(const Iterator& other) const {
                        return this->not_equal(other, this->indices);
                    }

                    auto operator*() {
                        return this->deref(this->indices);
                    }
            };
        private:
            template <std::size_t... Is>
            Iterator make_begin(std::index_sequence<Is...>) {
                return {std::begin(std::get<Is>(this->containers))...};
            }

            template <std::size_t... Is>
            Iterator make_end(std::index_sequence<Is...>) {
                return {std::end(std::get<Is>(this->containers))...};
            }

        public:

            Iterator begin() {
                return this->make_begin(this->indices);
            }

            Iterator end() {
                return this->make_end(this->indices);
            }
        };

    template <typename... Containers>
    Zipped<Containers...> zip(Containers&&... containers) {
        return {std::forward<Containers>(containers)...};
    }
}

#endif // #ifndef ITER_ZIP_HPP_
<commit_msg>Simplifies by templating on tuple and Is<commit_after>#ifndef ITER_ZIP_HPP_
#define ITER_ZIP_HPP_

#include "iterbase.hpp"

#include <iterator>
#include <tuple>
#include <utility>
#include <algorithm>

namespace iter {

    template <typename... Ts>
    void absorb(Ts&&...) { }

#if 0
    template <typename... RestContainers>
    class Zipped;

    template <typename... Containers>
    Zipped<Containers...> zip(Containers&&...);
#endif

    // specialization for at least 1 template argument
    template <typename TupType, std::size_t... Is>
    class Zipped {
        private:
            TupType containers;
            using iters_tuple =
                std::tuple<iterator_type<decltype(
                        std::get<Is>(std::declval<TupType>()))>...>;
        public:
            Zipped(TupType&& in_containers)
                : containers(std::move(in_containers))
            { }

            class Iterator {
                private:
                    using iters_tuple =
                        std::tuple<iterator_type<decltype(
                                std::get<Is>(std::declval<TupType>()))>...>;
                    using iters_deref_tuple =
                        std::tuple<iterator_deref<decltype(
                                std::get<Is>(std::declval<TupType>()))>...>;

                    iters_tuple iters;

                public:
                    Iterator(iters_tuple&& its)
                        : iters(std::move(its))
                    { }

                    Iterator& operator++() {
                        absorb(++std::get<Is>(this->iters)...);
                        return *this;
                    }

                    bool operator!=(const Iterator& other) const {
                        if (sizeof...(Is) == 0) return false;

                        bool results[] = { true,
                            (std::get<Is>(this->iters) !=
                                 std::get<Is>(other.iters))...
                        };
                        return std::all_of(
                                std::begin(results), std::end(results),
                                [](bool b){ return b; } );
                    }

                    auto operator*() {
                        return iters_deref_tuple{
                            (*std::get<Is>(this->iters))...};
                    }
            };

            Iterator begin() {
                return iters_tuple{
                    std::begin(std::get<Is>(this->containers))...};
            }

            Iterator end() {
                return iters_tuple{
                    std::end(std::get<Is>(this->containers))...};
            }
    };

    template <typename TupType, std::size_t... Is>
    Zipped<TupType, Is...> zip_impl(
            TupType&& in_containers, std::index_sequence<Is...>) {
        return {std::move(in_containers)};
    }

    template <typename... Containers>
    auto zip(Containers&&... containers) {
        return zip_impl(std::tuple<Containers...>{
            std::forward<Containers>(containers)...},
            std::index_sequence_for<Containers...>{});
    }
}

#endif // #ifndef ITER_ZIP_HPP_
<|endoftext|>


<commit_before>/*
* Copyright (c) 2002-2012, California Institute of Technology.
* All rights reserved.  Based on Government Sponsored Research under contracts NAS7-1407 and/or NAS7-03001.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*   1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*   2. Redistributions in binary form must reproduce the above copyright notice,
*      this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
*   3. Neither the name of the California Institute of Technology (Caltech), its operating division the Jet Propulsion Laboratory (JPL),
*      the National Aeronautics and Space Administration (NASA), nor the names of its contributors may be used to
*      endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE CALIFORNIA INSTITUTE OF TECHNOLOGY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 2014-2015 Esri
*
* 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.
*/

/*
 * $Id$
 * PNG band
 * PNG page compression and decompression functions
 * These functions are not methods, they reside in the global space
 *
 */

#include "marfa.h"
#include <cassert>

CPL_C_START
#include "../png/libpng/png.h"
CPL_C_END

NAMESPACE_MRF_START

//Lucian recommended to change the following three lines to above as
// it is causing trouble compiling for AMNH folks.
//CPL_C_START
//#include <png.h>
//CPL_C_END

// Do Nothing
static void flush_png(png_structp) {}

// Warning Emit
static void pngWH(png_struct * /*png*/, png_const_charp message)
{
    CPLError(CE_Warning, CPLE_AppDefined, "MRF: PNG warning %s", message);
}

// Fatal Warning
static void pngEH(png_struct *png, png_const_charp message)
{
    CPLError(CE_Failure, CPLE_AppDefined, "MRF: PNG Failure %s", message);
    longjmp(png->jmpbuf, 1);
}

// Read memory handlers for PNG
// No check for attempting to read past the end of the buffer

static void read_png(png_structp pngp, png_bytep data, png_size_t length)
{
    buf_mgr *pmgr = (buf_mgr *)png_get_io_ptr(pngp);
    memcpy(data, pmgr->buffer, length);
    pmgr->buffer += length;
    pmgr->size -= length;
}

static void write_png(png_structp pngp, png_bytep data, png_size_t length) {
    buf_mgr *mgr = (buf_mgr *)png_get_io_ptr(pngp);
    // Buffer could be too small, trigger an error on debug mode
    assert(length <= mgr->size);
    memcpy(mgr->buffer, data, length);
    mgr->buffer += length;
    mgr->size -= length;
}

/**
 *\brief In memory decompression of PNG file
 */

CPLErr PNG_Band::DecompressPNG(buf_mgr &dst, buf_mgr &src)
{
    png_bytep *png_rowp;

    // pngp=png_create_read_struct(PNG_LIBPNG_VER_STRING,0,pngEH,pngWH);
    png_structp pngp = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (0 == pngp) {
	CPLError(CE_Failure, CPLE_AppDefined, "MRF: Error creating PNG decompress");
	return CE_Failure;
    }

    png_infop infop = png_create_info_struct(pngp);
    if (0 == infop) {
	if (pngp) png_destroy_read_struct(&pngp, &infop, 0);
	CPLError(CE_Failure, CPLE_AppDefined, "MRF: Error creating PNG info");
	return CE_Failure;
    }

    if (setjmp(png_jmpbuf(pngp))) {
	CPLError(CE_Failure, CPLE_AppDefined, "MRF: Error starting PNG decompress");
	return CE_Failure;
    }

    // The mgr data ptr is already set up
    png_set_read_fn(pngp, &src, read_png);
    // Ready to read
    png_read_info(pngp, infop);
    GInt32 height = static_cast<GInt32>(png_get_image_height(pngp, infop));
    GInt32 byte_count = png_get_bit_depth(pngp, infop) / 8;
    // Check the size
    if (dst.size < (png_get_rowbytes(pngp, infop)*height)) {
	CPLError(CE_Failure, CPLE_AppDefined,
	    "MRF: PNG Page data bigger than the buffer provided");
	png_destroy_read_struct(&pngp, &infop, 0);
	return CE_Failure;
    }

    png_rowp = (png_bytep *)CPLMalloc(sizeof(png_bytep)*height);

    int rowbytes = static_cast<int>(png_get_rowbytes(pngp, infop));
    for (int i = 0; i < height; i++)
	png_rowp[i] = (png_bytep)dst.buffer + i*rowbytes;

    // Finally, the read
    // This is the lower level, the png_read_end allows some transforms
    // Like pallete to RGBA
    png_read_image(pngp, png_rowp);

    if (byte_count != 1) { // Swap from net order if data is short
	for (int i = 0; i < height; i++) {
	    unsigned short int*p = (unsigned short int *)png_rowp[i];
	    for (int j = 0; j < rowbytes / 2; j++, p++)
		*p = net16(*p);
	}
    }

    //    ppmWrite("Test.ppm",(char *)data,ILSize(512,512,1,4,0));
    // Required
    png_read_end(pngp, infop);

    // png_set_rows(pngp,infop,png_rowp);
    // png_read_png(pngp,infop,PNG_TRANSFORM_IDENTITY,0);

    CPLFree(png_rowp);
    png_destroy_read_struct(&pngp, &infop, 0);
    return CE_None;
}

/**
 *\Brief Compres a page in PNG format
 * Returns the compressed size in dst.size
 *
 */

CPLErr PNG_Band::CompressPNG(buf_mgr &dst, buf_mgr &src)

{
    png_structp pngp;
    png_infop infop;
    buf_mgr mgr = dst;

    pngp = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, pngEH, pngWH);
    if (!pngp) {
	CPLError(CE_Failure, CPLE_AppDefined, "MRF: Error creating png structure");
	return CE_Failure;
    }
    infop = png_create_info_struct(pngp);
    if (!infop) {
	png_destroy_write_struct(&pngp, NULL);
	CPLError(CE_Failure, CPLE_AppDefined, "MRF: Error creating png info structure");
	return CE_Failure;
    }

    if (setjmp(png_jmpbuf(pngp))) {
	png_destroy_write_struct(&pngp, &infop);
	CPLError(CE_Failure, CPLE_AppDefined, "MRF: Error during png init");
	return CE_Failure;
    }

    png_set_write_fn(pngp, &mgr, write_png, flush_png);

    int png_ctype;

    switch (img.pagesize.c) {
    case 1: if (PNGColors != NULL) png_ctype = PNG_COLOR_TYPE_PALETTE;
	    else png_ctype = PNG_COLOR_TYPE_GRAY;
	    break;
    case 2: png_ctype = PNG_COLOR_TYPE_GRAY_ALPHA; break;
    case 3: png_ctype = PNG_COLOR_TYPE_RGB; break;
    case 4: png_ctype = PNG_COLOR_TYPE_RGB_ALPHA; break;
    default: { // This never happens if we check at the open
	CPLError(CE_Failure, CPLE_AppDefined, "MRF:PNG Write with %d colors called",
	    img.pagesize.c);
	return CE_Failure;
    }
    }

    png_set_IHDR(pngp, infop, img.pagesize.x, img.pagesize.y,
	GDALGetDataTypeSize(img.dt), png_ctype,
	PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

    // Optional, force certain filters only.  Makes it somewhat faster but worse compression
    // png_set_filter(pngp, PNG_FILTER_TYPE_BASE, PNG_FILTER_SUB);

#if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER > 10200)
    png_uint_32 mask, flags;

    flags = png_get_asm_flags(pngp);
    mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
    png_set_asm_flags(pngp, flags | mask); // use flags &~mask to disable all

    // Test that the MMX is compiled into PNG
    //	fprintf(stderr,"MMX support is %d\n", png_mmx_support());

#endif

    // Let the quality control the compression level
    // Supposedly low numbers work well too while being fast
    png_set_compression_level(pngp, img.quality / 10);

    // Custom strategy for zlib, set using the band option Z_STRATEGY
    if (deflate_flags & ZFLAG_SMASK)
	png_set_compression_strategy(pngp, (deflate_flags & ZFLAG_SMASK) >> 6);

    // Write the palete and the transparencies if they exist
    if (PNGColors != NULL)
    {
	png_set_PLTE(pngp, infop, (png_colorp)PNGColors, PalSize);
	if (TransSize != 0)
	    png_set_tRNS(pngp, infop, (unsigned char*)PNGAlpha, TransSize, NULL);
    }

    png_write_info(pngp, infop);

    png_bytep *png_rowp = (png_bytep *)CPLMalloc(sizeof(png_bytep)*img.pagesize.y);

    if (setjmp(png_jmpbuf(pngp))) {
	CPLFree(png_rowp);
	png_destroy_write_struct(&pngp, &infop);
	CPLError(CE_Failure, CPLE_AppDefined, "MRF: Error during png compression");
	return CE_Failure;
    }

    int rowbytes = static_cast<int>(png_get_rowbytes(pngp, infop));
    for (int i = 0; i < img.pagesize.y; i++) {
	png_rowp[i] = (png_bytep)(src.buffer + i*rowbytes);
	if (img.dt != GDT_Byte) { // Swap to net order if data is short
	    unsigned short int*p = (unsigned short int *)png_rowp[i];
	    for (int j = 0; j < rowbytes / 2; j++, p++) *p = net16(*p);
	}
    }

    png_write_image(pngp, png_rowp);
    png_write_end(pngp, infop);

    // Done
    CPLFree(png_rowp);
    png_destroy_write_struct(&pngp, &infop);

    // Done
    // mgr.size holds the available bytes, so the size of the compressed png
    // is the original destination size minus the still available bytes
    dst.size -= mgr.size;

    return CE_None;
}

CPLErr PNG_Band::Decompress(buf_mgr &dst, buf_mgr &src)
{
    return DecompressPNG(dst, src);
}

// The PNG internal palette is set on first band write
CPLErr PNG_Band::Compress(buf_mgr &dst, buf_mgr &src)
{   // Late set palette
    if (img.comp == IL_PPNG && !PNGColors && ResetPalette() != CE_None)
	return CE_Failure;
    return CompressPNG(dst, src);
}

CPLErr PNG_Band::ResetPalette()
{   // Convert the GDAL LUT to PNG style
    GDALColorTable *poCT = GetColorTable();

    if (!poCT) {
	CPLError(CE_Failure, CPLE_NotSupported, "MRF PPNG needs a color table");
	return CE_Failure;
    }

    TransSize = PalSize = poCT->GetColorEntryCount();

    png_color *pasPNGColors = (png_color *)CPLMalloc(sizeof(png_color) * PalSize);
    unsigned char *pabyAlpha = (unsigned char *)CPLMalloc(TransSize);
    PNGColors = (void *)pasPNGColors;
    PNGAlpha = (void *)pabyAlpha;
    bool NoTranspYet = true;

    // Set the palette from the end to reduce the size of the opacity mask
    for (int iColor = PalSize - 1; iColor >= 0; iColor--)
    {
	GDALColorEntry  sEntry;
	poCT->GetColorEntryAsRGB(iColor, &sEntry);

	pasPNGColors[iColor].red = (png_byte)sEntry.c1;
	pasPNGColors[iColor].green = (png_byte)sEntry.c2;
	pasPNGColors[iColor].blue = (png_byte)sEntry.c3;
	if (NoTranspYet && sEntry.c4 == 255)
	    TransSize--;
	else {
	    NoTranspYet = false;
	    pabyAlpha[iColor] = (unsigned char)sEntry.c4;
	}
    }

    return CE_None;
}

/**
 * \Brief For PPNG, builds the data structures needed to write the palette
 * The presence of the PNGColors and PNGAlpha is used as a flag for PPNG only
 */

PNG_Band::PNG_Band(GDALMRFDataset *pDS, const ILImage &image, int b, int level) :
GDALMRFRasterBand(pDS, image, b, level), PNGColors(NULL), PNGAlpha(NULL)

{   // Check error conditions
    if (image.dt != GDT_Byte && image.dt != GDT_Int16 && image.dt != GDT_UInt16) {
	CPLError(CE_Failure, CPLE_NotSupported, "Data type not supported by MRF PNG");
	return;
    }
    if (image.pagesize.c > 4) {
	CPLError(CE_Failure, CPLE_NotSupported, "MRF PNG can only handle up to 4 bands per page");
	return;
    }
}

PNG_Band::~PNG_Band() {
    CPLFree(PNGColors);
    CPLFree(PNGAlpha);
}

NAMESPACE_MRF_END
<commit_msg>GDAL integration #32<commit_after>/*
* Copyright (c) 2002-2012, California Institute of Technology.
* All rights reserved.  Based on Government Sponsored Research under contracts NAS7-1407 and/or NAS7-03001.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*   1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*   2. Redistributions in binary form must reproduce the above copyright notice,
*      this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
*   3. Neither the name of the California Institute of Technology (Caltech), its operating division the Jet Propulsion Laboratory (JPL),
*      the National Aeronautics and Space Administration (NASA), nor the names of its contributors may be used to
*      endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE CALIFORNIA INSTITUTE OF TECHNOLOGY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 2014-2015 Esri
*
* 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.
*/

/*
 * $Id$
 * PNG band
 * PNG page compression and decompression functions
 * These functions are not methods, they reside in the global space
 *
 */

#include "marfa.h"
#include <cassert>

CPL_C_START
#include "../png/libpng/png.h"
CPL_C_END

NAMESPACE_MRF_START

//Lucian recommended to change the following three lines to above as
// it is causing trouble compiling for AMNH folks.
//CPL_C_START
//#include <png.h>
//CPL_C_END

// Do Nothing
static void flush_png(png_structp) {}

// Warning Emit
static void pngWH(png_struct * /*png*/, png_const_charp message)
{
    CPLError(CE_Warning, CPLE_AppDefined, "MRF: PNG warning %s", message);
}

// Fatal Warning
static void pngEH(png_struct *png, png_const_charp message)
{
    CPLError(CE_Failure, CPLE_AppDefined, "MRF: PNG Failure %s", message);
    longjmp(png->jmpbuf, 1);
}

// Read memory handlers for PNG
// No check for attempting to read past the end of the buffer

static void read_png(png_structp pngp, png_bytep data, png_size_t length)
{
    buf_mgr *pmgr = (buf_mgr *)png_get_io_ptr(pngp);
    memcpy(data, pmgr->buffer, length);
    pmgr->buffer += length;
    pmgr->size -= length;
}

static void write_png(png_structp pngp, png_bytep data, png_size_t length) {
    buf_mgr *mgr = (buf_mgr *)png_get_io_ptr(pngp);
    // Buffer could be too small, trigger an error on debug mode
    assert(length <= mgr->size);
    memcpy(mgr->buffer, data, length);
    mgr->buffer += length;
    mgr->size -= length;
}

/**
 *\brief In memory decompression of PNG file
 */

CPLErr PNG_Band::DecompressPNG(buf_mgr &dst, buf_mgr &src)
{
    png_bytep *png_rowp;

    // pngp=png_create_read_struct(PNG_LIBPNG_VER_STRING,0,pngEH,pngWH);
    png_structp pngp = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (0 == pngp) {
	CPLError(CE_Failure, CPLE_AppDefined, "MRF: Error creating PNG decompress");
	return CE_Failure;
    }

    png_infop infop = png_create_info_struct(pngp);
    if (0 == infop) {
	if (pngp) png_destroy_read_struct(&pngp, &infop, 0);
	CPLError(CE_Failure, CPLE_AppDefined, "MRF: Error creating PNG info");
	return CE_Failure;
    }

    if (setjmp(png_jmpbuf(pngp))) {
	CPLError(CE_Failure, CPLE_AppDefined, "MRF: Error starting PNG decompress");
	return CE_Failure;
    }

    // The mgr data ptr is already set up
    png_set_read_fn(pngp, &src, read_png);
    // Ready to read
    png_read_info(pngp, infop);
    GInt32 height = static_cast<GInt32>(png_get_image_height(pngp, infop));
    GInt32 byte_count = png_get_bit_depth(pngp, infop) / 8;
    // Check the size
    if (dst.size < (png_get_rowbytes(pngp, infop)*height)) {
	CPLError(CE_Failure, CPLE_AppDefined,
	    "MRF: PNG Page data bigger than the buffer provided");
	png_destroy_read_struct(&pngp, &infop, 0);
	return CE_Failure;
    }

    png_rowp = (png_bytep *)CPLMalloc(sizeof(png_bytep)*height);

    int rowbytes = static_cast<int>(png_get_rowbytes(pngp, infop));
    for (int i = 0; i < height; i++)
	png_rowp[i] = (png_bytep)dst.buffer + i*rowbytes;

    // Finally, the read
    // This is the lower level, the png_read_end allows some transforms
    // Like pallete to RGBA
    png_read_image(pngp, png_rowp);

    if (byte_count != 1) { // Swap from net order if data is short
	for (int i = 0; i < height; i++) {
	    unsigned short int*p = (unsigned short int *)png_rowp[i];
	    for (int j = 0; j < rowbytes / 2; j++, p++)
		*p = net16(*p);
	}
    }

    //    ppmWrite("Test.ppm",(char *)data,ILSize(512,512,1,4,0));
    // Required
    png_read_end(pngp, infop);

    // png_set_rows(pngp,infop,png_rowp);
    // png_read_png(pngp,infop,PNG_TRANSFORM_IDENTITY,0);

    CPLFree(png_rowp);
    png_destroy_read_struct(&pngp, &infop, 0);
    return CE_None;
}

/**
 *\Brief Compres a page in PNG format
 * Returns the compressed size in dst.size
 *
 */

CPLErr PNG_Band::CompressPNG(buf_mgr &dst, buf_mgr &src)

{
    png_structp pngp;
    png_infop infop;
    buf_mgr mgr = dst;

    pngp = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, pngEH, pngWH);
    if (!pngp) {
	CPLError(CE_Failure, CPLE_AppDefined, "MRF: Error creating png structure");
	return CE_Failure;
    }
    infop = png_create_info_struct(pngp);
    if (!infop) {
	png_destroy_write_struct(&pngp, NULL);
	CPLError(CE_Failure, CPLE_AppDefined, "MRF: Error creating png info structure");
	return CE_Failure;
    }

    if (setjmp(png_jmpbuf(pngp))) {
	png_destroy_write_struct(&pngp, &infop);
	CPLError(CE_Failure, CPLE_AppDefined, "MRF: Error during png init");
	return CE_Failure;
    }

    png_set_write_fn(pngp, &mgr, write_png, flush_png);

    int png_ctype;

    switch (img.pagesize.c) {
    case 1: if (PNGColors != NULL) png_ctype = PNG_COLOR_TYPE_PALETTE;
	    else png_ctype = PNG_COLOR_TYPE_GRAY;
	    break;
    case 2: png_ctype = PNG_COLOR_TYPE_GRAY_ALPHA; break;
    case 3: png_ctype = PNG_COLOR_TYPE_RGB; break;
    case 4: png_ctype = PNG_COLOR_TYPE_RGB_ALPHA; break;
    default: { // This never happens if we check at the open
	CPLError(CE_Failure, CPLE_AppDefined, "MRF:PNG Write with %d colors called",
	    img.pagesize.c);
	return CE_Failure;
    }
    }

    png_set_IHDR(pngp, infop, img.pagesize.x, img.pagesize.y,
	GDALGetDataTypeSize(img.dt), png_ctype,
	PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

    // Optional, force certain filters only.  Makes it somewhat faster but worse compression
    // png_set_filter(pngp, PNG_FILTER_TYPE_BASE, PNG_FILTER_SUB);

#if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER > 10200) && defined(PNG_SELECT_READ)
    png_uint_32 mask, flags;

    flags = png_get_asm_flags(pngp);
    mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
    png_set_asm_flags(pngp, flags | mask); // use flags &~mask to disable all

    // Test that the MMX is compiled into PNG
    //	fprintf(stderr,"MMX support is %d\n", png_mmx_support());

#endif

    // Let the quality control the compression level
    // Supposedly low numbers work well too while being fast
    png_set_compression_level(pngp, img.quality / 10);

    // Custom strategy for zlib, set using the band option Z_STRATEGY
    if (deflate_flags & ZFLAG_SMASK)
	png_set_compression_strategy(pngp, (deflate_flags & ZFLAG_SMASK) >> 6);

    // Write the palete and the transparencies if they exist
    if (PNGColors != NULL)
    {
	png_set_PLTE(pngp, infop, (png_colorp)PNGColors, PalSize);
	if (TransSize != 0)
	    png_set_tRNS(pngp, infop, (unsigned char*)PNGAlpha, TransSize, NULL);
    }

    png_write_info(pngp, infop);

    png_bytep *png_rowp = (png_bytep *)CPLMalloc(sizeof(png_bytep)*img.pagesize.y);

    if (setjmp(png_jmpbuf(pngp))) {
	CPLFree(png_rowp);
	png_destroy_write_struct(&pngp, &infop);
	CPLError(CE_Failure, CPLE_AppDefined, "MRF: Error during png compression");
	return CE_Failure;
    }

    int rowbytes = static_cast<int>(png_get_rowbytes(pngp, infop));
    for (int i = 0; i < img.pagesize.y; i++) {
	png_rowp[i] = (png_bytep)(src.buffer + i*rowbytes);
	if (img.dt != GDT_Byte) { // Swap to net order if data is short
	    unsigned short int*p = (unsigned short int *)png_rowp[i];
	    for (int j = 0; j < rowbytes / 2; j++, p++) *p = net16(*p);
	}
    }

    png_write_image(pngp, png_rowp);
    png_write_end(pngp, infop);

    // Done
    CPLFree(png_rowp);
    png_destroy_write_struct(&pngp, &infop);

    // Done
    // mgr.size holds the available bytes, so the size of the compressed png
    // is the original destination size minus the still available bytes
    dst.size -= mgr.size;

    return CE_None;
}

CPLErr PNG_Band::Decompress(buf_mgr &dst, buf_mgr &src)
{
    return DecompressPNG(dst, src);
}

// The PNG internal palette is set on first band write
CPLErr PNG_Band::Compress(buf_mgr &dst, buf_mgr &src)
{   // Late set palette
    if (img.comp == IL_PPNG && !PNGColors && ResetPalette() != CE_None)
	return CE_Failure;
    return CompressPNG(dst, src);
}

CPLErr PNG_Band::ResetPalette()
{   // Convert the GDAL LUT to PNG style
    GDALColorTable *poCT = GetColorTable();

    if (!poCT) {
	CPLError(CE_Failure, CPLE_NotSupported, "MRF PPNG needs a color table");
	return CE_Failure;
    }

    TransSize = PalSize = poCT->GetColorEntryCount();

    png_color *pasPNGColors = (png_color *)CPLMalloc(sizeof(png_color) * PalSize);
    unsigned char *pabyAlpha = (unsigned char *)CPLMalloc(TransSize);
    PNGColors = (void *)pasPNGColors;
    PNGAlpha = (void *)pabyAlpha;
    bool NoTranspYet = true;

    // Set the palette from the end to reduce the size of the opacity mask
    for (int iColor = PalSize - 1; iColor >= 0; iColor--)
    {
	GDALColorEntry  sEntry;
	poCT->GetColorEntryAsRGB(iColor, &sEntry);

	pasPNGColors[iColor].red = (png_byte)sEntry.c1;
	pasPNGColors[iColor].green = (png_byte)sEntry.c2;
	pasPNGColors[iColor].blue = (png_byte)sEntry.c3;
	if (NoTranspYet && sEntry.c4 == 255)
	    TransSize--;
	else {
	    NoTranspYet = false;
	    pabyAlpha[iColor] = (unsigned char)sEntry.c4;
	}
    }

    return CE_None;
}

/**
 * \Brief For PPNG, builds the data structures needed to write the palette
 * The presence of the PNGColors and PNGAlpha is used as a flag for PPNG only
 */

PNG_Band::PNG_Band(GDALMRFDataset *pDS, const ILImage &image, int b, int level) :
GDALMRFRasterBand(pDS, image, b, level), PNGColors(NULL), PNGAlpha(NULL)

{   // Check error conditions
    if (image.dt != GDT_Byte && image.dt != GDT_Int16 && image.dt != GDT_UInt16) {
	CPLError(CE_Failure, CPLE_NotSupported, "Data type not supported by MRF PNG");
	return;
    }
    if (image.pagesize.c > 4) {
	CPLError(CE_Failure, CPLE_NotSupported, "MRF PNG can only handle up to 4 bands per page");
	return;
    }
}

PNG_Band::~PNG_Band() {
    CPLFree(PNGColors);
    CPLFree(PNGAlpha);
}

NAMESPACE_MRF_END
<|endoftext|>


<commit_before>#include "utils.hpp"
#include "mapnik_query.hpp"

#include <boost/make_shared.hpp>

Persistent<FunctionTemplate> Query::constructor;

void Query::Initialize(Handle<Object> target) {

    HandleScope scope;

    constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(Query::New));
    constructor->InstanceTemplate()->SetInternalFieldCount(1);
    constructor->SetClassName(String::NewSymbol("Query"));

    target->Set(String::NewSymbol("Query"),constructor->GetFunction());
}

Query::Query(mapnik::box2d<double> const& box) :
    ObjectWrap(),
    this_(boost::make_shared<mapnik::query>(box)) {}

Query::~Query()
{
}

Handle<Value> Query::New(const Arguments& args)
{
    HandleScope scope;
}
<commit_msg>avoid compiler warning<commit_after>#include "utils.hpp"
#include "mapnik_query.hpp"

#include <boost/make_shared.hpp>

Persistent<FunctionTemplate> Query::constructor;

void Query::Initialize(Handle<Object> target) {

    HandleScope scope;

    constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(Query::New));
    constructor->InstanceTemplate()->SetInternalFieldCount(1);
    constructor->SetClassName(String::NewSymbol("Query"));

    target->Set(String::NewSymbol("Query"),constructor->GetFunction());
}

Query::Query(mapnik::box2d<double> const& box) :
    ObjectWrap(),
    this_(boost::make_shared<mapnik::query>(box)) {}

Query::~Query()
{
}

Handle<Value> Query::New(const Arguments& args)
{
    HandleScope scope;
    // TODO - implement this
    return Undefined();
}
<|endoftext|>