<commit_before>//
// SqratImport: Supports importing of squirrel modules
//

//
// Copyright (c) 2009 Brandon Jones
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
//  1. The origin of this software must not be misrepresented; you must not
//  claim that you wrote the original software. If you use this software
//  in a product, an acknowledgment in the product documentation would be
//  appreciated but is not required.
//
//  2. Altered source versions must be plainly marked as such, and must not be
//  misrepresented as being the original software.
//
//  3. This notice may not be removed or altered from any source
//  distribution.
//

#include "sqimport.h"
#include "sqmodule.h"

//#include "sqratlib/sqratBase.h"
#include <sqstdio.h>
#include <string>
// getenv
#include <stdlib.h>

#if defined(_WIN32)

#include <windows.h>

#elif defined(__unix)

#include <dlfcn.h>

#endif

typedef SQRESULT (*SQMODULELOAD)(HSQUIRRELVM v, HSQAPI sq);

static HSQAPI sqapi = NULL;

// Create and populate the HSQAPI structure with function pointers
// If new functions are added to the Squirrel API, they should be added here too
static HSQAPI sqrat_newapi() {
    HSQAPI sq = (HSQAPI)sq_malloc(sizeof(sq_api));

    /*vm*/
    sq->open = sq_open;
    sq->newthread = sq_newthread;
    sq->seterrorhandler = sq_seterrorhandler;
    sq->close = sq_close;
    sq->setforeignptr = sq_setforeignptr;
    sq->getforeignptr = sq_getforeignptr;
    sq->setprintfunc = sq_setprintfunc;
    sq->getprintfunc = sq_getprintfunc;
    sq->suspendvm = sq_suspendvm;
    sq->wakeupvm = sq_wakeupvm;
    sq->getvmstate = sq_getvmstate;

    /*compiler*/
    sq->compile = sq_compile;
    sq->compilebuffer = sq_compilebuffer;
    sq->enabledebuginfo = sq_enabledebuginfo;
    sq->notifyallexceptions = sq_notifyallexceptions;
    sq->setcompilererrorhandler = sq_setcompilererrorhandler;

    /*stack operations*/
    sq->push = sq_push;
    sq->pop = sq_pop;
    sq->poptop = sq_poptop;
    sq->remove = sq_remove;
    sq->gettop = sq_gettop;
    sq->settop = sq_settop;
    sq->reservestack = sq_reservestack;
    sq->cmp = sq_cmp;
    sq->move = sq_move;

    /*object creation handling*/
    sq->newuserdata = sq_newuserdata;
    sq->newtable = sq_newtable;
    sq->newarray = sq_newarray;
    sq->newclosure = sq_newclosure;
    sq->setparamscheck = sq_setparamscheck;
    sq->bindenv = sq_bindenv;
    sq->pushstring = sq_pushstring;
    sq->pushfloat = sq_pushfloat;
    sq->pushinteger = sq_pushinteger;
    sq->pushbool = sq_pushbool;
    sq->pushuserpointer = sq_pushuserpointer;
    sq->pushnull = sq_pushnull;
    sq->gettype = sq_gettype;
    sq->getsize = sq_getsize;
    sq->getbase = sq_getbase;
    sq->instanceof = sq_instanceof;
    sq->tostring = sq_tostring;
    sq->tobool = sq_tobool;
    sq->getstring = sq_getstring;
    sq->getinteger = sq_getinteger;
    sq->getthread = sq_getthread;
    sq->getbool = sq_getbool;
    sq->getuserpointer = sq_getuserpointer;
    sq->getuserdata = sq_getuserdata;
    sq->settypetag = sq_settypetag;
    sq->gettypetag = sq_gettypetag;
    sq->setreleasehook = sq_setreleasehook;
    sq->getscratchpad = sq_getscratchpad;
    sq->getclosureinfo = sq_getclosureinfo;
    sq->setnativeclosurename = sq_setnativeclosurename;
    sq->setinstanceup = sq_setinstanceup;
    sq->getinstanceup = sq_getinstanceup;
    sq->setclassudsize = sq_setclassudsize;
    sq->newclass = sq_newclass;
    sq->createinstance = sq_createinstance;
    sq->setattributes = sq_setattributes;
    sq->getattributes = sq_getattributes;
    sq->getclass = sq_getclass;
    sq->weakref = sq_weakref;
    sq->getdefaultdelegate = sq_getdefaultdelegate;

    /*object manipulation*/
    sq->pushroottable = sq_pushroottable;
    sq->pushregistrytable = sq_pushregistrytable;
    sq->pushconsttable = sq_pushconsttable;
    sq->setroottable = sq_setroottable;
    sq->setconsttable = sq_setconsttable;
    sq->newslot = sq_newslot;
    sq->deleteslot = sq_deleteslot;
    sq->set = sq_set;
    sq->get = sq_get;
    sq->rawset = sq_rawset;
    sq->rawget = sq_rawget;
    sq->rawdeleteslot = sq_rawdeleteslot;
    sq->arrayappend = sq_arrayappend;
    sq->arraypop = sq_arraypop;
    sq->arrayresize = sq_arrayresize;
    sq->arrayreverse = sq_arrayreverse;
    sq->arrayremove = sq_arrayremove;
    sq->arrayinsert = sq_arrayinsert;
    sq->setdelegate = sq_setdelegate;
    sq->getdelegate = sq_getdelegate;
    sq->clone = sq_clone;
    sq->setfreevariable = sq_setfreevariable;
    sq->next = sq_next;
    sq->getweakrefval = sq_getweakrefval;
    sq->clear = sq_clear;

    /*calls*/
    sq->call = sq_call;
    sq->resume = sq_resume;
    sq->getlocal = sq_getlocal;
    sq->getfreevariable = sq_getfreevariable;
    sq->throwerror = sq_throwerror;
    sq->reseterror = sq_reseterror;
    sq->getlasterror = sq_getlasterror;

    /*raw object handling*/
    sq->getstackobj = sq_getstackobj;
    sq->pushobject = sq_pushobject;
    sq->addref = sq_addref;
    sq->release = sq_release;
    sq->resetobject = sq_resetobject;
    sq->objtostring = sq_objtostring;
    sq->objtobool = sq_objtobool;
    sq->objtointeger = sq_objtointeger;
    sq->objtofloat = sq_objtofloat;
    sq->getobjtypetag = sq_getobjtypetag;

    /*GC*/
    sq->collectgarbage = sq_collectgarbage;

    /*serialization*/
    sq->writeclosure = sq_writeclosure;
    sq->readclosure = sq_readclosure;

    /*mem allocation*/
    sq->malloc = sq_malloc;
    sq->realloc = sq_realloc;
    sq->free = sq_free;

    /*debug*/
    sq->stackinfos = sq_stackinfos;
    sq->setdebughook = sq_setdebughook;

    return sq;
}

static SQRESULT sqrat_importscript(HSQUIRRELVM v, const SQChar* filename) {
    if(SQ_FAILED(sqstd_loadfile(v, filename, true))) {
        return SQ_ERROR;
    }
    sq_push(v, -2);
    sq_call(v, 1, false, true);
    return SQ_OK;
}

static SQRESULT sqrat_importbin(HSQUIRRELVM v, const SQChar* moduleName) {
#ifdef SQUNICODE
#warning sqrat_importbin() Not Implemented
    return SQ_ERROR;
#else
    SQMODULELOAD modLoad = 0;

#if defined(_WIN32)
    HMODULE mod;
    mod = GetModuleHandle(moduleName);
    if(mod == NULL) {
        mod = LoadLibrary(moduleName);
        if(mod == NULL) {
            return SQ_ERROR;
        }
    }

    modLoad = (SQMODULELOAD)GetProcAddress(mod, "sqmodule_load");
    if(modLoad == NULL) {
        FreeLibrary(mod);
        return SQ_ERROR;
    }
#elif defined(__unix)
    /* adding .so to moduleName? */
    void *mod = dlopen(moduleName, RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD); //RTLD_NOLOAD flag is not specified in POSIX.1-2001..so not the best solution :(
    if (mod == NULL) {
        mod = dlopen(moduleName, RTLD_NOW | RTLD_LOCAL);
        if (mod == NULL)
            return SQ_ERROR;
    }
    modLoad = (SQMODULELOAD) dlsym(mod, "sqmodule_load");
    if (modLoad == NULL) {
        dlclose(mod);
        return SQ_ERROR;
    }
#endif

    if(sqapi == NULL) {
        sqapi = sqrat_newapi(); // Caching this for multiple imports is probably a very good idea
    }

    SQRESULT res = modLoad(v, sqapi);

    return res;
#endif
}

bool file_exists(const SQChar* filename)
{
    return access(filename, F_OK) == 0;
}

#define NOT_FOUND 100

SQRESULT try_import_path(HSQUIRRELVM v, std::basic_string<SQChar>& fname)
{
    // Try to import module at given path. This tries
    // different module types in order.

    // Check binary module
    fname[fname.size() - 1] = 'd';
    if (file_exists(fname.c_str()))
        return sqrat_importbin(v, fname.c_str());
    // Check bytecode module
    fname[fname.size() - 1] = 'c';
    if (file_exists(fname.c_str()))
        return sqrat_importscript(v, fname.c_str());
    // Check source module
    fname[fname.size() - 1] = 't';
    if (file_exists(fname.c_str()))
        return sqrat_importscript(v, fname.c_str());

    return NOT_FOUND;
}

SQRESULT sqrat_import(HSQUIRRELVM v) {
    const SQChar* moduleName;
    HSQOBJECT table;
    SQRESULT res = SQ_OK;

    sq_getstring(v, -2, &moduleName);
    sq_getstackobj(v, -1, &table);
    sq_addref(v, &table);

    sq_settop(v, 0); // Clear Stack
    sq_pushobject(v, table); // Push the target table onto the stack

    std::basic_string<SQChar> fname;
    // Explicit path is needed for dlopen() later, and won't hurt
    // for other cases
    fname = "./";
    fname += moduleName;
    fname += ".nut";
    res = try_import_path(v, fname);
    if (res == NOT_FOUND) {
        const char *path = getenv("SQPATH");
        if (path)
            fname = path;
        else {
            path = getenv("HOME");
            if (path) {
                fname = path;
                fname += "/.squirrel/lib";
            } else {
                fname = "/usr/lib/squirrel";
            }
        }
        fname += "/";
        fname += moduleName;
        fname += ".nut";
        res = try_import_path(v, fname);
        if (res == NOT_FOUND)
            res = SQ_ERROR;
    }

    sq_settop(v, 0); // Clean up the stack (just in case the module load leaves it messy)
    sq_pushobject(v, table); // return the target table
    sq_release(v, &table);

    return res;
}

static SQInteger sqratbase_import(HSQUIRRELVM v) {
    SQInteger args = sq_gettop(v);
    switch(args) {
    case 2:
        sq_pushroottable(v);
        break;
    case 3:
        // should already have the desired table pushed onto the stack
        break;
    default:
        // Error, unexpected number of arguments
        break;
    }

    sqrat_import(v);

    return 1;
}

SQRESULT sqrat_register_importlib(HSQUIRRELVM v) {
    sq_pushroottable(v);

    sq_pushstring(v, _SC("_import_"), -1);
    sq_newclosure(v, &sqratbase_import, 0);
    sq_newslot(v, -3, 0);

    sq_pop(v, 1); // pop sqrat table

    return SQ_OK;
}
<commit_msg>Properly handle module not found condition (throw exception).<commit_after>//
// SqratImport: Supports importing of squirrel modules
//

//
// Copyright (c) 2009 Brandon Jones
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
//  1. The origin of this software must not be misrepresented; you must not
//  claim that you wrote the original software. If you use this software
//  in a product, an acknowledgment in the product documentation would be
//  appreciated but is not required.
//
//  2. Altered source versions must be plainly marked as such, and must not be
//  misrepresented as being the original software.
//
//  3. This notice may not be removed or altered from any source
//  distribution.
//

#include "sqimport.h"
#include "sqmodule.h"

//#include "sqratlib/sqratBase.h"
#include <sqstdio.h>
#include <string>
// getenv
#include <stdlib.h>

#if defined(_WIN32)

#include <windows.h>

#elif defined(__unix)

#include <dlfcn.h>

#endif

typedef SQRESULT (*SQMODULELOAD)(HSQUIRRELVM v, HSQAPI sq);

static HSQAPI sqapi = NULL;

// Create and populate the HSQAPI structure with function pointers
// If new functions are added to the Squirrel API, they should be added here too
static HSQAPI sqrat_newapi() {
    HSQAPI sq = (HSQAPI)sq_malloc(sizeof(sq_api));

    /*vm*/
    sq->open = sq_open;
    sq->newthread = sq_newthread;
    sq->seterrorhandler = sq_seterrorhandler;
    sq->close = sq_close;
    sq->setforeignptr = sq_setforeignptr;
    sq->getforeignptr = sq_getforeignptr;
    sq->setprintfunc = sq_setprintfunc;
    sq->getprintfunc = sq_getprintfunc;
    sq->suspendvm = sq_suspendvm;
    sq->wakeupvm = sq_wakeupvm;
    sq->getvmstate = sq_getvmstate;

    /*compiler*/
    sq->compile = sq_compile;
    sq->compilebuffer = sq_compilebuffer;
    sq->enabledebuginfo = sq_enabledebuginfo;
    sq->notifyallexceptions = sq_notifyallexceptions;
    sq->setcompilererrorhandler = sq_setcompilererrorhandler;

    /*stack operations*/
    sq->push = sq_push;
    sq->pop = sq_pop;
    sq->poptop = sq_poptop;
    sq->remove = sq_remove;
    sq->gettop = sq_gettop;
    sq->settop = sq_settop;
    sq->reservestack = sq_reservestack;
    sq->cmp = sq_cmp;
    sq->move = sq_move;

    /*object creation handling*/
    sq->newuserdata = sq_newuserdata;
    sq->newtable = sq_newtable;
    sq->newarray = sq_newarray;
    sq->newclosure = sq_newclosure;
    sq->setparamscheck = sq_setparamscheck;
    sq->bindenv = sq_bindenv;
    sq->pushstring = sq_pushstring;
    sq->pushfloat = sq_pushfloat;
    sq->pushinteger = sq_pushinteger;
    sq->pushbool = sq_pushbool;
    sq->pushuserpointer = sq_pushuserpointer;
    sq->pushnull = sq_pushnull;
    sq->gettype = sq_gettype;
    sq->getsize = sq_getsize;
    sq->getbase = sq_getbase;
    sq->instanceof = sq_instanceof;
    sq->tostring = sq_tostring;
    sq->tobool = sq_tobool;
    sq->getstring = sq_getstring;
    sq->getinteger = sq_getinteger;
    sq->getthread = sq_getthread;
    sq->getbool = sq_getbool;
    sq->getuserpointer = sq_getuserpointer;
    sq->getuserdata = sq_getuserdata;
    sq->settypetag = sq_settypetag;
    sq->gettypetag = sq_gettypetag;
    sq->setreleasehook = sq_setreleasehook;
    sq->getscratchpad = sq_getscratchpad;
    sq->getclosureinfo = sq_getclosureinfo;
    sq->setnativeclosurename = sq_setnativeclosurename;
    sq->setinstanceup = sq_setinstanceup;
    sq->getinstanceup = sq_getinstanceup;
    sq->setclassudsize = sq_setclassudsize;
    sq->newclass = sq_newclass;
    sq->createinstance = sq_createinstance;
    sq->setattributes = sq_setattributes;
    sq->getattributes = sq_getattributes;
    sq->getclass = sq_getclass;
    sq->weakref = sq_weakref;
    sq->getdefaultdelegate = sq_getdefaultdelegate;

    /*object manipulation*/
    sq->pushroottable = sq_pushroottable;
    sq->pushregistrytable = sq_pushregistrytable;
    sq->pushconsttable = sq_pushconsttable;
    sq->setroottable = sq_setroottable;
    sq->setconsttable = sq_setconsttable;
    sq->newslot = sq_newslot;
    sq->deleteslot = sq_deleteslot;
    sq->set = sq_set;
    sq->get = sq_get;
    sq->rawset = sq_rawset;
    sq->rawget = sq_rawget;
    sq->rawdeleteslot = sq_rawdeleteslot;
    sq->arrayappend = sq_arrayappend;
    sq->arraypop = sq_arraypop;
    sq->arrayresize = sq_arrayresize;
    sq->arrayreverse = sq_arrayreverse;
    sq->arrayremove = sq_arrayremove;
    sq->arrayinsert = sq_arrayinsert;
    sq->setdelegate = sq_setdelegate;
    sq->getdelegate = sq_getdelegate;
    sq->clone = sq_clone;
    sq->setfreevariable = sq_setfreevariable;
    sq->next = sq_next;
    sq->getweakrefval = sq_getweakrefval;
    sq->clear = sq_clear;

    /*calls*/
    sq->call = sq_call;
    sq->resume = sq_resume;
    sq->getlocal = sq_getlocal;
    sq->getfreevariable = sq_getfreevariable;
    sq->throwerror = sq_throwerror;
    sq->reseterror = sq_reseterror;
    sq->getlasterror = sq_getlasterror;

    /*raw object handling*/
    sq->getstackobj = sq_getstackobj;
    sq->pushobject = sq_pushobject;
    sq->addref = sq_addref;
    sq->release = sq_release;
    sq->resetobject = sq_resetobject;
    sq->objtostring = sq_objtostring;
    sq->objtobool = sq_objtobool;
    sq->objtointeger = sq_objtointeger;
    sq->objtofloat = sq_objtofloat;
    sq->getobjtypetag = sq_getobjtypetag;

    /*GC*/
    sq->collectgarbage = sq_collectgarbage;

    /*serialization*/
    sq->writeclosure = sq_writeclosure;
    sq->readclosure = sq_readclosure;

    /*mem allocation*/
    sq->malloc = sq_malloc;
    sq->realloc = sq_realloc;
    sq->free = sq_free;

    /*debug*/
    sq->stackinfos = sq_stackinfos;
    sq->setdebughook = sq_setdebughook;

    return sq;
}

static SQRESULT sqrat_importscript(HSQUIRRELVM v, const SQChar* filename) {
    if(SQ_FAILED(sqstd_loadfile(v, filename, true))) {
        return SQ_ERROR;
    }
    sq_push(v, -2);
    sq_call(v, 1, false, true);
    return SQ_OK;
}

static SQRESULT sqrat_importbin(HSQUIRRELVM v, const SQChar* moduleName) {
#ifdef SQUNICODE
#warning sqrat_importbin() Not Implemented
    return SQ_ERROR;
#else
    SQMODULELOAD modLoad = 0;

#if defined(_WIN32)
    HMODULE mod;
    mod = GetModuleHandle(moduleName);
    if(mod == NULL) {
        mod = LoadLibrary(moduleName);
        if(mod == NULL) {
            return SQ_ERROR;
        }
    }

    modLoad = (SQMODULELOAD)GetProcAddress(mod, "sqmodule_load");
    if(modLoad == NULL) {
        FreeLibrary(mod);
        return SQ_ERROR;
    }
#elif defined(__unix)
    /* adding .so to moduleName? */
    void *mod = dlopen(moduleName, RTLD_NOW | RTLD_LOCAL | RTLD_NOLOAD); //RTLD_NOLOAD flag is not specified in POSIX.1-2001..so not the best solution :(
    if (mod == NULL) {
        mod = dlopen(moduleName, RTLD_NOW | RTLD_LOCAL);
        if (mod == NULL)
            return SQ_ERROR;
    }
    modLoad = (SQMODULELOAD) dlsym(mod, "sqmodule_load");
    if (modLoad == NULL) {
        dlclose(mod);
        return SQ_ERROR;
    }
#endif

    if(sqapi == NULL) {
        sqapi = sqrat_newapi(); // Caching this for multiple imports is probably a very good idea
    }

    SQRESULT res = modLoad(v, sqapi);

    return res;
#endif
}

bool file_exists(const SQChar* filename)
{
    return access(filename, F_OK) == 0;
}

#define NOT_FOUND 100

SQRESULT try_import_path(HSQUIRRELVM v, std::basic_string<SQChar>& fname)
{
    // Try to import module at given path. This tries
    // different module types in order.

    // Check binary module
    fname[fname.size() - 1] = 'd';
    if (file_exists(fname.c_str()))
        return sqrat_importbin(v, fname.c_str());
    // Check bytecode module
    fname[fname.size() - 1] = 'c';
    if (file_exists(fname.c_str()))
        return sqrat_importscript(v, fname.c_str());
    // Check source module
    fname[fname.size() - 1] = 't';
    if (file_exists(fname.c_str()))
        return sqrat_importscript(v, fname.c_str());

    return NOT_FOUND;
}

SQRESULT sqrat_import(HSQUIRRELVM v) {
    const SQChar* moduleName;
    HSQOBJECT table;
    SQRESULT res = SQ_OK;

    sq_getstring(v, -2, &moduleName);
    sq_getstackobj(v, -1, &table);
    sq_addref(v, &table);

    sq_settop(v, 0); // Clear Stack
    sq_pushobject(v, table); // Push the target table onto the stack

    std::basic_string<SQChar> fname;
    // Explicit path is needed for dlopen() later, and won't hurt
    // for other cases
    fname = "./";
    fname += moduleName;
    fname += ".nut";
    res = try_import_path(v, fname);
    if (res == NOT_FOUND) {
        const char *path = getenv("SQPATH");
        if (path)
            fname = path;
        else {
            path = getenv("HOME");
            if (path) {
                fname = path;
                fname += "/.squirrel/lib";
            } else {
                fname = "/usr/lib/squirrel";
            }
        }
        fname += "/";
        fname += moduleName;
        fname += ".nut";
        res = try_import_path(v, fname);
        if (res == NOT_FOUND) {
            sq_settop(v, 0); // Clean up the stack (just in case the module load leaves it messy)
            sq_release(v, &table);
            return sq_throwerror(v, _SC("Module not found"));
        }
    }

    sq_settop(v, 0); // Clean up the stack (just in case the module load leaves it messy)
    sq_pushobject(v, table); // return the target table
    sq_release(v, &table);

    return res;
}

static SQInteger sqratbase_import(HSQUIRRELVM v) {
    SQInteger args = sq_gettop(v);
    switch(args) {
    case 2:
        sq_pushroottable(v);
        break;
    case 3:
        // should already have the desired table pushed onto the stack
        break;
    default:
        // Error, unexpected number of arguments
        break;
    }

    return sqrat_import(v);
}

SQRESULT sqrat_register_importlib(HSQUIRRELVM v) {
    sq_pushroottable(v);

    sq_pushstring(v, _SC("_import_"), -1);
    sq_newclosure(v, &sqratbase_import, 0);
    sq_newslot(v, -3, 0);

    sq_pop(v, 1); // pop sqrat table

    return SQ_OK;
}
<|endoftext|>


<commit_before>//
//  Audio.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 31/05/2019.
//  Copyright © 2019 Thomas Harte. All rights reserved.
//

#include "Audio.hpp"

using namespace Apple::Macintosh;

namespace {
const std::size_t sample_length = 352;
}

Audio::Audio(Concurrency::DeferringAsyncTaskQueue &task_queue) : task_queue_(task_queue) {}

// MARK: - Inputs

void Audio::post_sample(uint8_t sample) {
	// Grab the read and write pointers, ensure there's room for a new sample and, if not,
	// drop this one.
	const auto write_pointer = sample_queue_.write_pointer.load();
	const auto read_pointer = sample_queue_.read_pointer.load();
	const decltype(write_pointer) next_write_pointer = (write_pointer + 1) % sample_queue_.buffer.size();
	if(next_write_pointer == read_pointer) {
		return;
	}

	sample_queue_.buffer[write_pointer] = sample;
	sample_queue_.write_pointer.store(next_write_pointer);
}

void Audio::set_volume(int volume) {
	// Post the volume change as a deferred event.
	task_queue_.defer([=] () {
		volume_ = volume;
	});
}

void Audio::set_enabled(bool on) {
	// Post the enabled mask change as a deferred event.
	task_queue_.defer([=] () {
		enabled_mask_ = on ? 1 : 0;
	});
}

// MARK: - Output generation

bool Audio::is_zero_level() {
	return !volume_ || !enabled_mask_;
}

void Audio::set_sample_volume_range(std::int16_t range) {
	// Some underflow here doesn't really matter.
	volume_multiplier_ = range / (7 * 255);
}

void Audio::get_samples(std::size_t number_of_samples, int16_t *target) {
	const auto write_pointer = sample_queue_.write_pointer.load();
	auto read_pointer = sample_queue_.read_pointer.load();

	// TODO: the implementation below acts as if the hardware uses pulse-amplitude modulation;
	// in fact it uses pulse-width modulation. But the scale for pulses isn't specified, so
	// that's something to return to.

	// TODO: temporary implementation. Very inefficient. Replace.
	for(std::size_t sample = 0; sample < number_of_samples; ++sample) {
		target[sample] = volume_multiplier_ * int16_t(sample_queue_.buffer[read_pointer]);// * volume_ * enabled_mask_);
		++subcycle_offset_;

		if(subcycle_offset_ == sample_length) {
//			printf("%d: %d\n", sample_queue_.buffer[read_pointer], volume_multiplier_ * int16_t(sample_queue_.buffer[read_pointer]));
			subcycle_offset_ = 0;
			const unsigned int next_read_pointer = (read_pointer + 1) % sample_queue_.buffer.size();
			if(next_read_pointer != write_pointer) {
				read_pointer = next_read_pointer;
			}
		}
	}

	sample_queue_.read_pointer.store(read_pointer);
}

void Audio::skip_samples(std::size_t number_of_samples) {
	const auto write_pointer = sample_queue_.write_pointer.load();
	auto read_pointer = sample_queue_.read_pointer.load();

	// Number of samples that would be consumed is (number_of_samples + subcycle_offset_) / sample_length.
	const unsigned int samples_passed = static_cast<unsigned int>((number_of_samples + subcycle_offset_) / sample_length);
	subcycle_offset_ = (number_of_samples + subcycle_offset_) % sample_length;

	// Get also number of samples available.
	const unsigned int samples_available = static_cast<unsigned int>((write_pointer + sample_queue_.buffer.size() - read_pointer) % sample_queue_.buffer.size());

	// Advance by whichever of those is the lower number.
	const auto samples_to_consume = std::min(samples_available, samples_passed);
	read_pointer = (read_pointer + samples_to_consume) % sample_queue_.buffer.size();

	sample_queue_.read_pointer.store(read_pointer);
}
<commit_msg>Restores attempt at proper audio behaviour.<commit_after>//
//  Audio.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 31/05/2019.
//  Copyright © 2019 Thomas Harte. All rights reserved.
//

#include "Audio.hpp"

using namespace Apple::Macintosh;

namespace {
const std::size_t sample_length = 352;
}

Audio::Audio(Concurrency::DeferringAsyncTaskQueue &task_queue) : task_queue_(task_queue) {}

// MARK: - Inputs

void Audio::post_sample(uint8_t sample) {
	// Grab the read and write pointers, ensure there's room for a new sample and, if not,
	// drop this one.
	const auto write_pointer = sample_queue_.write_pointer.load();
	const auto read_pointer = sample_queue_.read_pointer.load();
	const decltype(write_pointer) next_write_pointer = (write_pointer + 1) % sample_queue_.buffer.size();
	if(next_write_pointer == read_pointer) {
		return;
	}

	sample_queue_.buffer[write_pointer] = sample;
	sample_queue_.write_pointer.store(next_write_pointer);
}

void Audio::set_volume(int volume) {
	// Post the volume change as a deferred event.
	task_queue_.defer([=] () {
		volume_ = volume;
	});
}

void Audio::set_enabled(bool on) {
	// Post the enabled mask change as a deferred event.
	task_queue_.defer([=] () {
		enabled_mask_ = on ? 1 : 0;
	});
}

// MARK: - Output generation

bool Audio::is_zero_level() {
	return !volume_ || !enabled_mask_;
}

void Audio::set_sample_volume_range(std::int16_t range) {
	// Some underflow here doesn't really matter.
	volume_multiplier_ = range / (7 * 255);
}

void Audio::get_samples(std::size_t number_of_samples, int16_t *target) {
	const auto write_pointer = sample_queue_.write_pointer.load();
	auto read_pointer = sample_queue_.read_pointer.load();

	// TODO: the implementation below acts as if the hardware uses pulse-amplitude modulation;
	// in fact it uses pulse-width modulation. But the scale for pulses isn't specified, so
	// that's something to return to.

	// TODO: temporary implementation. Very inefficient. Replace.
	for(std::size_t sample = 0; sample < number_of_samples; ++sample) {
		target[sample] = volume_multiplier_ * int16_t(sample_queue_.buffer[read_pointer] * volume_ * enabled_mask_);
		++subcycle_offset_;

		if(subcycle_offset_ == sample_length) {
//			printf("%d: %d\n", sample_queue_.buffer[read_pointer], volume_multiplier_ * int16_t(sample_queue_.buffer[read_pointer]));
			subcycle_offset_ = 0;
			const unsigned int next_read_pointer = (read_pointer + 1) % sample_queue_.buffer.size();
			if(next_read_pointer != write_pointer) {
				read_pointer = next_read_pointer;
			}
		}
	}

	sample_queue_.read_pointer.store(read_pointer);
}

void Audio::skip_samples(std::size_t number_of_samples) {
	const auto write_pointer = sample_queue_.write_pointer.load();
	auto read_pointer = sample_queue_.read_pointer.load();

	// Number of samples that would be consumed is (number_of_samples + subcycle_offset_) / sample_length.
	const unsigned int samples_passed = static_cast<unsigned int>((number_of_samples + subcycle_offset_) / sample_length);
	subcycle_offset_ = (number_of_samples + subcycle_offset_) % sample_length;

	// Get also number of samples available.
	const unsigned int samples_available = static_cast<unsigned int>((write_pointer + sample_queue_.buffer.size() - read_pointer) % sample_queue_.buffer.size());

	// Advance by whichever of those is the lower number.
	const auto samples_to_consume = std::min(samples_available, samples_passed);
	read_pointer = (read_pointer + samples_to_consume) % sample_queue_.buffer.size();

	sample_queue_.read_pointer.store(read_pointer);
}
<|endoftext|>


<commit_before>#include "CharRangeSet.hpp"

#include <algorithm>
#include <numeric>
#include <stdexcept>
#include "JEB/Algorithms/Algorithms.hpp"
//#include "JEB/Collections/PairUtilities.hpp"
#include "EscapedString.hpp"

namespace JEB { namespace String { namespace Generic {

static Interval::Inclusive<uint32_t> INCLUSIVE;

CharRangeSet::CharRangeSet()
{}

CharRangeSet::CharRangeSet(CharRangeSet&& other)
{
    std::swap(m_Ranges, other.m_Ranges);
}

CharRangeSet::CharRangeSet(const CharRangeSet& other)
    : m_Ranges(other.m_Ranges)
{}

CharRangeSet& CharRangeSet::operator=(CharRangeSet&& other)
{
    std::swap(m_Ranges, other.m_Ranges);
    return *this;
}

CharRangeSet& CharRangeSet::operator=(const CharRangeSet& other)
{
    m_Ranges = other.m_Ranges;
    return *this;
}

void CharRangeSet::add(Char c)
{
    add(Range(c, c));
}

void CharRangeSet::add(const Range& range)
{
    typedef std::pair<std::vector<Range>::iterator,
                      std::vector<Range>::iterator> Its;
    Its its = Interval::findInterval(
            m_Ranges.begin(), m_Ranges.end(),
            std::make_pair(Interval::previous(range, INCLUSIVE),
                           Interval::next(range, INCLUSIVE)),
            INCLUSIVE);

    if (its.first == its.second)
    {
        m_Ranges.insert(its.first, range);
    }
    else
    {
        *its.first = Range(std::min(range.first, its.first->first),
                           std::max(range.second, (its.second - 1)->second));
        m_Ranges.erase(its.first + 1, its.second);
    }
}

void CharRangeSet::addAll()
{
    m_Ranges.clear();
    m_Ranges.push_back(Interval::maxInterval<Char>());
}

CharRangeSet CharRangeSet::complement() const
{
    Range remainder = Interval::maxInterval<Char>();
    CharRangeSet result;
    std::vector<Range>::const_iterator it;
    for (it = m_Ranges.begin(); it != m_Ranges.end(); it++)
    {
        if (it->first != remainder.first)
            result.m_Ranges.push_back(Range(remainder.first, it->first - 1));
        remainder.first = it->second + 1;
    }
    if (remainder.first <= remainder.second)
        result.m_Ranges.push_back(remainder);
    return result;
}

bool CharRangeSet::has(Char c) const
{
    return hasAll(Range(c, c));
}

bool CharRangeSet::hasAll(const Range& range) const
{
    std::vector<Range>::const_iterator it = JEB::Algorithms::lower_bound(
            m_Ranges.begin(), m_Ranges.end(),
            range.first,
            [](const Range& r){return r.second;});
    return it != m_Ranges.end() && subInterval(*it, range, INCLUSIVE);
}

bool CharRangeSet::hasAny(const Range& range) const
{
    std::vector<Range>::const_iterator it = JEB::Algorithms::lower_bound(
            m_Ranges.begin(), m_Ranges.end(),
            range.first,
            [](const Range& r){return r.second;});
    return it != m_Ranges.end() && overlaps(*it, range, INCLUSIVE);
}

size_t CharRangeSet::numberOfCharacters() const
{
    return std::accumulate(
            m_Ranges.begin(), m_Ranges.end(),
            (size_t)0,
            [](size_t s, const Range& r){return s + Interval::size(r, INCLUSIVE);});
}

size_t CharRangeSet::size() const
{
    return m_Ranges.size();
}

}}}
<commit_msg>Replaced use of PairUtilities.hpp with lambdas<commit_after>#include "CharRangeSet.hpp"

#include <algorithm>
#include <numeric>
#include <stdexcept>
#include "JEB/Algorithms/Algorithms.hpp"
#include "EscapedString.hpp"

namespace JEB { namespace String { namespace Generic {

static Interval::Inclusive<uint32_t> INCLUSIVE;

CharRangeSet::CharRangeSet()
{}

CharRangeSet::CharRangeSet(CharRangeSet&& other)
{
    std::swap(m_Ranges, other.m_Ranges);
}

CharRangeSet::CharRangeSet(const CharRangeSet& other)
    : m_Ranges(other.m_Ranges)
{}

CharRangeSet& CharRangeSet::operator=(CharRangeSet&& other)
{
    std::swap(m_Ranges, other.m_Ranges);
    return *this;
}

CharRangeSet& CharRangeSet::operator=(const CharRangeSet& other)
{
    m_Ranges = other.m_Ranges;
    return *this;
}

void CharRangeSet::add(Char c)
{
    add(Range(c, c));
}

void CharRangeSet::add(const Range& range)
{
    typedef std::pair<std::vector<Range>::iterator,
                      std::vector<Range>::iterator> Its;
    Its its = Interval::findInterval(
            m_Ranges.begin(), m_Ranges.end(),
            std::make_pair(Interval::previous(range, INCLUSIVE),
                           Interval::next(range, INCLUSIVE)),
            INCLUSIVE);

    if (its.first == its.second)
    {
        m_Ranges.insert(its.first, range);
    }
    else
    {
        *its.first = Range(std::min(range.first, its.first->first),
                           std::max(range.second, (its.second - 1)->second));
        m_Ranges.erase(its.first + 1, its.second);
    }
}

void CharRangeSet::addAll()
{
    m_Ranges.clear();
    m_Ranges.push_back(Interval::maxInterval<Char>());
}

CharRangeSet CharRangeSet::complement() const
{
    Range remainder = Interval::maxInterval<Char>();
    CharRangeSet result;
    std::vector<Range>::const_iterator it;
    for (it = m_Ranges.begin(); it != m_Ranges.end(); it++)
    {
        if (it->first != remainder.first)
            result.m_Ranges.push_back(Range(remainder.first, it->first - 1));
        remainder.first = it->second + 1;
    }
    if (remainder.first <= remainder.second)
        result.m_Ranges.push_back(remainder);
    return result;
}

bool CharRangeSet::has(Char c) const
{
    return hasAll(Range(c, c));
}

bool CharRangeSet::hasAll(const Range& range) const
{
    std::vector<Range>::const_iterator it = JEB::Algorithms::lower_bound(
            m_Ranges.begin(), m_Ranges.end(),
            range.first,
            [](const Range& r){return r.second;});
    return it != m_Ranges.end() && subInterval(*it, range, INCLUSIVE);
}

bool CharRangeSet::hasAny(const Range& range) const
{
    std::vector<Range>::const_iterator it = JEB::Algorithms::lower_bound(
            m_Ranges.begin(), m_Ranges.end(),
            range.first,
            [](const Range& r){return r.second;});
    return it != m_Ranges.end() && overlaps(*it, range, INCLUSIVE);
}

size_t CharRangeSet::numberOfCharacters() const
{
    return std::accumulate(
            m_Ranges.begin(), m_Ranges.end(),
            (size_t)0,
            [](size_t s, const Range& r){return s + Interval::size(r, INCLUSIVE);});
}

size_t CharRangeSet::size() const
{
    return m_Ranges.size();
}

}}}
<|endoftext|>


<commit_before>#ifndef JEBMATH_GEOMETRY_MATRIX_HPP
#define JEBMATH_GEOMETRY_MATRIX_HPP

#include <array>
#include <initializer_list>
#include <stdexcept>

namespace JEBMath {

template <typename T, unsigned N>
class Matrix
{
public:
    static unsigned rows() {return N;}
    static unsigned cols() {return N;}
    static unsigned size() {return N * N;}

    Matrix()
    {}

    Matrix(std::initializer_list<T> v)
    {
        if (v.size() != size())
            throw std::invalid_argument("Incorrect number of arguments.");
        auto it = v.begin();
        for (auto dst = begin(); dst != end(); ++dst, ++it)
            *dst = *it;
    }

    template <typename U>
    Matrix(U (&arr)[N * N])
    {
        for (auto dst = begin(); dst != end(); ++dst, ++arr)
            *dst = T(*arr);
    }

    template <typename U>
    explicit Matrix(const Matrix<U, N>& other)
    {
        auto src = other.begin();
        for (auto dst = begin(); dst != end(); ++dst, ++src)
            *dst = T(*src);
    }

    template <typename U>
    Matrix<T, N>& operator=(const Matrix<U, N>& other)
    {
        auto src = other.begin();
        for (auto dst = begin(); dst != end(); ++dst, ++src)
            *dst = T(*src);
        return *this;
    }

    T* operator[](unsigned row)
    {
        return &m_Values[row * cols()];
    }

    const T* operator[](unsigned row) const
    {
        return &m_Values[row * cols()];
    }

    T* begin()
    {
        return m_Values.data();
    }

    T* end()
    {
        return m_Values.data() + size();
    }

    const T* begin() const
    {
        return m_Values.data();
    }

    const T* end() const
    {
        return m_Values.data() + size();
    }

    T* data()
    {
        return m_Values.data();
    }

    const T* data() const
    {
        return m_Values.data();
    }
private:
    std::array<T, N * N> m_Values;
};

}

#include "MatrixFunctions.hpp"
#include "MatrixOperators.hpp"

#endif
<commit_msg>Initialize matrixes with 0s.<commit_after>#ifndef JEBMATH_GEOMETRY_MATRIX_HPP
#define JEBMATH_GEOMETRY_MATRIX_HPP

#include <array>
#include <initializer_list>
#include <stdexcept>

namespace JEBMath {

template <typename T, unsigned N>
class Matrix
{
public:
    static unsigned rows() {return N;}
    static unsigned cols() {return N;}
    static unsigned size() {return N * N;}

    Matrix()
    {
        m_Values.fill(0);
    }

    Matrix(std::initializer_list<T> v)
    {
        if (v.size() != size())
            throw std::invalid_argument("Incorrect number of arguments.");
        auto it = v.begin();
        for (auto dst = begin(); dst != end(); ++dst, ++it)
            *dst = *it;
    }

    template <typename U>
    Matrix(U (&arr)[N * N])
    {
        for (auto dst = begin(); dst != end(); ++dst, ++arr)
            *dst = T(*arr);
    }

    template <typename U>
    explicit Matrix(const Matrix<U, N>& other)
    {
        auto src = other.begin();
        for (auto dst = begin(); dst != end(); ++dst, ++src)
            *dst = T(*src);
    }

    template <typename U>
    Matrix<T, N>& operator=(const Matrix<U, N>& other)
    {
        auto src = other.begin();
        for (auto dst = begin(); dst != end(); ++dst, ++src)
            *dst = T(*src);
        return *this;
    }

    T* operator[](unsigned row)
    {
        return &m_Values[row * cols()];
    }

    const T* operator[](unsigned row) const
    {
        return &m_Values[row * cols()];
    }

    T* begin()
    {
        return m_Values.data();
    }

    T* end()
    {
        return m_Values.data() + size();
    }

    const T* begin() const
    {
        return m_Values.data();
    }

    const T* end() const
    {
        return m_Values.data() + size();
    }

    T* data()
    {
        return m_Values.data();
    }

    const T* data() const
    {
        return m_Values.data();
    }
private:
    std::array<T, N * N> m_Values;
};

}

#include "MatrixFunctions.hpp"
#include "MatrixOperators.hpp"

#endif
<|endoftext|>


<commit_before>#include "rwte/rwte.h"
#include "lua/state.h"
#include "lua/config.h"

namespace lua {
namespace config {

int get_int(const char *name, int def)
{
    auto L = rwte.lua();
    L->getglobal("config");
    L->getfield(-1, name);
    int val = L->tointegerdef(-1, def);
    L->pop(2);

    return val;
}

float get_float(const char *name, float def)
{
    auto L = rwte.lua();
    L->getglobal("config");
    L->getfield(-1, name);
    float val = L->tonumberdef(-1, def);
    L->pop(2);

    return val;
}

bool get_bool(const char *name, bool def)
{
    auto L = rwte.lua();
    L->getglobal("config");
    L->getfield(-1, name);
    float val = L->tobooldef(-1, def);
    L->pop(2);

    return val;
}

std::string get_string(const char *name)
{
    std::string val;

    auto L = rwte.lua();
    L->getglobal("config");
    L->getfield(-1, name);
    const char * s = L->tostring(-1);
    if (s)
        val = s;
    L->pop(2);

    return val;
}

} // namespace config
} // namespace lua
<commit_msg>Fixed wrong type in get_bool.<commit_after>#include "rwte/rwte.h"
#include "lua/state.h"
#include "lua/config.h"

namespace lua {
namespace config {

int get_int(const char *name, int def)
{
    auto L = rwte.lua();
    L->getglobal("config");
    L->getfield(-1, name);
    int val = L->tointegerdef(-1, def);
    L->pop(2);

    return val;
}

float get_float(const char *name, float def)
{
    auto L = rwte.lua();
    L->getglobal("config");
    L->getfield(-1, name);
    float val = L->tonumberdef(-1, def);
    L->pop(2);

    return val;
}

bool get_bool(const char *name, bool def)
{
    auto L = rwte.lua();
    L->getglobal("config");
    L->getfield(-1, name);
    bool val = L->tobooldef(-1, def);
    L->pop(2);

    return val;
}

std::string get_string(const char *name)
{
    std::string val;

    auto L = rwte.lua();
    L->getglobal("config");
    L->getfield(-1, name);
    const char * s = L->tostring(-1);
    if (s)
        val = s;
    L->pop(2);

    return val;
}

} // namespace config
} // namespace lua
<|endoftext|>


<commit_before>#pragma once

#include <memory>
#include <optional>
#include <string>
#include <tl/expected.hpp>
#include "PropagateConstWrapper.hpp"

namespace minesweeper {

enum class Error {
  Ok,
  InvalidInput,
  IndexIsOutOfRange,
  ConversionError,
  UnexpectedError,
};

enum class GameLevel {
  Beginner,
  Intermediate,
  Expert,
};

enum class OpenResult {
  Ok,
  IsFlagged,
  Boom,
  Winner,
};

enum class FieldFlagResult {
  Flagged,
  FlagRemoved,
  AlreadyOpened,
};

enum class FieldType : uint8_t { Empty = 0, One, Two, Three, Four, Five, Six, Seven, Eight, Nine, Mine };

#pragma pack(push, 1)
struct FieldInfo {
  uint64_t row{0U};
  uint64_t column{0U};
  FieldType type{FieldType::Empty};
};
#pragma pack(pop)

struct OpenInfo {
  OpenResult openResult;
  std::vector<FieldInfo> fieldInfos;
};

template <typename TResult>
using Result = tl::expected<TResult, Error>;
constexpr auto in_place = tl::in_place;

class Minesweeper {
public:
  struct Dimension {
    uint64_t width;
    uint64_t height;
  };

  [[nodiscard]] static Result<Minesweeper> create(GameLevel level) noexcept;

  Minesweeper(const Minesweeper &) = delete;
  Minesweeper(Minesweeper &&other) noexcept;
  Minesweeper &operator=(const Minesweeper &) = delete;
  Minesweeper &operator=(Minesweeper &&other) noexcept;

  ~Minesweeper() noexcept;

  [[nodiscard]] Result<Dimension> getSize() const noexcept;
  [[nodiscard]] Result<uint64_t> getElapsedSeconds() const noexcept;
  [[nodiscard]] Result<FieldFlagResult> toggleFlag(const uint64_t row, const uint64_t column);
  [[nodiscard]] Result<OpenInfo> open(const uint64_t row, const uint64_t column);

private:
  struct Impl;

  explicit Minesweeper(std::unique_ptr<Impl> &&impl);

  std::experimental::propagate_const<std::unique_ptr<Impl>> impl;
};
} // namespace minesweeper
<commit_msg>Format FieldType<commit_after>#pragma once

#include <memory>
#include <optional>
#include <string>
#include <tl/expected.hpp>
#include "PropagateConstWrapper.hpp"

namespace minesweeper {

enum class Error {
  Ok,
  InvalidInput,
  IndexIsOutOfRange,
  ConversionError,
  UnexpectedError,
};

enum class GameLevel {
  Beginner,
  Intermediate,
  Expert,
};

enum class OpenResult {
  Ok,
  IsFlagged,
  Boom,
  Winner,
};

enum class FieldFlagResult {
  Flagged,
  FlagRemoved,
  AlreadyOpened,
};

enum class FieldType : uint8_t {
  Empty = 0,
  One,
  Two,
  Three,
  Four,
  Five,
  Six,
  Seven,
  Eight,
  Nine,
  Mine,
};

#pragma pack(push, 1)
struct FieldInfo {
  uint64_t row{0U};
  uint64_t column{0U};
  FieldType type{FieldType::Empty};
};
#pragma pack(pop)

struct OpenInfo {
  OpenResult openResult;
  std::vector<FieldInfo> fieldInfos;
};

template <typename TResult>
using Result = tl::expected<TResult, Error>;
constexpr auto in_place = tl::in_place;

class Minesweeper {
public:
  struct Dimension {
    uint64_t width;
    uint64_t height;
  };

  [[nodiscard]] static Result<Minesweeper> create(GameLevel level) noexcept;

  Minesweeper(const Minesweeper &) = delete;
  Minesweeper(Minesweeper &&other) noexcept;
  Minesweeper &operator=(const Minesweeper &) = delete;
  Minesweeper &operator=(Minesweeper &&other) noexcept;

  ~Minesweeper() noexcept;

  [[nodiscard]] Result<Dimension> getSize() const noexcept;
  [[nodiscard]] Result<uint64_t> getElapsedSeconds() const noexcept;
  [[nodiscard]] Result<FieldFlagResult> toggleFlag(const uint64_t row, const uint64_t column);
  [[nodiscard]] Result<OpenInfo> open(const uint64_t row, const uint64_t column);

private:
  struct Impl;

  explicit Minesweeper(std::unique_ptr<Impl> &&impl);

  std::experimental::propagate_const<std::unique_ptr<Impl>> impl;
};
} // namespace minesweeper
<|endoftext|>


<commit_before>#include <Turpitude.h>

jobject zval_to_jobject(JNIEnv* env, zval* val) {
    if (NULL == val)
        return NULL;

    TSRMLS_FETCH();

    jclass cls = NULL;
    jobject obj = NULL;
    jmethodID mid = NULL;

    switch (Z_TYPE_P(val)) {
        case IS_LONG:
            printf("IS_LONG\n");
            cls = env->FindClass("java/lang/Long");
            mid = env->GetMethodID(cls, "<init>", "(J)V");
            obj = env->NewObject(cls, mid, val->value.lval);
            break;
        case IS_DOUBLE:
            printf("IS_DOUBLE\n");
            cls = env->FindClass("java/lang/Double");
            mid = env->GetMethodID(cls, "<init>", "(D)V");
            obj = env->NewObject(cls, mid, val->value.dval);
            break;
        case IS_BOOL:
            printf("IS_BOOL\n");
            cls = env->FindClass("java/lang/Boolean");
            mid = env->GetMethodID(cls, "<init>", "(Z)V");
            obj = env->NewObject(cls, mid, (val->value.lval)?true:false);
            break;
        case IS_ARRAY:
            printf("IS_ARRAY\n");
            break;
        case IS_OBJECT:
            printf("IS_OBJECT\n");
            zend_object_value* zo = &(val->value.obj);
            printf("TRALALA %d\n", zo->handle);
            HashTable* tbl = zo->handlers->get_properties(val TSRMLS_CC);

            break;
        case IS_CONSTANT:
        case IS_STRING:
            printf("IS_STRING or IS_CONSTANT\n");
            obj = env->NewStringUTF(val->value.str.val);
            break;
        default:
            // probably null
            obj = NULL;
    }

    return obj;
}

<commit_msg>-- reading properties<commit_after>#include <Turpitude.h>

jobject zval_to_jobject(JNIEnv* env, zval* val) {
    if (NULL == val)
        return NULL;

    TSRMLS_FETCH();

    jclass cls = NULL;
    jobject obj = NULL;
    jmethodID mid = NULL;

    switch (Z_TYPE_P(val)) {
        case IS_LONG:
            //printf("IS_LONG\n");
            cls = env->FindClass("java/lang/Long");
            mid = env->GetMethodID(cls, "<init>", "(J)V");
            obj = env->NewObject(cls, mid, val->value.lval);
            break;
        case IS_DOUBLE:
            //printf("IS_DOUBLE\n");
            cls = env->FindClass("java/lang/Double");
            mid = env->GetMethodID(cls, "<init>", "(D)V");
            obj = env->NewObject(cls, mid, val->value.dval);
            break;
        case IS_BOOL:
            //printf("IS_BOOL\n");
            cls = env->FindClass("java/lang/Boolean");
            mid = env->GetMethodID(cls, "<init>", "(Z)V");
            obj = env->NewObject(cls, mid, (val->value.lval)?true:false);
            break;
        case IS_ARRAY:
            printf("IS_ARRAY\n");
            break;
        case IS_OBJECT:
            //printf("IS_OBJECT\n");
            zend_class_entry* ce = Z_OBJCE_P(val);
            printf("Class: %s\n", ce->name);
            zend_object_value* zo = &(val->value.obj);
            printf("Handle: %d\n", zo->handle);
            HashTable* props = Z_OBJ_HT_P(val)->get_properties(val TSRMLS_CC);
            HashPosition pos;
            zend_hash_internal_pointer_reset_ex(props, &pos);
            zval** prop;
            while (zend_hash_get_current_data_ex(props, (void **) &prop, &pos) == SUCCESS) {
                char  *prop_name;
                uint  prop_name_size;
                ulong index;
                if (zend_hash_get_current_key_ex(props, &prop_name, &prop_name_size, &index, 1, &pos) == HASH_KEY_IS_STRING) {
                    if (prop_name_size && prop_name[0]) {
                        printf("propname: %s\n", prop_name);
                    }
                    efree(prop_name);
                }
                zend_hash_move_forward_ex(props, &pos);
            }
            /*
            zend_hash_get_current_data_ex(props, (void **) &prop, &pos);
            char  *prop_name;
            uint  prop_name_size;
            ulong index;
            if (zend_hash_get_current_key_ex(props, &prop_name, &prop_name_size, &index, 1, &pos) == HASH_KEY_IS_STRING) {
                if (prop_name_size && prop_name[0]) {
                        printf("propname: %s\n", prop_name);
                    if (!zend_hash_quick_exists(&ce->properties_info, prop_name, prop_name_size, zend_get_hash_value(prop_name, prop_name_size))) {
                printf("hierher\n");
                    }
                }
            }
            */

            break;
        case IS_CONSTANT:
        case IS_STRING:
            printf("IS_STRING or IS_CONSTANT\n");
            obj = env->NewStringUTF(val->value.str.val);
            break;
        default:
            // probably null
            obj = NULL;
    }

    return obj;
}

<|endoftext|>


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

extern "C" {
#ifdef __cplusplus
#define __STDC_CONSTANT_MACROS
#ifdef _STDINT_H
#undef _STDINT_H
#endif
#include <stdint.h>
#endif
#include <libavcodec/avcodec.h>
#include <libavresample/avresample.h>
#include <libavutil/channel_layout.h>
#include <libavutil/error.h>
#include <libavutil/opt.h>
}

#define LOG_TAG "ffmpeg_jni"
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, \
                   __VA_ARGS__))

#define DECODER_FUNC(RETURN_TYPE, NAME, ...) \
  extern "C" { \
  JNIEXPORT RETURN_TYPE \
    Java_com_google_android_exoplayer2_ext_ffmpeg_FfmpegDecoder_ ## NAME \
      (JNIEnv* env, jobject thiz, ##__VA_ARGS__);\
  } \
  JNIEXPORT RETURN_TYPE \
    Java_com_google_android_exoplayer2_ext_ffmpeg_FfmpegDecoder_ ## NAME \
      (JNIEnv* env, jobject thiz, ##__VA_ARGS__)\

#define LIBRARY_FUNC(RETURN_TYPE, NAME, ...) \
  extern "C" { \
  JNIEXPORT RETURN_TYPE \
    Java_com_google_android_exoplayer2_ext_ffmpeg_FfmpegLibrary_ ## NAME \
      (JNIEnv* env, jobject thiz, ##__VA_ARGS__);\
  } \
  JNIEXPORT RETURN_TYPE \
    Java_com_google_android_exoplayer2_ext_ffmpeg_FfmpegLibrary_ ## NAME \
      (JNIEnv* env, jobject thiz, ##__VA_ARGS__)\

#define ERROR_STRING_BUFFER_LENGTH 256

// Output format corresponding to AudioFormat.ENCODING_PCM_16BIT.
static const AVSampleFormat OUTPUT_FORMAT_PCM_16BIT = AV_SAMPLE_FMT_S16;
// Output format corresponding to AudioFormat.ENCODING_PCM_FLOAT.
static const AVSampleFormat OUTPUT_FORMAT_PCM_FLOAT = AV_SAMPLE_FMT_FLT;

// Error codes matching FfmpegDecoder.java.
static const int DECODER_ERROR_INVALID_DATA = -1;
static const int DECODER_ERROR_OTHER = -2;

/**
 * Returns the AVCodec with the specified name, or NULL if it is not available.
 */
AVCodec *getCodecByName(JNIEnv* env, jstring codecName);

/**
 * Allocates and opens a new AVCodecContext for the specified codec, passing the
 * provided extraData as initialization data for the decoder if it is non-NULL.
 * Returns the created context.
 */
AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, jbyteArray extraData,
                              jboolean outputFloat, jint rawSampleRate,
                              jint rawChannelCount);

/**
 * Decodes the packet into the output buffer, returning the number of bytes
 * written, or a negative DECODER_ERROR constant value in the case of an error.
 */
int decodePacket(AVCodecContext *context, AVPacket *packet,
                 uint8_t *outputBuffer, int outputSize);

/**
 * Outputs a log message describing the avcodec error number.
 */
void logError(const char *functionName, int errorNumber);

/**
 * Releases the specified context.
 */
void releaseContext(AVCodecContext *context);

jint JNI_OnLoad(JavaVM *vm, void *reserved) {
  JNIEnv *env;
  if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
    return -1;
  }
  avcodec_register_all();
  return JNI_VERSION_1_6;
}

LIBRARY_FUNC(jstring, ffmpegGetVersion) {
  return env->NewStringUTF(LIBAVCODEC_IDENT);
}

LIBRARY_FUNC(jboolean, ffmpegHasDecoder, jstring codecName) {
  return getCodecByName(env, codecName) != NULL;
}

DECODER_FUNC(jlong, ffmpegInitialize, jstring codecName, jbyteArray extraData,
             jboolean outputFloat, jint rawSampleRate, jint rawChannelCount) {
  AVCodec *codec = getCodecByName(env, codecName);
  if (!codec) {
    LOGE("Codec not found.");
    return 0L;
  }
  return (jlong)createContext(env, codec, extraData, outputFloat, rawSampleRate,
                              rawChannelCount);
}

DECODER_FUNC(jint, ffmpegDecode, jlong context, jobject inputData,
    jint inputSize, jobject outputData, jint outputSize) {
  if (!context) {
    LOGE("Context must be non-NULL.");
    return -1;
  }
  if (!inputData || !outputData) {
    LOGE("Input and output buffers must be non-NULL.");
    return -1;
  }
  if (inputSize < 0) {
    LOGE("Invalid input buffer size: %d.", inputSize);
    return -1;
  }
  if (outputSize < 0) {
    LOGE("Invalid output buffer length: %d", outputSize);
    return -1;
  }
  uint8_t *inputBuffer = (uint8_t *) env->GetDirectBufferAddress(inputData);
  uint8_t *outputBuffer = (uint8_t *) env->GetDirectBufferAddress(outputData);
  AVPacket packet;
  av_init_packet(&packet);
  packet.data = inputBuffer;
  packet.size = inputSize;
  return decodePacket((AVCodecContext *) context, &packet, outputBuffer,
                      outputSize);
}

DECODER_FUNC(jint, ffmpegGetChannelCount, jlong context) {
  if (!context) {
    LOGE("Context must be non-NULL.");
    return -1;
  }
  return ((AVCodecContext *) context)->channels;
}

DECODER_FUNC(jint, ffmpegGetSampleRate, jlong context) {
  if (!context) {
    LOGE("Context must be non-NULL.");
    return -1;
  }
  return ((AVCodecContext *) context)->sample_rate;
}

DECODER_FUNC(jlong, ffmpegReset, jlong jContext, jbyteArray extraData) {
  AVCodecContext *context = (AVCodecContext *) jContext;
  if (!context) {
    LOGE("Tried to reset without a context.");
    return 0L;
  }

  AVCodecID codecId = context->codec_id;
  if (codecId == AV_CODEC_ID_TRUEHD) {
    // Release and recreate the context if the codec is TrueHD.
    // TODO: Figure out why flushing doesn't work for this codec.
    releaseContext(context);
    AVCodec *codec = avcodec_find_decoder(codecId);
    if (!codec) {
      LOGE("Unexpected error finding codec %d.", codecId);
      return 0L;
    }
    jboolean outputFloat =
        (jboolean)(context->request_sample_fmt == OUTPUT_FORMAT_PCM_FLOAT);
    return (jlong)createContext(env, codec, extraData, outputFloat,
                                /* rawSampleRate= */ -1,
                                /* rawChannelCount= */ -1);
  }

  avcodec_flush_buffers(context);
  return (jlong) context;
}

DECODER_FUNC(void, ffmpegRelease, jlong context) {
  if (context) {
    releaseContext((AVCodecContext *) context);
  }
}

AVCodec *getCodecByName(JNIEnv* env, jstring codecName) {
  if (!codecName) {
    return NULL;
  }
  const char *codecNameChars = env->GetStringUTFChars(codecName, NULL);
  AVCodec *codec = avcodec_find_decoder_by_name(codecNameChars);
  env->ReleaseStringUTFChars(codecName, codecNameChars);
  return codec;
}

AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, jbyteArray extraData,
                              jboolean outputFloat, jint rawSampleRate,
                              jint rawChannelCount) {
  AVCodecContext *context = avcodec_alloc_context3(codec);
  if (!context) {
    LOGE("Failed to allocate context.");
    return NULL;
  }
  context->request_sample_fmt =
      outputFloat ? OUTPUT_FORMAT_PCM_FLOAT : OUTPUT_FORMAT_PCM_16BIT;
  if (extraData) {
    jsize size = env->GetArrayLength(extraData);
    context->extradata_size = size;
    context->extradata =
        (uint8_t *) av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
    if (!context->extradata) {
      LOGE("Failed to allocate extradata.");
      releaseContext(context);
      return NULL;
    }
    env->GetByteArrayRegion(extraData, 0, size, (jbyte *) context->extradata);
  }
  if (context->codec_id == AV_CODEC_ID_PCM_MULAW ||
      context->codec_id == AV_CODEC_ID_PCM_ALAW) {
    context->sample_rate = rawSampleRate;
    context->channels = rawChannelCount;
    context->channel_layout = av_get_default_channel_layout(rawChannelCount);
  }
  context->err_recognition = AV_EF_IGNORE_ERR;
  int result = avcodec_open2(context, codec, NULL);
  if (result < 0) {
    logError("avcodec_open2", result);
    releaseContext(context);
    return NULL;
  }
  return context;
}

int decodePacket(AVCodecContext *context, AVPacket *packet,
                 uint8_t *outputBuffer, int outputSize) {
  int result = 0;
  // Queue input data.
  result = avcodec_send_packet(context, packet);
  if (result) {
    logError("avcodec_send_packet", result);
    return result == AVERROR_INVALIDDATA ? DECODER_ERROR_INVALID_DATA
                                         : DECODER_ERROR_OTHER;
  }

  // Dequeue output data until it runs out.
  int outSize = 0;
  while (true) {
    AVFrame *frame = av_frame_alloc();
    if (!frame) {
      LOGE("Failed to allocate output frame.");
      return -1;
    }
    result = avcodec_receive_frame(context, frame);
    if (result) {
      av_frame_free(&frame);
      if (result == AVERROR(EAGAIN)) {
        break;
      }
      logError("avcodec_receive_frame", result);
      return result;
    }

    // Resample output.
    AVSampleFormat sampleFormat = context->sample_fmt;
    int channelCount = context->channels;
    int channelLayout = context->channel_layout;
    int sampleRate = context->sample_rate;
    int sampleCount = frame->nb_samples;
    int dataSize = av_samples_get_buffer_size(NULL, channelCount, sampleCount,
                                              sampleFormat, 1);
    AVAudioResampleContext *resampleContext;
    if (context->opaque) {
      resampleContext = (AVAudioResampleContext *) context->opaque;
    } else {
      resampleContext = avresample_alloc_context();
      av_opt_set_int(resampleContext, "in_channel_layout",  channelLayout, 0);
      av_opt_set_int(resampleContext, "out_channel_layout", channelLayout, 0);
      av_opt_set_int(resampleContext, "in_sample_rate", sampleRate, 0);
      av_opt_set_int(resampleContext, "out_sample_rate", sampleRate, 0);
      av_opt_set_int(resampleContext, "in_sample_fmt", sampleFormat, 0);
      // The output format is always the requested format.
      av_opt_set_int(resampleContext, "out_sample_fmt",
          context->request_sample_fmt, 0);
      result = avresample_open(resampleContext);
      if (result < 0) {
        logError("avresample_open", result);
        av_frame_free(&frame);
        return -1;
      }
      context->opaque = resampleContext;
    }
    int inSampleSize = av_get_bytes_per_sample(sampleFormat);
    int outSampleSize = av_get_bytes_per_sample(context->request_sample_fmt);
    int outSamples = avresample_get_out_samples(resampleContext, sampleCount);
    int bufferOutSize = outSampleSize * channelCount * outSamples;
    if (outSize + bufferOutSize > outputSize) {
      LOGE("Output buffer size (%d) too small for output data (%d).",
           outputSize, outSize + bufferOutSize);
      av_frame_free(&frame);
      return -1;
    }
    result = avresample_convert(resampleContext, &outputBuffer, bufferOutSize,
                                outSamples, frame->data, frame->linesize[0],
                                sampleCount);
    av_frame_free(&frame);
    if (result < 0) {
      logError("avresample_convert", result);
      return result;
    }
    int available = avresample_available(resampleContext);
    if (available != 0) {
      LOGE("Expected no samples remaining after resampling, but found %d.",
           available);
      return -1;
    }
    outputBuffer += bufferOutSize;
    outSize += bufferOutSize;
  }
  return outSize;
}

void logError(const char *functionName, int errorNumber) {
  char *buffer = (char *) malloc(ERROR_STRING_BUFFER_LENGTH * sizeof(char));
  av_strerror(errorNumber, buffer, ERROR_STRING_BUFFER_LENGTH);
  LOGE("Error in %s: %s", functionName, buffer);
  free(buffer);
}

void releaseContext(AVCodecContext *context) {
  if (!context) {
    return;
  }
  AVAudioResampleContext *resampleContext;
  if ((resampleContext = (AVAudioResampleContext *) context->opaque)) {
    avresample_free(&resampleContext);
    context->opaque = NULL;
  }
  avcodec_free_context(&context);
}

<commit_msg>use swresample instead of avresample, since avresample module has been deprecated.<commit_after>/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <jni.h>
#include <stdlib.h>
#include <android/log.h>

extern "C" {
#ifdef __cplusplus
#define __STDC_CONSTANT_MACROS
#ifdef _STDINT_H
#undef _STDINT_H
#endif
#include <stdint.h>
#endif
#include <libavcodec/avcodec.h>
#include <libswresample/swresample.h>
#include <libavutil/channel_layout.h>
#include <libavutil/error.h>
#include <libavutil/opt.h>
}

#define LOG_TAG "ffmpeg_jni"
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, \
                   __VA_ARGS__))

#define DECODER_FUNC(RETURN_TYPE, NAME, ...) \
  extern "C" { \
  JNIEXPORT RETURN_TYPE \
    Java_com_google_android_exoplayer2_ext_ffmpeg_FfmpegDecoder_ ## NAME \
      (JNIEnv* env, jobject thiz, ##__VA_ARGS__);\
  } \
  JNIEXPORT RETURN_TYPE \
    Java_com_google_android_exoplayer2_ext_ffmpeg_FfmpegDecoder_ ## NAME \
      (JNIEnv* env, jobject thiz, ##__VA_ARGS__)\

#define LIBRARY_FUNC(RETURN_TYPE, NAME, ...) \
  extern "C" { \
  JNIEXPORT RETURN_TYPE \
    Java_com_google_android_exoplayer2_ext_ffmpeg_FfmpegLibrary_ ## NAME \
      (JNIEnv* env, jobject thiz, ##__VA_ARGS__);\
  } \
  JNIEXPORT RETURN_TYPE \
    Java_com_google_android_exoplayer2_ext_ffmpeg_FfmpegLibrary_ ## NAME \
      (JNIEnv* env, jobject thiz, ##__VA_ARGS__)\

#define ERROR_STRING_BUFFER_LENGTH 256

// Output format corresponding to AudioFormat.ENCODING_PCM_16BIT.
static const AVSampleFormat OUTPUT_FORMAT_PCM_16BIT = AV_SAMPLE_FMT_S16;
// Output format corresponding to AudioFormat.ENCODING_PCM_FLOAT.
static const AVSampleFormat OUTPUT_FORMAT_PCM_FLOAT = AV_SAMPLE_FMT_FLT;

// Error codes matching FfmpegDecoder.java.
static const int DECODER_ERROR_INVALID_DATA = -1;
static const int DECODER_ERROR_OTHER = -2;

/**
 * Returns the AVCodec with the specified name, or NULL if it is not available.
 */
AVCodec *getCodecByName(JNIEnv* env, jstring codecName);

/**
 * Allocates and opens a new AVCodecContext for the specified codec, passing the
 * provided extraData as initialization data for the decoder if it is non-NULL.
 * Returns the created context.
 */
AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, jbyteArray extraData,
                              jboolean outputFloat, jint rawSampleRate,
                              jint rawChannelCount);

/**
 * Decodes the packet into the output buffer, returning the number of bytes
 * written, or a negative DECODER_ERROR constant value in the case of an error.
 */
int decodePacket(AVCodecContext *context, AVPacket *packet,
                 uint8_t *outputBuffer, int outputSize);

/**
 * Outputs a log message describing the avcodec error number.
 */
void logError(const char *functionName, int errorNumber);

/**
 * Releases the specified context.
 */
void releaseContext(AVCodecContext *context);

jint JNI_OnLoad(JavaVM *vm, void *reserved) {
  JNIEnv *env;
  if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
    return -1;
  }
  avcodec_register_all();
  return JNI_VERSION_1_6;
}

LIBRARY_FUNC(jstring, ffmpegGetVersion) {
  return env->NewStringUTF(LIBAVCODEC_IDENT);
}

LIBRARY_FUNC(jboolean, ffmpegHasDecoder, jstring codecName) {
  return getCodecByName(env, codecName) != NULL;
}

DECODER_FUNC(jlong, ffmpegInitialize, jstring codecName, jbyteArray extraData,
             jboolean outputFloat, jint rawSampleRate, jint rawChannelCount) {
  AVCodec *codec = getCodecByName(env, codecName);
  if (!codec) {
    LOGE("Codec not found.");
    return 0L;
  }
  return (jlong)createContext(env, codec, extraData, outputFloat, rawSampleRate,
                              rawChannelCount);
}

DECODER_FUNC(jint, ffmpegDecode, jlong context, jobject inputData,
    jint inputSize, jobject outputData, jint outputSize) {
  if (!context) {
    LOGE("Context must be non-NULL.");
    return -1;
  }
  if (!inputData || !outputData) {
    LOGE("Input and output buffers must be non-NULL.");
    return -1;
  }
  if (inputSize < 0) {
    LOGE("Invalid input buffer size: %d.", inputSize);
    return -1;
  }
  if (outputSize < 0) {
    LOGE("Invalid output buffer length: %d", outputSize);
    return -1;
  }
  uint8_t *inputBuffer = (uint8_t *) env->GetDirectBufferAddress(inputData);
  uint8_t *outputBuffer = (uint8_t *) env->GetDirectBufferAddress(outputData);
  AVPacket packet;
  av_init_packet(&packet);
  packet.data = inputBuffer;
  packet.size = inputSize;
  return decodePacket((AVCodecContext *) context, &packet, outputBuffer,
                      outputSize);
}

DECODER_FUNC(jint, ffmpegGetChannelCount, jlong context) {
  if (!context) {
    LOGE("Context must be non-NULL.");
    return -1;
  }
  return ((AVCodecContext *) context)->channels;
}

DECODER_FUNC(jint, ffmpegGetSampleRate, jlong context) {
  if (!context) {
    LOGE("Context must be non-NULL.");
    return -1;
  }
  return ((AVCodecContext *) context)->sample_rate;
}

DECODER_FUNC(jlong, ffmpegReset, jlong jContext, jbyteArray extraData) {
  AVCodecContext *context = (AVCodecContext *) jContext;
  if (!context) {
    LOGE("Tried to reset without a context.");
    return 0L;
  }

  AVCodecID codecId = context->codec_id;
  if (codecId == AV_CODEC_ID_TRUEHD) {
    // Release and recreate the context if the codec is TrueHD.
    // TODO: Figure out why flushing doesn't work for this codec.
    releaseContext(context);
    AVCodec *codec = avcodec_find_decoder(codecId);
    if (!codec) {
      LOGE("Unexpected error finding codec %d.", codecId);
      return 0L;
    }
    jboolean outputFloat =
        (jboolean)(context->request_sample_fmt == OUTPUT_FORMAT_PCM_FLOAT);
    return (jlong)createContext(env, codec, extraData, outputFloat,
                                /* rawSampleRate= */ -1,
                                /* rawChannelCount= */ -1);
  }

  avcodec_flush_buffers(context);
  return (jlong) context;
}

DECODER_FUNC(void, ffmpegRelease, jlong context) {
  if (context) {
    releaseContext((AVCodecContext *) context);
  }
}

AVCodec *getCodecByName(JNIEnv* env, jstring codecName) {
  if (!codecName) {
    return NULL;
  }
  const char *codecNameChars = env->GetStringUTFChars(codecName, NULL);
  AVCodec *codec = avcodec_find_decoder_by_name(codecNameChars);
  env->ReleaseStringUTFChars(codecName, codecNameChars);
  return codec;
}

AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, jbyteArray extraData,
                              jboolean outputFloat, jint rawSampleRate,
                              jint rawChannelCount) {
  AVCodecContext *context = avcodec_alloc_context3(codec);
  if (!context) {
    LOGE("Failed to allocate context.");
    return NULL;
  }
  context->request_sample_fmt =
      outputFloat ? OUTPUT_FORMAT_PCM_FLOAT : OUTPUT_FORMAT_PCM_16BIT;
  if (extraData) {
    jsize size = env->GetArrayLength(extraData);
    context->extradata_size = size;
    context->extradata =
        (uint8_t *) av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
    if (!context->extradata) {
      LOGE("Failed to allocate extradata.");
      releaseContext(context);
      return NULL;
    }
    env->GetByteArrayRegion(extraData, 0, size, (jbyte *) context->extradata);
  }
  if (context->codec_id == AV_CODEC_ID_PCM_MULAW ||
      context->codec_id == AV_CODEC_ID_PCM_ALAW) {
    context->sample_rate = rawSampleRate;
    context->channels = rawChannelCount;
    context->channel_layout = av_get_default_channel_layout(rawChannelCount);
  }
  context->err_recognition = AV_EF_IGNORE_ERR;
  int result = avcodec_open2(context, codec, NULL);
  if (result < 0) {
    logError("avcodec_open2", result);
    releaseContext(context);
    return NULL;
  }
  return context;
}

int decodePacket(AVCodecContext *context, AVPacket *packet,
                 uint8_t *outputBuffer, int outputSize) {
  int result = 0;
  // Queue input data.
  result = avcodec_send_packet(context, packet);
  if (result) {
    logError("avcodec_send_packet", result);
    return result == AVERROR_INVALIDDATA ? DECODER_ERROR_INVALID_DATA
                                         : DECODER_ERROR_OTHER;
  }

  // Dequeue output data until it runs out.
  int outSize = 0;
  while (true) {
    AVFrame *frame = av_frame_alloc();
    if (!frame) {
      LOGE("Failed to allocate output frame.");
      return -1;
    }
    result = avcodec_receive_frame(context, frame);
    if (result) {
      av_frame_free(&frame);
      if (result == AVERROR(EAGAIN)) {
        break;
      }
      logError("avcodec_receive_frame", result);
      return result;
    }

    // Resample output.
    AVSampleFormat sampleFormat = context->sample_fmt;
    int channelCount = context->channels;
    int channelLayout = context->channel_layout;
    int sampleRate = context->sample_rate;
    int sampleCount = frame->nb_samples;
    int dataSize = av_samples_get_buffer_size(NULL, channelCount, sampleCount,
                                              sampleFormat, 1);
    SwrContext *resampleContext;
    if (context->opaque) {
      resampleContext = (SwrContext *) context->opaque;
    } else {
      resampleContext = swr_alloc();
      av_opt_set_int(resampleContext, "in_channel_layout",  channelLayout, 0);
      av_opt_set_int(resampleContext, "out_channel_layout", channelLayout, 0);
      av_opt_set_int(resampleContext, "in_sample_rate", sampleRate, 0);
      av_opt_set_int(resampleContext, "out_sample_rate", sampleRate, 0);
      av_opt_set_int(resampleContext, "in_sample_fmt", sampleFormat, 0);
      // The output format is always the requested format.
      av_opt_set_int(resampleContext, "out_sample_fmt",
          context->request_sample_fmt, 0);
      result = swr_init(resampleContext);
      if (result < 0) {
        logError("avresample_open", result);
        av_frame_free(&frame);
        return -1;
      }
      context->opaque = resampleContext;
    }
    int inSampleSize = av_get_bytes_per_sample(sampleFormat);
    int outSampleSize = av_get_bytes_per_sample(context->request_sample_fmt);
    int outSamples = swr_get_out_samples(resampleContext, sampleCount);
    int bufferOutSize = outSampleSize * channelCount * outSamples;
    if (outSize + bufferOutSize > outputSize) {
      LOGE("Output buffer size (%d) too small for output data (%d).",
           outputSize, outSize + bufferOutSize);
      av_frame_free(&frame);
      return -1;
    }
    result = swr_convert(resampleContext,
                                &outputBuffer, bufferOutSize,
                                (const uint8_t **)frame->data, frame->nb_samples);
    av_frame_free(&frame);
    if (result < 0) {
      logError("avresample_convert", result);
      return result;
    }
    int available = swr_get_out_samples(resampleContext, 0);
    if (available != 0) {
      LOGE("Expected no samples remaining after resampling, but found %d.",
           available);
      return -1;
    }
    outputBuffer += bufferOutSize;
    outSize += bufferOutSize;
  }
  return outSize;
}

void logError(const char *functionName, int errorNumber) {
  char *buffer = (char *) malloc(ERROR_STRING_BUFFER_LENGTH * sizeof(char));
  av_strerror(errorNumber, buffer, ERROR_STRING_BUFFER_LENGTH);
  LOGE("Error in %s: %s", functionName, buffer);
  free(buffer);
}

void releaseContext(AVCodecContext *context) {
  if (!context) {
    return;
  }
  SwrContext *swrContext;
  if ((swrContext = (SwrContext *) context->opaque)) {
      swr_free(&swrContext);
      context->opaque = NULL;
  }
  avcodec_free_context(&context);
}

<|endoftext|>


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

#include "qorganizerasynchprocess.h"
#include "qtorganizer.h"
#include "qorganizermaemo5_p.h"
#include "qorganizermaemo5ids_p.h"
#include <QtCore/qtimer.h>
#include <QtCore/qcoreapplication.h>

QTM_USE_NAMESPACE

OrganizerRequestTimeoutTimer::OrganizerRequestTimeoutTimer(QOrganizerItemAbstractRequest *req, int msecs)
    : m_req(req)
{
    m_timeoutTimer = new QTimer();
    connect(m_timeoutTimer, SIGNAL(timeout()), this, SLOT(internalTimeout()));
    m_timeoutTimer->setSingleShot(true);
    m_timeoutTimer->start(msecs);
}

OrganizerRequestTimeoutTimer::~OrganizerRequestTimeoutTimer()
{
    delete m_timeoutTimer;
}

QOrganizerItemAbstractRequest* OrganizerRequestTimeoutTimer::request() const
{
    return m_req;
}

void OrganizerRequestTimeoutTimer::internalTimeout()
{
    emit timeout(this);
}

OrganizerAsynchProcess::OrganizerAsynchProcess(QOrganizerItemMaemo5Engine* engine)
    : m_engine(engine), m_quitNow(false)
{
    start();
    QObject::moveToThread(this);
}

void OrganizerAsynchProcess::run()
{
    while(!m_quitNow) {
        yieldCurrentThread();
        processRequest();
    }

    // Inform that the thread quits now
    m_quitNow = false;
}

OrganizerAsynchProcess::~OrganizerAsynchProcess()
{
    // Tell thread to quit
    m_quitNow = true;

    // Wait for run() to exit
    while(m_quitNow)
        yieldCurrentThread();
}

void OrganizerAsynchProcess::requestDestroyed(QOrganizerItemAbstractRequest *req)
{
    bool requestRemoved = false;

    if (req->state() != QOrganizerItemAbstractRequest::ActiveState) {
        m_mainMutex.lock();
        m_requestQueue.removeOne(req);
        m_mainMutex.unlock();
        requestRemoved = true;
    }

    if (!requestRemoved)
        waitForRequestFinished(req);
}

bool OrganizerAsynchProcess::addRequest(QOrganizerItemAbstractRequest *req)
{
    QOrganizerItemManagerEngine::updateRequestState(req, QOrganizerItemAbstractRequest::InactiveState);
    m_requestQueue.enqueue(req);
    return true;
}

bool OrganizerAsynchProcess::cancelRequest(QOrganizerItemAbstractRequest *req)
{
    m_mainMutex.lock();
    if (req->state() != QOrganizerItemAbstractRequest::ActiveState) {
        QOrganizerItemManagerEngine::updateRequestState(req, QOrganizerItemAbstractRequest::CanceledState);
        m_requestQueue.removeOne(req);
        m_mainMutex.unlock();
        return true;
    }
    else {
        // cannot cancel active requests
        m_mainMutex.unlock();
        return false;
    }
}

bool OrganizerAsynchProcess::waitForRequestFinished(QOrganizerItemAbstractRequest *req, int msecs)
{
    if (req->state() == QOrganizerItemAbstractRequest::FinishedState)
        return true;
    else if (req->state() == QOrganizerItemAbstractRequest::CanceledState)
        return false;

    // Multiple timers are created to make this method thread safe.
    // There's a timer for each calling thread.
    OrganizerRequestTimeoutTimer* newTimer = new OrganizerRequestTimeoutTimer(req, msecs);
    connect(newTimer, SIGNAL(timeout(OrganizerRequestTimeoutTimer*)), this, SLOT(timeout(OrganizerRequestTimeoutTimer*)));
    m_timers << newTimer;
    return waitForRequestFinished(req);
}

bool OrganizerAsynchProcess::waitForRequestFinished(QOrganizerItemAbstractRequest *req)
{
    m_activeRequests.insert(req);

    do {
        yieldCurrentThread();
        // Process events to allow the timeout timers to work
        QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers);
    } while(m_activeRequests.contains(req)
            && (req->state() == QOrganizerItemAbstractRequest::InactiveState
             || req->state() == QOrganizerItemAbstractRequest::ActiveState));

    m_timeoutMutex.lock();
    if (!m_activeRequests.contains(req)) {
        // timeout occured
        m_timeoutMutex.unlock();
        return false;
    }
    else {
        // timeout not occured
        m_activeRequests.remove(req);

        // cancel and remove timer
        QList<OrganizerRequestTimeoutTimer *>::iterator timer;
        for (timer = m_timers.begin(); timer != m_timers.end(); ++timer)
            if ((*timer)->request() == req)
                break;
        if (timer != m_timers.end()) {
            m_timers.removeOne(*timer);
            delete *timer;
        }
        m_timeoutMutex.unlock();
        return true;
    }
}

void OrganizerAsynchProcess::timeout(OrganizerRequestTimeoutTimer *timer)
{
    m_timeoutMutex.lock();
    if (m_activeRequests.contains(timer->request())) {
        m_activeRequests.remove(timer->request());
        m_timers.removeOne(timer);
        delete timer;
    }
    m_timeoutMutex.unlock();
}

void OrganizerAsynchProcess::processRequest()
{
    m_mainMutex.lock();

    if (m_requestQueue.isEmpty()) {
        m_mainMutex.unlock();
        return;
    }

    QOrganizerItemAbstractRequest *req = m_requestQueue.dequeue();
    if (!req->state() == QOrganizerItemAbstractRequest::InactiveState) {
        m_mainMutex.unlock();
        return;
    }

    QOrganizerItemManagerEngine::updateRequestState(req, QOrganizerItemAbstractRequest::ActiveState);

    switch(req->type()) {
    case QOrganizerItemAbstractRequest::ItemInstanceFetchRequest:
        handleItemInstanceFetchRequest(static_cast<QOrganizerItemInstanceFetchRequest *>(req));
        break;
    case QOrganizerItemAbstractRequest::ItemFetchRequest:
        handleItemFetchRequest(static_cast<QOrganizerItemFetchRequest *>(req));
        break;
    case QOrganizerItemAbstractRequest::ItemLocalIdFetchRequest:
        handleLocalIdFetchRequest(static_cast<QOrganizerItemLocalIdFetchRequest *>(req));
        break;
    case QOrganizerItemAbstractRequest::ItemRemoveRequest:
        handleItemRemoveRequest(static_cast<QOrganizerItemRemoveRequest *>(req));
        break;
    case QOrganizerItemAbstractRequest::ItemSaveRequest:
        handleSaveRequest(static_cast<QOrganizerItemSaveRequest *>(req));
        break;
    case QOrganizerItemAbstractRequest::DetailDefinitionFetchRequest:
        handleDefinitionFetchRequest(static_cast<QOrganizerItemDetailDefinitionFetchRequest *>(req));
        break;
    case QOrganizerItemAbstractRequest::DetailDefinitionRemoveRequest:
        handleDefinitionRemoveRequest(static_cast<QOrganizerItemDetailDefinitionRemoveRequest *>(req));
        break;
    case QOrganizerItemAbstractRequest::DetailDefinitionSaveRequest:
        handleDefinitionSaveRequest(static_cast<QOrganizerItemDetailDefinitionSaveRequest *>(req));
        break;
    case QOrganizerItemAbstractRequest::CollectionFetchRequest:
        handleCollectionFetchRequest(static_cast<QOrganizerCollectionFetchRequest *>(req));
        break;
    case QOrganizerItemAbstractRequest::CollectionLocalIdFetchRequest:
        handleCollectionLocalIdFetchRequest(static_cast<QOrganizerCollectionLocalIdFetchRequest *>(req));
        break;
    case QOrganizerItemAbstractRequest::CollectionRemoveRequest:
        handleCollectionRemoveRequest(static_cast<QOrganizerCollectionRemoveRequest *>(req));
        break;
    case QOrganizerItemAbstractRequest::CollectionSaveRequest:
        handleCollectionSaveRequest(static_cast<QOrganizerCollectionSaveRequest *>(req));
        break;

    default:
        // invalid request
        break;
    }

    m_mainMutex.unlock();
}

void OrganizerAsynchProcess::handleItemInstanceFetchRequest(QOrganizerItemInstanceFetchRequest *req)
{
    QOrganizerItemManager::Error err = QOrganizerItemManager::NoError;
    QList<QOrganizerItem> items = m_engine->itemInstances(req->filter(), req->sorting(), req->fetchHint(), &err);
    QOrganizerItemManagerEngine::updateItemInstanceFetchRequest(req, items, err, QOrganizerItemAbstractRequest::FinishedState);
}

void OrganizerAsynchProcess::handleItemFetchRequest(QOrganizerItemFetchRequest *req)
{
    QOrganizerItemManager::Error err = QOrganizerItemManager::NoError;
    QList<QOrganizerItem> items = m_engine->items(req->filter(), req->sorting(), req->fetchHint(), &err);
    QOrganizerItemManagerEngine::updateItemFetchRequest(req, items, err, QOrganizerItemAbstractRequest::FinishedState);
}

void OrganizerAsynchProcess::handleLocalIdFetchRequest(QOrganizerItemLocalIdFetchRequest *req)
{
    QOrganizerItemManager::Error err = QOrganizerItemManager::NoError;
    QList<QOrganizerItemLocalId> ids = m_engine->itemIds(req->filter(), req->sorting(), &err);
    QOrganizerItemManagerEngine::updateItemLocalIdFetchRequest(req, ids, err, QOrganizerItemAbstractRequest::FinishedState);
}

void OrganizerAsynchProcess::handleItemRemoveRequest(QOrganizerItemRemoveRequest *req)
{
    QOrganizerItemManager::Error err = QOrganizerItemManager::NoError;
    QMap<int, QOrganizerItemManager::Error> errorMap;
    m_engine->removeItems(req->itemIds(), &errorMap, &err);
    QOrganizerItemManagerEngine::updateItemRemoveRequest(req, err, errorMap, QOrganizerItemAbstractRequest::FinishedState);
}

void OrganizerAsynchProcess::handleSaveRequest(QOrganizerItemSaveRequest *req)
{
    QOrganizerItemManager::Error err = QOrganizerItemManager::NoError;
    QMap<int, QOrganizerItemManager::Error> errorMap;
    QList<QOrganizerItem> items = req->items();
    m_engine->saveItems(&items, req->collectionId(), &errorMap, &err);
    QOrganizerItemManagerEngine::updateItemSaveRequest(req, items, err, errorMap, QOrganizerItemAbstractRequest::FinishedState);
}

void OrganizerAsynchProcess::handleDefinitionFetchRequest(QOrganizerItemDetailDefinitionFetchRequest *req)
{
    Q_UNUSED(req);
    // TODO: Probably this is not needed as detail definitions are handled in API
}

void OrganizerAsynchProcess::handleDefinitionRemoveRequest(QOrganizerItemDetailDefinitionRemoveRequest *req)
{
    Q_UNUSED(req);
    // TODO: Probably this is not needed as detail definitions are handled in API
}

void OrganizerAsynchProcess::handleDefinitionSaveRequest(QOrganizerItemDetailDefinitionSaveRequest *req)
{
    Q_UNUSED(req);
    // TODO: Probably this is not needed as detail definitions are handled in API
}

void OrganizerAsynchProcess::handleCollectionFetchRequest(QOrganizerCollectionFetchRequest *req)
{
    QOrganizerItemManager::Error err = QOrganizerItemManager::NoError;
    QList<QOrganizerCollection> collections = m_engine->collections(req->collectionIds(), &err);
    QOrganizerItemManagerEngine::updateCollectionFetchRequest(req, collections, err, QOrganizerItemAbstractRequest::FinishedState);
}

void OrganizerAsynchProcess::handleCollectionLocalIdFetchRequest(QOrganizerCollectionLocalIdFetchRequest *req)
{
    QOrganizerItemManager::Error err = QOrganizerItemManager::NoError;
    QList<QOrganizerCollectionLocalId> collectionIds = m_engine->collectionIds(&err);
    QOrganizerItemManagerEngine::updateCollectionLocalIdFetchRequest(req, collectionIds, err, QOrganizerItemAbstractRequest::FinishedState);
}

void OrganizerAsynchProcess::handleCollectionRemoveRequest(QOrganizerCollectionRemoveRequest *req)
{
    QOrganizerItemManager::Error err = QOrganizerItemManager::NoError;
    QMap<int, QOrganizerItemManager::Error> errorMap;
    int i = 0;
    foreach (QOrganizerCollectionLocalId id, req->collectionIds()) {
        m_engine->removeCollection(id, &err);
        errorMap.insert(i, err);
        i++;
    }
    QOrganizerItemManagerEngine::updateCollectionRemoveRequest(req, err, errorMap, QOrganizerItemAbstractRequest::FinishedState);
}

void OrganizerAsynchProcess::handleCollectionSaveRequest(QOrganizerCollectionSaveRequest *req)
{
    QOrganizerItemManager::Error err = QOrganizerItemManager::NoError;
    QMap<int, QOrganizerItemManager::Error> errorMap;
    QList<QOrganizerCollection> collections = req->collections();
    int i = 0;
    foreach (QOrganizerCollection collection, collections) {
        m_engine->saveCollection(&collection, &err);
        errorMap.insert(i, err);
        i++;
    }
    QOrganizerItemManagerEngine::updateCollectionSaveRequest(req, collections, err, errorMap, QOrganizerItemAbstractRequest::FinishedState);
}
<commit_msg>Fix compile error in maemo5 backend due to API break<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qorganizerasynchprocess.h"
#include "qtorganizer.h"
#include "qorganizermaemo5_p.h"
#include "qorganizermaemo5ids_p.h"
#include <QtCore/qtimer.h>
#include <QtCore/qcoreapplication.h>

QTM_USE_NAMESPACE

OrganizerRequestTimeoutTimer::OrganizerRequestTimeoutTimer(QOrganizerItemAbstractRequest *req, int msecs)
    : m_req(req)
{
    m_timeoutTimer = new QTimer();
    connect(m_timeoutTimer, SIGNAL(timeout()), this, SLOT(internalTimeout()));
    m_timeoutTimer->setSingleShot(true);
    m_timeoutTimer->start(msecs);
}

OrganizerRequestTimeoutTimer::~OrganizerRequestTimeoutTimer()
{
    delete m_timeoutTimer;
}

QOrganizerItemAbstractRequest* OrganizerRequestTimeoutTimer::request() const
{
    return m_req;
}

void OrganizerRequestTimeoutTimer::internalTimeout()
{
    emit timeout(this);
}

OrganizerAsynchProcess::OrganizerAsynchProcess(QOrganizerItemMaemo5Engine* engine)
    : m_engine(engine), m_quitNow(false)
{
    start();
    QObject::moveToThread(this);
}

void OrganizerAsynchProcess::run()
{
    while(!m_quitNow) {
        yieldCurrentThread();
        processRequest();
    }

    // Inform that the thread quits now
    m_quitNow = false;
}

OrganizerAsynchProcess::~OrganizerAsynchProcess()
{
    // Tell thread to quit
    m_quitNow = true;

    // Wait for run() to exit
    while(m_quitNow)
        yieldCurrentThread();
}

void OrganizerAsynchProcess::requestDestroyed(QOrganizerItemAbstractRequest *req)
{
    bool requestRemoved = false;

    if (req->state() != QOrganizerItemAbstractRequest::ActiveState) {
        m_mainMutex.lock();
        m_requestQueue.removeOne(req);
        m_mainMutex.unlock();
        requestRemoved = true;
    }

    if (!requestRemoved)
        waitForRequestFinished(req);
}

bool OrganizerAsynchProcess::addRequest(QOrganizerItemAbstractRequest *req)
{
    QOrganizerItemManagerEngine::updateRequestState(req, QOrganizerItemAbstractRequest::InactiveState);
    m_requestQueue.enqueue(req);
    return true;
}

bool OrganizerAsynchProcess::cancelRequest(QOrganizerItemAbstractRequest *req)
{
    m_mainMutex.lock();
    if (req->state() != QOrganizerItemAbstractRequest::ActiveState) {
        QOrganizerItemManagerEngine::updateRequestState(req, QOrganizerItemAbstractRequest::CanceledState);
        m_requestQueue.removeOne(req);
        m_mainMutex.unlock();
        return true;
    }
    else {
        // cannot cancel active requests
        m_mainMutex.unlock();
        return false;
    }
}

bool OrganizerAsynchProcess::waitForRequestFinished(QOrganizerItemAbstractRequest *req, int msecs)
{
    if (req->state() == QOrganizerItemAbstractRequest::FinishedState)
        return true;
    else if (req->state() == QOrganizerItemAbstractRequest::CanceledState)
        return false;

    // Multiple timers are created to make this method thread safe.
    // There's a timer for each calling thread.
    OrganizerRequestTimeoutTimer* newTimer = new OrganizerRequestTimeoutTimer(req, msecs);
    connect(newTimer, SIGNAL(timeout(OrganizerRequestTimeoutTimer*)), this, SLOT(timeout(OrganizerRequestTimeoutTimer*)));
    m_timers << newTimer;
    return waitForRequestFinished(req);
}

bool OrganizerAsynchProcess::waitForRequestFinished(QOrganizerItemAbstractRequest *req)
{
    m_activeRequests.insert(req);

    do {
        yieldCurrentThread();
        // Process events to allow the timeout timers to work
        QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers);
    } while(m_activeRequests.contains(req)
            && (req->state() == QOrganizerItemAbstractRequest::InactiveState
             || req->state() == QOrganizerItemAbstractRequest::ActiveState));

    m_timeoutMutex.lock();
    if (!m_activeRequests.contains(req)) {
        // timeout occured
        m_timeoutMutex.unlock();
        return false;
    }
    else {
        // timeout not occured
        m_activeRequests.remove(req);

        // cancel and remove timer
        QList<OrganizerRequestTimeoutTimer *>::iterator timer;
        for (timer = m_timers.begin(); timer != m_timers.end(); ++timer)
            if ((*timer)->request() == req)
                break;
        if (timer != m_timers.end()) {
            m_timers.removeOne(*timer);
            delete *timer;
        }
        m_timeoutMutex.unlock();
        return true;
    }
}

void OrganizerAsynchProcess::timeout(OrganizerRequestTimeoutTimer *timer)
{
    m_timeoutMutex.lock();
    if (m_activeRequests.contains(timer->request())) {
        m_activeRequests.remove(timer->request());
        m_timers.removeOne(timer);
        delete timer;
    }
    m_timeoutMutex.unlock();
}

void OrganizerAsynchProcess::processRequest()
{
    m_mainMutex.lock();

    if (m_requestQueue.isEmpty()) {
        m_mainMutex.unlock();
        return;
    }

    QOrganizerItemAbstractRequest *req = m_requestQueue.dequeue();
    if (!req->state() == QOrganizerItemAbstractRequest::InactiveState) {
        m_mainMutex.unlock();
        return;
    }

    QOrganizerItemManagerEngine::updateRequestState(req, QOrganizerItemAbstractRequest::ActiveState);

    switch(req->type()) {
    case QOrganizerItemAbstractRequest::ItemInstanceFetchRequest:
        handleItemInstanceFetchRequest(static_cast<QOrganizerItemInstanceFetchRequest *>(req));
        break;
    case QOrganizerItemAbstractRequest::ItemFetchRequest:
        handleItemFetchRequest(static_cast<QOrganizerItemFetchRequest *>(req));
        break;
    case QOrganizerItemAbstractRequest::ItemLocalIdFetchRequest:
        handleLocalIdFetchRequest(static_cast<QOrganizerItemLocalIdFetchRequest *>(req));
        break;
    case QOrganizerItemAbstractRequest::ItemRemoveRequest:
        handleItemRemoveRequest(static_cast<QOrganizerItemRemoveRequest *>(req));
        break;
    case QOrganizerItemAbstractRequest::ItemSaveRequest:
        handleSaveRequest(static_cast<QOrganizerItemSaveRequest *>(req));
        break;
    case QOrganizerItemAbstractRequest::DetailDefinitionFetchRequest:
        handleDefinitionFetchRequest(static_cast<QOrganizerItemDetailDefinitionFetchRequest *>(req));
        break;
    case QOrganizerItemAbstractRequest::DetailDefinitionRemoveRequest:
        handleDefinitionRemoveRequest(static_cast<QOrganizerItemDetailDefinitionRemoveRequest *>(req));
        break;
    case QOrganizerItemAbstractRequest::DetailDefinitionSaveRequest:
        handleDefinitionSaveRequest(static_cast<QOrganizerItemDetailDefinitionSaveRequest *>(req));
        break;
    case QOrganizerItemAbstractRequest::CollectionFetchRequest:
        handleCollectionFetchRequest(static_cast<QOrganizerCollectionFetchRequest *>(req));
        break;
    case QOrganizerItemAbstractRequest::CollectionLocalIdFetchRequest:
        handleCollectionLocalIdFetchRequest(static_cast<QOrganizerCollectionLocalIdFetchRequest *>(req));
        break;
    case QOrganizerItemAbstractRequest::CollectionRemoveRequest:
        handleCollectionRemoveRequest(static_cast<QOrganizerCollectionRemoveRequest *>(req));
        break;
    case QOrganizerItemAbstractRequest::CollectionSaveRequest:
        handleCollectionSaveRequest(static_cast<QOrganizerCollectionSaveRequest *>(req));
        break;

    default:
        // invalid request
        break;
    }

    m_mainMutex.unlock();
}

void OrganizerAsynchProcess::handleItemInstanceFetchRequest(QOrganizerItemInstanceFetchRequest *req)
{
    QOrganizerItemManager::Error err = QOrganizerItemManager::NoError;
    QList<QOrganizerItem> items = m_engine->itemInstances(req->filter(), req->sorting(), req->fetchHint(), &err);
    QOrganizerItemManagerEngine::updateItemInstanceFetchRequest(req, items, err, QOrganizerItemAbstractRequest::FinishedState);
}

void OrganizerAsynchProcess::handleItemFetchRequest(QOrganizerItemFetchRequest *req)
{
    QOrganizerItemManager::Error err = QOrganizerItemManager::NoError;
    QList<QOrganizerItem> items = m_engine->items(req->filter(), req->sorting(), req->fetchHint(), &err);
    QOrganizerItemManagerEngine::updateItemFetchRequest(req, items, err, QOrganizerItemAbstractRequest::FinishedState);
}

void OrganizerAsynchProcess::handleLocalIdFetchRequest(QOrganizerItemLocalIdFetchRequest *req)
{
    QOrganizerItemManager::Error err = QOrganizerItemManager::NoError;
    QList<QOrganizerItemLocalId> ids = m_engine->itemIds(req->filter(), req->sorting(), &err);
    QOrganizerItemManagerEngine::updateItemLocalIdFetchRequest(req, ids, err, QOrganizerItemAbstractRequest::FinishedState);
}

void OrganizerAsynchProcess::handleItemRemoveRequest(QOrganizerItemRemoveRequest *req)
{
    QOrganizerItemManager::Error err = QOrganizerItemManager::NoError;
    QMap<int, QOrganizerItemManager::Error> errorMap;
    m_engine->removeItems(req->itemIds(), &errorMap, &err);
    QOrganizerItemManagerEngine::updateItemRemoveRequest(req, err, errorMap, QOrganizerItemAbstractRequest::FinishedState);
}

void OrganizerAsynchProcess::handleSaveRequest(QOrganizerItemSaveRequest *req)
{
    QOrganizerItemManager::Error err = QOrganizerItemManager::NoError;
    QMap<int, QOrganizerItemManager::Error> errorMap;
    QList<QOrganizerItem> items = req->items();
    m_engine->saveItems(&items, req->collectionId(), &errorMap, &err);
    QOrganizerItemManagerEngine::updateItemSaveRequest(req, items, err, errorMap, QOrganizerItemAbstractRequest::FinishedState);
}

void OrganizerAsynchProcess::handleDefinitionFetchRequest(QOrganizerItemDetailDefinitionFetchRequest *req)
{
    Q_UNUSED(req);
    // TODO: Probably this is not needed as detail definitions are handled in API
}

void OrganizerAsynchProcess::handleDefinitionRemoveRequest(QOrganizerItemDetailDefinitionRemoveRequest *req)
{
    Q_UNUSED(req);
    // TODO: Probably this is not needed as detail definitions are handled in API
}

void OrganizerAsynchProcess::handleDefinitionSaveRequest(QOrganizerItemDetailDefinitionSaveRequest *req)
{
    Q_UNUSED(req);
    // TODO: Probably this is not needed as detail definitions are handled in API
}

void OrganizerAsynchProcess::handleCollectionFetchRequest(QOrganizerCollectionFetchRequest *req)
{
    QOrganizerItemManager::Error err = QOrganizerItemManager::NoError;
    QMap<int, QOrganizerItemManager::Error> errorMap;
    QList<QOrganizerCollection> collections = m_engine->collections(req->collectionIds(), &errorMap, &err);
    QOrganizerItemManagerEngine::updateCollectionFetchRequest(req, collections, err, errorMap, QOrganizerItemAbstractRequest::FinishedState);
}

void OrganizerAsynchProcess::handleCollectionLocalIdFetchRequest(QOrganizerCollectionLocalIdFetchRequest *req)
{
    QOrganizerItemManager::Error err = QOrganizerItemManager::NoError;
    QList<QOrganizerCollectionLocalId> collectionIds = m_engine->collectionIds(&err);
    QOrganizerItemManagerEngine::updateCollectionLocalIdFetchRequest(req, collectionIds, err, QOrganizerItemAbstractRequest::FinishedState);
}

void OrganizerAsynchProcess::handleCollectionRemoveRequest(QOrganizerCollectionRemoveRequest *req)
{
    QOrganizerItemManager::Error err = QOrganizerItemManager::NoError;
    QMap<int, QOrganizerItemManager::Error> errorMap;
    int i = 0;
    foreach (QOrganizerCollectionLocalId id, req->collectionIds()) {
        m_engine->removeCollection(id, &err);
        errorMap.insert(i, err);
        i++;
    }
    QOrganizerItemManagerEngine::updateCollectionRemoveRequest(req, err, errorMap, QOrganizerItemAbstractRequest::FinishedState);
}

void OrganizerAsynchProcess::handleCollectionSaveRequest(QOrganizerCollectionSaveRequest *req)
{
    QOrganizerItemManager::Error err = QOrganizerItemManager::NoError;
    QMap<int, QOrganizerItemManager::Error> errorMap;
    QList<QOrganizerCollection> collections = req->collections();
    int i = 0;
    foreach (QOrganizerCollection collection, collections) {
        m_engine->saveCollection(&collection, &err);
        errorMap.insert(i, err);
        i++;
    }
    QOrganizerItemManagerEngine::updateCollectionSaveRequest(req, collections, err, errorMap, QOrganizerItemAbstractRequest::FinishedState);
}
<|endoftext|>