<commit_before>// $RCSfile: $
// $Revision: $ $Date: $
// Auth: Samson Bonfante (bonfante@steptools.com)
//
// Copyright (c) 1991-2016 by STEP Tools Inc.
//
// 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 "nodeMachineState.h"
#include "nodeUtils.h"
#include <stp_schema.h>

StixSimGeomType GeomTypeFromString(char* typ)
{
    if (!strcmp(typ, "MESH"))
    {
	return STIXSIM_GT_MESH;
    }
    if (!strcmp(typ, "POLYLINE"))
    {
	return STIXSIM_GT_POLYLINE;
    }
    else
    {
	return STIXSIM_GT_NULL;
    }
}

NAN_METHOD(machineState::New)
{

    if (info.IsConstructCall()){
    	if (info.Length() == 0){
    	    return;
    	}
        else if(info.Length() == 1 || (info.Length() == 2 && info[1]->BooleanValue() == false)){
        	char * b;
        	v8StringToChar(info[0], b);
        	machineState * ms = new machineState();
        	ms->_ms = MachineState::InitializeState(b);
        	delete[] b;
        	ms->Wrap(info.This());
        	info.GetReturnValue().Set(info.This());
        }
        else if(info.Length() == 2){
            char * b;
            v8StringToChar(info[0], b);
            bool c = info[1]->BooleanValue();
            machineState * ms = new machineState();
            ms->_ms = MachineState::InitializeState(b, c);
            delete[] b;
            ms->Wrap(info.This());
            info.GetReturnValue().Set(info.This());
        }
        else{
            return;
        }
    }
    else{
	   return;
    }
}

NAN_METHOD(machineState::AdvanceState)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (!info[0]->IsUndefined()) return; //This function takes no arguments.
    int rtnval = ms->_ms->AdvanceState();
    info.GetReturnValue().Set(rtnval);
}

NAN_METHOD(machineState::GetGeometryJSON)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    //This function has a 2 argument and a no argument version.
    if (info.Length() == 0)
    {
	RoseStringObject rtn;
	ms->_ms->GetGeometryJSON(rtn);
	info.GetReturnValue().Set(CharTov8String(rtn.as_const()));
	return;
    }
    else
    {
	if (info.Length() != 2) return; // invalid number of arguments
	if (info[0]->IsUndefined()) return; //No Given ID
	if (info[1]->IsUndefined()) return; //No Given Typ
	if (!info[0]->IsString()) return; //ID is not valid
	if (!info[1]->IsString()) return; //Typ is not valid
	char * id;
	v8StringToChar(info[0], id);
	RoseObject * obj = ms->_ms->FindObjectByID(id);
	if (!obj)
	{
	    delete[] id;
	    return; //No Object Associated with given ID
	}
	char * typ;
	v8StringToChar(info[1], typ);
	RoseStringObject rtn;
	ms->_ms->GetGeometryJSON(rtn, id, obj, GeomTypeFromString(typ));
	info.GetReturnValue().Set(CharTov8String(rtn.as_const()));
	delete[] id;
	delete[] typ;
	return;
    }
}

NAN_METHOD(machineState::GetDeltaGeometryJSON)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (info.Length() != 1) //Function takes one argument
	return;
    if (!info[0]->IsNumber()) { // argument of wrong type
	return;
    }
    RoseStringObject rtn;
    ms->_ms->GetDeltaGeometryJSON(rtn,Nan::To<int32_t>(info[0]).FromJust());
    info.GetReturnValue().Set(CharTov8String(rtn.as_const()));
    return;
}

NAN_METHOD(machineState::GetDeltaStateJSON)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (!info[0]->IsUndefined()) return; //This function takes no arguments.
    RoseStringObject rtn;
    ms->_ms->GetStateJSON(rtn,false);
    info.GetReturnValue().Set(CharTov8String(rtn.as_const()));
    return;
}

NAN_METHOD(machineState::GetKeyStateJSON)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (!info[0]->IsUndefined()) return; //This function takes no arguments.
    RoseStringObject rtn;
    ms->_ms->GetStateJSON(rtn,true);
    info.GetReturnValue().Set(CharTov8String(rtn.as_const()));
    return;
}

NAN_METHOD(machineState::GoToWS)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (info.Length() != 1) //Function takes one argument
    return;
    RoseObject * obj = ms->_ms->design()->findByEntityId(Nan::To<int32_t>(info[0]).FromJust());
    if (!obj)
    return;
    stp_machining_workingstep * ws = ROSE_CAST(stp_machining_workingstep, obj);
    if(!ws)
    return;
    int rtnval = ms->_ms->GoToWS(ws);
    info.GetReturnValue().Set(rtnval);
    return;
}

NAN_METHOD(machineState::GetEIDfromUUID)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (info.Length() != 1) //Function takes one argument
    return;
    if(!info[0]->IsString())
    return;
    char * uuid = 0;
    v8StringToChar(info[0], uuid);
    RoseObject * obj = ms->_ms->FindObjectByID(uuid);
    if (!obj)
    return;
    int rtnval = obj->entity_id();
    info.GetReturnValue().Set(Nan::New(rtnval));
    return;
}

NAN_METHOD(machineState::LoadMachine)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (info[0]->IsUndefined()) return;
    char * b;
    v8StringToChar(info[0], b);
    bool success = ms->_ms->SetMachine(b);
    info.GetReturnValue().Set(success);
    delete[] b;

    return;
}

NAN_METHOD(machineState::NextWS)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (!info[0]->IsUndefined()) return; //This function takes no arguments.
    ms->_ms->GoToNextWS();
    return;
}

NAN_METHOD(machineState::PrevWS)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (!info[0]->IsUndefined()) return; //This function takes no arguments.
    ms->_ms->GoToPrevWS();
    return;
}

NAN_METHOD(machineState::GetPrevWSID)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (!info[0]->IsUndefined()) return; //This function takes no arguments.
    int id = ms->_ms->GetPrevWSID();
    info.GetReturnValue().Set(id);
    return;
}

NAN_METHOD(machineState::GetWSID)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (!info[0]->IsUndefined()) return; //This function takes no arguments.
    int id = ms->_ms->GetWSID();
    info.GetReturnValue().Set(id);
    return;
}

NAN_METHOD(machineState::GetNextWSID)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (!info[0]->IsUndefined()) return; //This function takes no arguments.
    int id = ms->_ms->GetNextWSID();
    info.GetReturnValue().Set(id);
    return;
}

NAN_METHOD(machineState::GetCurrentFeedrate)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (!info[0]->IsUndefined()) return; //This function takes no arguments.
    double feed = ms->_ms->GetCurrentFeedrate();
    info.GetReturnValue().Set(feed);
    return;
}

NAN_METHOD(machineState::GetCurrentSpindleSpeed)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (!info[0]->IsUndefined()) return; //This function takes no arguments.
    double speed = ms->_ms->GetCurrentSpindleSpeed();
    info.GetReturnValue().Set(speed);
    return;
}

NAN_METHOD(machineState::SetToolPosition)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (info.Length() != 6) return;    // bad input

    double xyz[3];
    double ijk[3];

    for (int i=0; i<3; i++) {
	if (info[i]->IsUndefined()) return; // throw ex
	if (!info[i]->IsNumber()) return; // needs to be a number

	Nan::Maybe<double> num = Nan::To<double>(info[i]);

	xyz[i] = num.FromJust();
    }

    for (int i=3; i<6; i++) {
	if (info[i]->IsUndefined()) return; // bad input
	if (!info[i]->IsNumber()) return; // check for number

	Nan::Maybe<double> num = Nan::To<double>(info[i]);

	ijk[i - 3] = num.FromJust();
    }

    ms->_ms->SetToolPosition(xyz, ijk);
    return;
}

NAN_MODULE_INIT(machineState::Init)
{
    v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
    tpl->SetClassName(Nan::New("machineState").ToLocalChecked());
    tpl->InstanceTemplate()->SetInternalFieldCount(1);

    Nan::SetPrototypeMethod(tpl, "AdvanceState", AdvanceState);
    Nan::SetPrototypeMethod(tpl, "GetGeometryJSON", GetGeometryJSON);
    Nan::SetPrototypeMethod(tpl, "GetDeltaGeometryJSON", GetDeltaGeometryJSON);
    Nan::SetPrototypeMethod(tpl, "GetDeltaStateJSON", GetDeltaStateJSON);
    Nan::SetPrototypeMethod(tpl, "GetKeyStateJSON", GetKeyStateJSON);
    Nan::SetPrototypeMethod(tpl, "GoToWS", GoToWS);
    Nan::SetPrototypeMethod(tpl, "GetEIDfromUUID", GetEIDfromUUID);
    Nan::SetPrototypeMethod(tpl, "LoadMachine", LoadMachine);
    Nan::SetPrototypeMethod(tpl, "NextWS", NextWS);
    Nan::SetPrototypeMethod(tpl, "PrevWS", PrevWS);
    Nan::SetPrototypeMethod(tpl, "GetPrevWSID", GetPrevWSID);
    Nan::SetPrototypeMethod(tpl, "GetWSID", GetWSID);
    Nan::SetPrototypeMethod(tpl, "GetNextWSID", GetNextWSID);
    Nan::SetPrototypeMethod(tpl, "GetCurrentFeedrate", GetCurrentFeedrate);
    Nan::SetPrototypeMethod(tpl, "GetCurrentSpindleSpeed", GetCurrentSpindleSpeed);
    Nan::SetPrototypeMethod(tpl, "SetToolPosition", SetToolPosition);
    constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
    Nan::Set(target, Nan::New("machineState").ToLocalChecked(), Nan::GetFunction(tpl).ToLocalChecked());

    MachineState::init();
}
<commit_msg>account for rename of deltageom to dynamicgeom<commit_after>// $RCSfile: $
// $Revision: $ $Date: $
// Auth: Samson Bonfante (bonfante@steptools.com)
//
// Copyright (c) 1991-2016 by STEP Tools Inc.
//
// 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 "nodeMachineState.h"
#include "nodeUtils.h"
#include <stp_schema.h>

StixSimGeomType GeomTypeFromString(char* typ)
{
    if (!strcmp(typ, "MESH"))
    {
	return STIXSIM_GT_MESH;
    }
    if (!strcmp(typ, "POLYLINE"))
    {
	return STIXSIM_GT_POLYLINE;
    }
    else
    {
	return STIXSIM_GT_NULL;
    }
}

NAN_METHOD(machineState::New)
{

    if (info.IsConstructCall()){
    	if (info.Length() == 0){
    	    return;
    	}
        else if(info.Length() == 1 || (info.Length() == 2 && info[1]->BooleanValue() == false)){
        	char * b;
        	v8StringToChar(info[0], b);
        	machineState * ms = new machineState();
        	ms->_ms = MachineState::InitializeState(b);
        	delete[] b;
        	ms->Wrap(info.This());
        	info.GetReturnValue().Set(info.This());
        }
        else if(info.Length() == 2){
            char * b;
            v8StringToChar(info[0], b);
            bool c = info[1]->BooleanValue();
            machineState * ms = new machineState();
            ms->_ms = MachineState::InitializeState(b, c);
            delete[] b;
            ms->Wrap(info.This());
            info.GetReturnValue().Set(info.This());
        }
        else{
            return;
        }
    }
    else{
	   return;
    }
}

NAN_METHOD(machineState::AdvanceState)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (!info[0]->IsUndefined()) return; //This function takes no arguments.
    int rtnval = ms->_ms->AdvanceState();
    info.GetReturnValue().Set(rtnval);
}

NAN_METHOD(machineState::GetGeometryJSON)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    //This function has a 2 argument and a no argument version.
    if (info.Length() == 0)
    {
	RoseStringObject rtn;
	ms->_ms->GetGeometryJSON(rtn);
	info.GetReturnValue().Set(CharTov8String(rtn.as_const()));
	return;
    }
    else
    {
	if (info.Length() != 2) return; // invalid number of arguments
	if (info[0]->IsUndefined()) return; //No Given ID
	if (info[1]->IsUndefined()) return; //No Given Typ
	if (!info[0]->IsString()) return; //ID is not valid
	if (!info[1]->IsString()) return; //Typ is not valid
	char * id;
	v8StringToChar(info[0], id);
	RoseObject * obj = ms->_ms->FindObjectByID(id);
	if (!obj)
	{
	    delete[] id;
	    return; //No Object Associated with given ID
	}
	char * typ;
	v8StringToChar(info[1], typ);
	RoseStringObject rtn;
	ms->_ms->GetGeometryJSON(rtn, id, obj, GeomTypeFromString(typ));
	info.GetReturnValue().Set(CharTov8String(rtn.as_const()));
	delete[] id;
	delete[] typ;
	return;
    }
}

NAN_METHOD(machineState::GetDeltaGeometryJSON)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (info.Length() != 1) //Function takes one argument
	return;
    if (!info[0]->IsNumber()) { // argument of wrong type
	return;
    }
    RoseStringObject rtn;
    ms->_ms->GetDynamicGeometryJSON(rtn,Nan::To<int32_t>(info[0]).FromJust());
    info.GetReturnValue().Set(CharTov8String(rtn.as_const()));
    return;
}

NAN_METHOD(machineState::GetDeltaStateJSON)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (!info[0]->IsUndefined()) return; //This function takes no arguments.
    RoseStringObject rtn;
    ms->_ms->GetStateJSON(rtn,false);
    info.GetReturnValue().Set(CharTov8String(rtn.as_const()));
    return;
}

NAN_METHOD(machineState::GetKeyStateJSON)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (!info[0]->IsUndefined()) return; //This function takes no arguments.
    RoseStringObject rtn;
    ms->_ms->GetStateJSON(rtn,true);
    info.GetReturnValue().Set(CharTov8String(rtn.as_const()));
    return;
}

NAN_METHOD(machineState::GoToWS)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (info.Length() != 1) //Function takes one argument
    return;
    RoseObject * obj = ms->_ms->design()->findByEntityId(Nan::To<int32_t>(info[0]).FromJust());
    if (!obj)
    return;
    stp_machining_workingstep * ws = ROSE_CAST(stp_machining_workingstep, obj);
    if(!ws)
    return;
    int rtnval = ms->_ms->GoToWS(ws);
    info.GetReturnValue().Set(rtnval);
    return;
}

NAN_METHOD(machineState::GetEIDfromUUID)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (info.Length() != 1) //Function takes one argument
    return;
    if(!info[0]->IsString())
    return;
    char * uuid = 0;
    v8StringToChar(info[0], uuid);
    RoseObject * obj = ms->_ms->FindObjectByID(uuid);
    if (!obj)
    return;
    int rtnval = obj->entity_id();
    info.GetReturnValue().Set(Nan::New(rtnval));
    return;
}

NAN_METHOD(machineState::LoadMachine)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (info[0]->IsUndefined()) return;
    char * b;
    v8StringToChar(info[0], b);
    bool success = ms->_ms->SetMachine(b);
    info.GetReturnValue().Set(success);
    delete[] b;

    return;
}

NAN_METHOD(machineState::NextWS)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (!info[0]->IsUndefined()) return; //This function takes no arguments.
    ms->_ms->GoToNextWS();
    return;
}

NAN_METHOD(machineState::PrevWS)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (!info[0]->IsUndefined()) return; //This function takes no arguments.
    ms->_ms->GoToPrevWS();
    return;
}

NAN_METHOD(machineState::GetPrevWSID)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (!info[0]->IsUndefined()) return; //This function takes no arguments.
    int id = ms->_ms->GetPrevWSID();
    info.GetReturnValue().Set(id);
    return;
}

NAN_METHOD(machineState::GetWSID)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (!info[0]->IsUndefined()) return; //This function takes no arguments.
    int id = ms->_ms->GetWSID();
    info.GetReturnValue().Set(id);
    return;
}

NAN_METHOD(machineState::GetNextWSID)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (!info[0]->IsUndefined()) return; //This function takes no arguments.
    int id = ms->_ms->GetNextWSID();
    info.GetReturnValue().Set(id);
    return;
}

NAN_METHOD(machineState::GetCurrentFeedrate)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (!info[0]->IsUndefined()) return; //This function takes no arguments.
    double feed = ms->_ms->GetCurrentFeedrate();
    info.GetReturnValue().Set(feed);
    return;
}

NAN_METHOD(machineState::GetCurrentSpindleSpeed)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (!info[0]->IsUndefined()) return; //This function takes no arguments.
    double speed = ms->_ms->GetCurrentSpindleSpeed();
    info.GetReturnValue().Set(speed);
    return;
}

NAN_METHOD(machineState::SetToolPosition)
{
    machineState * ms = Nan::ObjectWrap::Unwrap<machineState>(info.This());
    if (!ms || !(ms->_ms)) return;
    if (info.Length() != 6) return;    // bad input

    double xyz[3];
    double ijk[3];

    for (int i=0; i<3; i++) {
	if (info[i]->IsUndefined()) return; // throw ex
	if (!info[i]->IsNumber()) return; // needs to be a number

	Nan::Maybe<double> num = Nan::To<double>(info[i]);

	xyz[i] = num.FromJust();
    }

    for (int i=3; i<6; i++) {
	if (info[i]->IsUndefined()) return; // bad input
	if (!info[i]->IsNumber()) return; // check for number

	Nan::Maybe<double> num = Nan::To<double>(info[i]);

	ijk[i - 3] = num.FromJust();
    }

    ms->_ms->SetToolPosition(xyz, ijk);
    return;
}

NAN_MODULE_INIT(machineState::Init)
{
    v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
    tpl->SetClassName(Nan::New("machineState").ToLocalChecked());
    tpl->InstanceTemplate()->SetInternalFieldCount(1);

    Nan::SetPrototypeMethod(tpl, "AdvanceState", AdvanceState);
    Nan::SetPrototypeMethod(tpl, "GetGeometryJSON", GetGeometryJSON);
    Nan::SetPrototypeMethod(tpl, "GetDeltaGeometryJSON", GetDeltaGeometryJSON);
    Nan::SetPrototypeMethod(tpl, "GetDeltaStateJSON", GetDeltaStateJSON);
    Nan::SetPrototypeMethod(tpl, "GetKeyStateJSON", GetKeyStateJSON);
    Nan::SetPrototypeMethod(tpl, "GoToWS", GoToWS);
    Nan::SetPrototypeMethod(tpl, "GetEIDfromUUID", GetEIDfromUUID);
    Nan::SetPrototypeMethod(tpl, "LoadMachine", LoadMachine);
    Nan::SetPrototypeMethod(tpl, "NextWS", NextWS);
    Nan::SetPrototypeMethod(tpl, "PrevWS", PrevWS);
    Nan::SetPrototypeMethod(tpl, "GetPrevWSID", GetPrevWSID);
    Nan::SetPrototypeMethod(tpl, "GetWSID", GetWSID);
    Nan::SetPrototypeMethod(tpl, "GetNextWSID", GetNextWSID);
    Nan::SetPrototypeMethod(tpl, "GetCurrentFeedrate", GetCurrentFeedrate);
    Nan::SetPrototypeMethod(tpl, "GetCurrentSpindleSpeed", GetCurrentSpindleSpeed);
    Nan::SetPrototypeMethod(tpl, "SetToolPosition", SetToolPosition);
    constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
    Nan::Set(target, Nan::New("machineState").ToLocalChecked(), Nan::GetFunction(tpl).ToLocalChecked());

    MachineState::init();
}
<|endoftext|>


<commit_before>#include "driver.hpp"

#include <csignal>
#include <cstdlib>
#include <ctime>
#include <exception>
#include <iostream>
#include <iomanip>
#include <omp.h>
#include <sstream>

#include "core/core_mesh.hpp"
#include "core/error.hpp"
#include "core/files.hpp"
#include "core/global_config.hpp"
#include "core/h5file.hpp"
#include "core/solver.hpp"
#include "core/timers.hpp"
#include "core/transport_sweeper.hpp"

#include "git_SHA1.hpp"
#include "input_proc.hpp"

using std::cout;
using std::cin;
using std::endl;

using namespace mocc;

// The global top-level solver
SP_Solver_t solver;

// Global core mesh
SP_CoreMesh_t mesh;

// Input processor
std::unique_ptr<InputProc> input_proc;

// Generate output from the solver
void generate_output() {
    std::string out_name = input_proc->case_name();
    out_name.append(".h5");
    H5Node outfile( out_name, H5Access::WRITE );
    solver->output( outfile );

    LogFile << std::endl;
    LogFile << "Full input:" << std::endl;

    std::stringstream filestream;

    input_proc->document().save(filestream);
    outfile.write("input_file", filestream.str());

    outfile.write("git_sha1", std::string(g_GIT_SHA1));
}

// Print the MOCC banner. Pretty!
void print_banner();

// Signal handler for SIGINT. Calls output() and quits
void int_handler(int p) {
    std::cout << "Caught SIGINT. Bailing." << std::endl;
    generate_output();
    std::exit(EXIT_FAILURE);
}

/**
 * This does the whole shebang: open and parse the input file pointed to by \p
 * file, producing a \ref Solver and \ref CoreMesh, calling \ref
 * Solver::Solve(), then calling \ref Solver::output().
 *
 * To give some rhyme to the reason for why this isn't just \c main(): This is
 * so that integration tests can link against the driver, and call \c run(),
 * then interpret the results after, without collisions of \c main(). For the
 * actual MOCC entry point, look in \c mocc.cpp, which just calls this function.
 */
int run( std::string file ) {
    std::signal( SIGINT, int_handler );

    print_banner();

    try {
        RootTimer.tic();

        // Set up an input processor
        input_proc.reset( new InputProc(file) );

        // Spin up the log file. We do this after we peek at the input
        // processor for a case_name tag
        StartLogFile(input_proc->case_name());

        LogScreen << "Running case: " << input_proc->case_name() << std::endl;
        LogScreen << "Using MOCC executable built with GIT SHA1: " <<
            g_GIT_SHA1 << std::endl;
        {
            time_t t;
            time(&t);
            LogScreen << "Local time: " << ctime(&t);
        }
        LogScreen << std::endl << std::endl;

#pragma omp parallel
        {
#pragma omp master
            {
                LogFile << "Running with " << omp_get_num_threads() << " treads"
                    << std::endl;
            }
        }

        // Actually process the XML input. We waited until now to do this,
        // because we want to be able to log the progress to a file, but needed
        // a case_name from the input file to be processed.
        input_proc->process();

        // Get an SP to the core mesh
        mesh = input_proc->core_mesh();
        LogFile << *mesh << endl;

        // Pull a shared pointer to the top-level solver and make it go
        solver = input_proc->solver();
        solver->solve();

        // Output stuff
        generate_output();

        RootTimer.toc();
        std::cout << RootTimer << std::endl;
        RootTimer.print(LogFile);

        StopLogFile();
    }

    catch(Exception e) {
        cout << "Error:" << endl;
        cout << e.what();
        return 1;
    }
    return 0;
}

void print_banner() {
    std::string space = "                         ";
    std::cout << space << "01001101010011110100001101000011" << std::endl;
    std::cout << space << " __  __   _____   _____   _____" <<std::endl;
    std::cout << space << "|  \\/  | |  _  | /  __ \\ /  __ \\" << std::endl;
    std::cout << space << "| .  . | | | | | | /  \\/ | /  \\/" << std::endl;
    std::cout << space << "| |\\/| | | | | | | |     | |    " << std::endl;
    std::cout << space << "| |  | | \\ \\_/ / | \\__/\\ | \\__/ " << std::endl;
    std::cout << space << "\\_|  |_/  \\___/   \\____/  \\____/" << std::endl;
    std::cout << space << std::endl;
    std::cout << space << "01101101011011110110001101100011 " << std::endl;
}
<commit_msg>Fix doc refs<commit_after>#include "driver.hpp"

#include <csignal>
#include <cstdlib>
#include <ctime>
#include <exception>
#include <iostream>
#include <iomanip>
#include <omp.h>
#include <sstream>

#include "core/core_mesh.hpp"
#include "core/error.hpp"
#include "core/files.hpp"
#include "core/global_config.hpp"
#include "core/h5file.hpp"
#include "core/solver.hpp"
#include "core/timers.hpp"
#include "core/transport_sweeper.hpp"

#include "git_SHA1.hpp"
#include "input_proc.hpp"

using std::cout;
using std::cin;
using std::endl;

using namespace mocc;

// The global top-level solver
SP_Solver_t solver;

// Global core mesh
SP_CoreMesh_t mesh;

// Input processor
std::unique_ptr<InputProc> input_proc;

// Generate output from the solver
void generate_output() {
    std::string out_name = input_proc->case_name();
    out_name.append(".h5");
    H5Node outfile( out_name, H5Access::WRITE );
    solver->output( outfile );

    LogFile << std::endl;
    LogFile << "Full input:" << std::endl;

    std::stringstream filestream;

    input_proc->document().save(filestream);
    outfile.write("input_file", filestream.str());

    outfile.write("git_sha1", std::string(g_GIT_SHA1));
}

// Print the MOCC banner. Pretty!
void print_banner();

// Signal handler for SIGINT. Calls output() and quits
void int_handler(int p) {
    std::cout << "Caught SIGINT. Bailing." << std::endl;
    generate_output();
    std::exit(EXIT_FAILURE);
}

/**
 * This does the whole shebang: open and parse the input file pointed to by \p
 * file, producing a \ref mocc::Solver and \ref mocc::CoreMesh, calling \ref
 * mocc::Solver::Solve(), then calling \ref mocc::Solver::output().
 *
 * To give some rhyme to the reason for why this isn't just \c main(): This is
 * so that integration tests can link against the driver, and call \c run(),
 * then interpret the results after, without collisions of \c main(). For the
 * actual MOCC entry point, look in \c mocc.cpp, which just calls this function.
 */
int run( std::string file ) {
    std::signal( SIGINT, int_handler );

    print_banner();

    try {
        RootTimer.tic();

        // Set up an input processor
        input_proc.reset( new InputProc(file) );

        // Spin up the log file. We do this after we peek at the input
        // processor for a case_name tag
        StartLogFile(input_proc->case_name());

        LogScreen << "Running case: " << input_proc->case_name() << std::endl;
        LogScreen << "Using MOCC executable built with GIT SHA1: " <<
            g_GIT_SHA1 << std::endl;
        {
            time_t t;
            time(&t);
            LogScreen << "Local time: " << ctime(&t);
        }
        LogScreen << std::endl << std::endl;

#pragma omp parallel
        {
#pragma omp master
            {
                LogFile << "Running with " << omp_get_num_threads() << " treads"
                    << std::endl;
            }
        }

        // Actually process the XML input. We waited until now to do this,
        // because we want to be able to log the progress to a file, but needed
        // a case_name from the input file to be processed.
        input_proc->process();

        // Get an SP to the core mesh
        mesh = input_proc->core_mesh();
        LogFile << *mesh << endl;

        // Pull a shared pointer to the top-level solver and make it go
        solver = input_proc->solver();
        solver->solve();

        // Output stuff
        generate_output();

        RootTimer.toc();
        std::cout << RootTimer << std::endl;
        RootTimer.print(LogFile);

        StopLogFile();
    }

    catch(Exception e) {
        cout << "Error:" << endl;
        cout << e.what();
        return 1;
    }
    return 0;
}

void print_banner() {
    std::string space = "                         ";
    std::cout << space << "01001101010011110100001101000011" << std::endl;
    std::cout << space << " __  __   _____   _____   _____" <<std::endl;
    std::cout << space << "|  \\/  | |  _  | /  __ \\ /  __ \\" << std::endl;
    std::cout << space << "| .  . | | | | | | /  \\/ | /  \\/" << std::endl;
    std::cout << space << "| |\\/| | | | | | | |     | |    " << std::endl;
    std::cout << space << "| |  | | \\ \\_/ / | \\__/\\ | \\__/ " << std::endl;
    std::cout << space << "\\_|  |_/  \\___/   \\____/  \\____/" << std::endl;
    std::cout << space << std::endl;
    std::cout << space << "01101101011011110110001101100011 " << std::endl;
}
<|endoftext|>


<commit_before>/**
 *  For conditions of distribution and use, see copyright notice in license.txt
 *
 *  @file   JavascriptInstance.cpp
 *  @brief  Javascript script instance used wit EC_Script.
 */

#include "StableHeaders.h"
#include "DebugOperatorNew.h"
#include "MemoryLeakCheck.h"
#include "JavascriptInstance.h"
#include "JavascriptModule.h"
#include "ScriptMetaTypeDefines.h"
#include "NaaliCoreTypeDefines.h"
#include "EC_Script.h"
#include "IModule.h"
#include "AssetAPI.h"
#include "IAssetProvider.h" //to check if the code was loaded from a local or remote storage

#include "LoggingFunctions.h"
DEFINE_POCO_LOGGING_FUNCTIONS("JavascriptInstance")

#include <QFile>
#include <sstream>

//#ifndef QT_NO_SCRIPTTOOLS
//#include <QScriptEngineDebugger>
//#endif

#include "MemoryLeakCheck.h"

JavascriptInstance::JavascriptInstance(const QString &fileName, JavascriptModule *module)
:engine_(0),
sourceFile(fileName),
module_(module),
evaluated(false)
{
    CreateEngine();
    Load();
}

JavascriptInstance::JavascriptInstance(ScriptAssetPtr scriptRef, JavascriptModule *module)
:engine_(0),
scriptRef_(scriptRef),
module_(module),
evaluated(false)
{
    CreateEngine();
    Load();
}

JavascriptInstance::~JavascriptInstance()
{
    DeleteEngine();
}

void JavascriptInstance::Load()
{
    if (!engine_)
        CreateEngine();

    // Can't specify both a file source and an Asset API source.
    assert(sourceFile.isEmpty() || scriptRef_.get() == 0);

    //determine based on code origin whether it can be trusted with system access or not
    if (scriptRef_.get())
    {
        AssetProviderPtr provider = scriptRef_.get()->GetAssetProvider();
        if (provider->Name() == "Local")
            trusted_ = true;
        else
            trusted_ = false;
    }

    if (sourceFile.length() > 0)
    {
        program_ = LoadScript(sourceFile);
        trusted_ = true; //this is a local file directly, right?
    }

    // Do we even have a script to execute?
    if (program_.isEmpty() && (!scriptRef_.get() || scriptRef_->scriptContent.isEmpty()))
    {
        LogError("JavascriptInstance::Load: No script content to load!");
        return;
    }

    QString scriptSourceFilename = (scriptRef_.get() ? scriptRef_->Name() : sourceFile);
    QString &scriptContent = (scriptRef_.get() ? scriptRef_->scriptContent : program_);

    QScriptSyntaxCheckResult syntaxResult = engine_->checkSyntax(scriptContent);
    if (syntaxResult.state() != QScriptSyntaxCheckResult::Valid)
    {
        LogError("Syntax error in script " + scriptSourceFilename.toStdString() + "," + QString::number(syntaxResult.errorLineNumber()).toStdString() +
            ": " + syntaxResult.errorMessage().toStdString());

        // Delete our loaded script content (if any exists).
        program_ == "";
    }
}

QString JavascriptInstance::LoadScript(const QString &fileName)
{
    QString filename = fileName.trimmed();

    // First check if the include was supposed to go through the Asset API.
    if (module_)
    {
        ScriptAssetPtr asset = boost::dynamic_pointer_cast<ScriptAsset>(module_->GetFramework()->Asset()->GetAsset(fileName));
        if (asset)
            return asset->scriptContent;
    }

    // Otherwise, treat fileName as a local file to load up.

    QFile scriptFile(filename);
    if (!scriptFile.open(QIODevice::ReadOnly))
    {
        LogError(("JavascriptInstance::LoadScript: Failed to load script from file " + filename + "!").toStdString());
        return "";
    }

    QString result = scriptFile.readAll();
    scriptFile.close();

    QString trimmedResult = result.trimmed();
    if (trimmedResult.isEmpty())
    {
        LogWarning(("JavascriptInstance::LoadScript: Warning Loaded script from file " + filename + ", but the content was empty.").toStdString());
        return "";
    }
    return result;
}

void JavascriptInstance::Unload()
{
    DeleteEngine();
}

void JavascriptInstance::Run()
{
    // Need to have either absolute file path source or an Asset API source.
    if (!scriptRef_.get() && program_.isEmpty())
    {
        LogError("JavascriptInstance::Run: Cannot run, no script reference loaded.");
        return;
    }

    // Can't specify both a file source and an Asset API source.
    assert(sourceFile.isEmpty() || scriptRef_.get() == 0);

    // If we've already evaluated this script once before, create a new script engine to run it again, or otherwise
    // the effects would stack (we'd possibly register into signals twice, or other odd side effects).
    // We never allow a script to be run twice in this kind of "stacking" manner.
    if (evaluated)
    {
        Unload();
        Load();
    }

    if (!engine_)
    {
        LogError("JavascriptInstance::Run: Cannot run, script engine not loaded.");
        return;
    }

    // If no script specified at all, we'll have to abort.
    if (!scriptRef_.get() && program_.isEmpty())
        return;

    QString scriptSourceFilename = (scriptRef_.get() ? scriptRef_->Name() : sourceFile);
    QString &scriptContent = (scriptRef_.get() ? scriptRef_->scriptContent : program_);

    included_files_.clear();
    QScriptValue result = engine_->evaluate(scriptContent, scriptSourceFilename);
    if (engine_->hasUncaughtException())
    {
        LogError("In run/evaluate: " + result.toString().toStdString());
        QStringList trace = engine_->uncaughtExceptionBacktrace();
        QStringList::const_iterator it;
        for (it = trace.constBegin(); it != trace.constEnd(); ++it)
            LogError((*it).toLocal8Bit().constData());

        std::stringstream ss;
        int linenum = engine_->uncaughtExceptionLineNumber();
        ss << linenum;
        LogError(ss.str());
    }

    evaluated = true;
}

void JavascriptInstance::RegisterService(QObject *serviceObject, const QString &name)
{
    if (!engine_)
    {
        LogError("JavascriptInstance::RegisterService: No Qt script engine created when trying to register service to js script instance.");
        return;
    }
    if (!serviceObject)
    {
        LogError("JavascriptInstance::RegisterService: Trying to pass a null service object pointer to RegisterService!");
        return;
    }

    QScriptValue scriptValue = engine_->newQObject(serviceObject);
    engine_->globalObject().setProperty(name, scriptValue);
}

void JavascriptInstance::IncludeFile(const QString &path)
{
    for (uint i = 0; i < included_files_.size(); ++i)
    {
        if (included_files_[i].toLower() == path.toLower())
        {
            LogDebug("JavascriptInstance::IncludeFile: Not including already included file " + path.toStdString());
            return;
        }
    }

    QString script = LoadScript(path);

    QScriptContext *context = engine_->currentContext();
    assert(context);
    if (!context)
    {
        LogError("JavascriptInstance::IncludeFile: QScriptEngine::currentContext() returned null!");
        return;
    }

    QScriptContext *parent = context->parentContext();
    if (!parent)
    {
        LogError("JavascriptInstance::IncludeFile: QScriptEngine::parentContext() returned null!");
        return;
    }

    context->setActivationObject(context->parentContext()->activationObject());
    context->setThisObject(context->parentContext()->thisObject());

    QScriptSyntaxCheckResult syntaxResult = engine_->checkSyntax(script);
    if(syntaxResult.state() != QScriptSyntaxCheckResult::Valid)
    {
        LogError("JavascriptInstance::IncludeFile: Syntax error in " + path.toStdString() + syntaxResult.errorMessage().toStdString()
            + " In line:" + QString::number(syntaxResult.errorLineNumber()).toStdString());
        return;
    }

    QScriptValue result = engine_->evaluate(script);

    included_files_.push_back(path);

    if (engine_->hasUncaughtException())
        LogError(result.toString().toStdString());
}

void JavascriptInstance::ImportExtension(const QString &scriptExtensionName)
{
    assert(engine_);
    if (!engine_)
    {
        LogWarning(("JavascriptInstance::ImportExtension(" + scriptExtensionName + ") failed, QScriptEngine==null!").toStdString());
        return;
    }

    QStringList extension_whitelist; //the search is system wide, so whitelist is best to not leak to 3rd party libs
    extension_whitelist << "qt.core" << "qt.gui" << "qt.xml" << "qt.xmlpatterns" << "qt.opengl"; //webkit not allowed directly so scripts can't open hidden browsers to do malicious stuff. uitools to be investigated

    QStringList qt_blacklist; //the types in qt core&gui which are not safe. should probably be a whitelist too.
    qt_blacklist << "QDir" << "QFile" << "QFileSystemWatcher" << "QFileInfo" << "QLibrary" << "QPluginLoader" << "QProcess"; //from qtcore. should double&triplecheck. or move to whitelisting, but it's tricky to code here
    qt_blacklist << "QFileSystemModel" << "QDirModel" << "QFileDialog"; //qt.gui filesys stuff

    if (!trusted_ && !extension_whitelist.contains(scriptExtensionName, Qt::CaseInsensitive))
    {
        LogWarning("JavascriptInstance::ImportExtension: refusing to load a QtScript plugin for an untrusted instance: " + scriptExtensionName.toStdString());
        return;
    }

    QScriptValue success = engine_->importExtension(scriptExtensionName);
    if (!success.isUndefined()) // Yes, importExtension returns undefinedValue if the import succeeds. http://doc.qt.nokia.com/4.7/qscriptengine.html#importExtension
        LogWarning(std::string("JavascriptInstance::ImportExtension: Failed to load ") + scriptExtensionName.toStdString() + " plugin for QtScript!");

    if (!trusted_)
    {
        QScriptValue exposed;
        foreach (const QString &blacktype, qt_blacklist)
        {
            exposed = engine_->globalObject().property(blacktype);
            if (exposed.isValid())
            {
                engine_->globalObject().setProperty(blacktype, QScriptValue()); //passing an invalid val removes the property, http://doc.qt.nokia.com/4.6/qscriptvalue.html#setProperty
                //LogInfo("JavascriptInstance::ImportExtension: removed a type from the untrusted context: " + blacktype.toStdString());
            }
        }
    }
}

void JavascriptInstance::CreateEngine()
{
    if (engine_)
        DeleteEngine();
    engine_ = new QScriptEngine;
    connect(engine_, SIGNAL(signalHandlerException(const QScriptValue &)), SLOT(OnSignalHandlerException(const QScriptValue &)));
//#ifndef QT_NO_SCRIPTTOOLS
//    QScriptEngineDebugger debugger;
//    debugger.attachTo(engine_);
//#endif
    ExposeQtMetaTypes(engine_);
    ExposeNaaliCoreTypes(engine_);
    ExposeCoreApiMetaTypes(engine_);

    EC_Script *ec = dynamic_cast<EC_Script *>(owner_.lock().get());
    module_->PrepareScriptInstance(this, ec);
    evaluated = false;
}

void JavascriptInstance::DeleteEngine()
{
    if (!engine_)
        return;

    program_ = "";
    engine_->abortEvaluation();

    // As a convention, we call a function 'OnScriptDestroyed' for each JS script
    // so that they can clean up their data before the script is removed from the object,
    // or when the system is unloading.

    QScriptValue destructor = engine_->globalObject().property("OnScriptDestroyed");
    if (!destructor.isUndefined())
        destructor.call();
    SAFE_DELETE(engine_);
}

void JavascriptInstance::OnSignalHandlerException(const QScriptValue& exception)
{
    LogError(exception.toString().toStdString());

    QStringList trace = engine_->uncaughtExceptionBacktrace();
    QStringList::const_iterator it;
    for (it = trace.constBegin(); it != trace.constEnd(); ++it)
        LogError((*it).toStdString());

    std::stringstream ss;
    int linenum = engine_->uncaughtExceptionLineNumber();
    ss << linenum;
    LogError(ss.str());
}

<commit_msg>JS white/blacklists: open up qt.webkit (non blacklisted QWebView, QGraphicsWebView, QWebPage, QWebFrame). Added few to core/gui blacklists.<commit_after>/**
 *  For conditions of distribution and use, see copyright notice in license.txt
 *
 *  @file   JavascriptInstance.cpp
 *  @brief  Javascript script instance used wit EC_Script.
 */

#include "StableHeaders.h"
#include "DebugOperatorNew.h"
#include "MemoryLeakCheck.h"
#include "JavascriptInstance.h"
#include "JavascriptModule.h"
#include "ScriptMetaTypeDefines.h"
#include "NaaliCoreTypeDefines.h"
#include "EC_Script.h"
#include "IModule.h"
#include "AssetAPI.h"
#include "IAssetProvider.h" //to check if the code was loaded from a local or remote storage

#include "LoggingFunctions.h"
DEFINE_POCO_LOGGING_FUNCTIONS("JavascriptInstance")

#include <QFile>
#include <sstream>

//#ifndef QT_NO_SCRIPTTOOLS
//#include <QScriptEngineDebugger>
//#endif

#include "MemoryLeakCheck.h"

JavascriptInstance::JavascriptInstance(const QString &fileName, JavascriptModule *module)
:engine_(0),
sourceFile(fileName),
module_(module),
evaluated(false)
{
    CreateEngine();
    Load();
}

JavascriptInstance::JavascriptInstance(ScriptAssetPtr scriptRef, JavascriptModule *module)
:engine_(0),
scriptRef_(scriptRef),
module_(module),
evaluated(false)
{
    CreateEngine();
    Load();
}

JavascriptInstance::~JavascriptInstance()
{
    DeleteEngine();
}

void JavascriptInstance::Load()
{
    if (!engine_)
        CreateEngine();

    // Can't specify both a file source and an Asset API source.
    assert(sourceFile.isEmpty() || scriptRef_.get() == 0);

    //determine based on code origin whether it can be trusted with system access or not
    if (scriptRef_.get())
    {
        AssetProviderPtr provider = scriptRef_.get()->GetAssetProvider();
        if (provider->Name() == "Local")
            trusted_ = true;
        else
            trusted_ = false;
    }

    if (sourceFile.length() > 0)
    {
        program_ = LoadScript(sourceFile);
        trusted_ = true; //this is a local file directly, right?
    }

    // Do we even have a script to execute?
    if (program_.isEmpty() && (!scriptRef_.get() || scriptRef_->scriptContent.isEmpty()))
    {
        LogError("JavascriptInstance::Load: No script content to load!");
        return;
    }

    QString scriptSourceFilename = (scriptRef_.get() ? scriptRef_->Name() : sourceFile);
    QString &scriptContent = (scriptRef_.get() ? scriptRef_->scriptContent : program_);

    QScriptSyntaxCheckResult syntaxResult = engine_->checkSyntax(scriptContent);
    if (syntaxResult.state() != QScriptSyntaxCheckResult::Valid)
    {
        LogError("Syntax error in script " + scriptSourceFilename.toStdString() + "," + QString::number(syntaxResult.errorLineNumber()).toStdString() +
            ": " + syntaxResult.errorMessage().toStdString());

        // Delete our loaded script content (if any exists).
        program_ == "";
    }
}

QString JavascriptInstance::LoadScript(const QString &fileName)
{
    QString filename = fileName.trimmed();

    // First check if the include was supposed to go through the Asset API.
    if (module_)
    {
        ScriptAssetPtr asset = boost::dynamic_pointer_cast<ScriptAsset>(module_->GetFramework()->Asset()->GetAsset(fileName));
        if (asset)
            return asset->scriptContent;
    }

    // Otherwise, treat fileName as a local file to load up.

    QFile scriptFile(filename);
    if (!scriptFile.open(QIODevice::ReadOnly))
    {
        LogError(("JavascriptInstance::LoadScript: Failed to load script from file " + filename + "!").toStdString());
        return "";
    }

    QString result = scriptFile.readAll();
    scriptFile.close();

    QString trimmedResult = result.trimmed();
    if (trimmedResult.isEmpty())
    {
        LogWarning(("JavascriptInstance::LoadScript: Warning Loaded script from file " + filename + ", but the content was empty.").toStdString());
        return "";
    }
    return result;
}

void JavascriptInstance::Unload()
{
    DeleteEngine();
}

void JavascriptInstance::Run()
{
    // Need to have either absolute file path source or an Asset API source.
    if (!scriptRef_.get() && program_.isEmpty())
    {
        LogError("JavascriptInstance::Run: Cannot run, no script reference loaded.");
        return;
    }

    // Can't specify both a file source and an Asset API source.
    assert(sourceFile.isEmpty() || scriptRef_.get() == 0);

    // If we've already evaluated this script once before, create a new script engine to run it again, or otherwise
    // the effects would stack (we'd possibly register into signals twice, or other odd side effects).
    // We never allow a script to be run twice in this kind of "stacking" manner.
    if (evaluated)
    {
        Unload();
        Load();
    }

    if (!engine_)
    {
        LogError("JavascriptInstance::Run: Cannot run, script engine not loaded.");
        return;
    }

    // If no script specified at all, we'll have to abort.
    if (!scriptRef_.get() && program_.isEmpty())
        return;

    QString scriptSourceFilename = (scriptRef_.get() ? scriptRef_->Name() : sourceFile);
    QString &scriptContent = (scriptRef_.get() ? scriptRef_->scriptContent : program_);

    included_files_.clear();
    QScriptValue result = engine_->evaluate(scriptContent, scriptSourceFilename);
    if (engine_->hasUncaughtException())
    {
        LogError("In run/evaluate: " + result.toString().toStdString());
        QStringList trace = engine_->uncaughtExceptionBacktrace();
        QStringList::const_iterator it;
        for (it = trace.constBegin(); it != trace.constEnd(); ++it)
            LogError((*it).toLocal8Bit().constData());

        std::stringstream ss;
        int linenum = engine_->uncaughtExceptionLineNumber();
        ss << linenum;
        LogError(ss.str());
    }

    evaluated = true;
}

void JavascriptInstance::RegisterService(QObject *serviceObject, const QString &name)
{
    if (!engine_)
    {
        LogError("JavascriptInstance::RegisterService: No Qt script engine created when trying to register service to js script instance.");
        return;
    }
    if (!serviceObject)
    {
        LogError("JavascriptInstance::RegisterService: Trying to pass a null service object pointer to RegisterService!");
        return;
    }

    QScriptValue scriptValue = engine_->newQObject(serviceObject);
    engine_->globalObject().setProperty(name, scriptValue);
}

void JavascriptInstance::IncludeFile(const QString &path)
{
    for (uint i = 0; i < included_files_.size(); ++i)
    {
        if (included_files_[i].toLower() == path.toLower())
        {
            LogDebug("JavascriptInstance::IncludeFile: Not including already included file " + path.toStdString());
            return;
        }
    }

    QString script = LoadScript(path);

    QScriptContext *context = engine_->currentContext();
    assert(context);
    if (!context)
    {
        LogError("JavascriptInstance::IncludeFile: QScriptEngine::currentContext() returned null!");
        return;
    }

    QScriptContext *parent = context->parentContext();
    if (!parent)
    {
        LogError("JavascriptInstance::IncludeFile: QScriptEngine::parentContext() returned null!");
        return;
    }

    context->setActivationObject(context->parentContext()->activationObject());
    context->setThisObject(context->parentContext()->thisObject());

    QScriptSyntaxCheckResult syntaxResult = engine_->checkSyntax(script);
    if(syntaxResult.state() != QScriptSyntaxCheckResult::Valid)
    {
        LogError("JavascriptInstance::IncludeFile: Syntax error in " + path.toStdString() + syntaxResult.errorMessage().toStdString()
            + " In line:" + QString::number(syntaxResult.errorLineNumber()).toStdString());
        return;
    }

    QScriptValue result = engine_->evaluate(script);

    included_files_.push_back(path);

    if (engine_->hasUncaughtException())
        LogError(result.toString().toStdString());
}

void JavascriptInstance::ImportExtension(const QString &scriptExtensionName)
{
    assert(engine_);
    if (!engine_)
    {
        LogWarning(("JavascriptInstance::ImportExtension(" + scriptExtensionName + ") failed, QScriptEngine==null!").toStdString());
        return;
    }

    QStringList qt_extension_whitelist;
    QStringList qt_class_blacklist;

    /// Allowed extension imports
    qt_extension_whitelist << "qt.core" << "qt.gui" << "qt.xml" << "qt.xmlpatterns" << "qt.opengl" << "qt.webkit";

    /// qt.core and qt.gui: Classes that may be harmful to your system from untrusted scripts
    qt_class_blacklist << "QLibrary" << "QPluginLoader" << "QProcess"               // process and library access
                       << "QFile" << "QDir" << "QFileSystemModel" << "QDirModel"    // file system access
                       << "QFileDialog" << "QFileSystemWatcher" << "QFileInfo"
                       << "QFileOpenEvent" << "QFileSystemModel"
                       << "QClipboard" << "QDesktopServices";                       // "system" access

    /// qt.webkit: Initial blacklist, enabling some of these can be discussed.
    /// Availble classes: QWebView, QGraphicsWebView, QWebPage, QWebFrame
    qt_class_blacklist << "QWebDatabase" << "QWebElement" << "QWebElementCollection" << "QWebHistory" << "QWebHistoryInterface" << "QWebHistoryItem"
                       << "QWebHitTestResult" << "QWebInspector" << "QWebPluginFactory" << "QWebSecurityOrigin" << "QWebSettings";

    if (!trusted_ && !qt_extension_whitelist.contains(scriptExtensionName, Qt::CaseInsensitive))
    {
        LogWarning("JavascriptInstance::ImportExtension: refusing to load a QtScript plugin for an untrusted instance: " + scriptExtensionName.toStdString());
        return;
    }

    QScriptValue success = engine_->importExtension(scriptExtensionName);
    if (!success.isUndefined()) // Yes, importExtension returns undefinedValue if the import succeeds. http://doc.qt.nokia.com/4.7/qscriptengine.html#importExtension
        LogWarning(std::string("JavascriptInstance::ImportExtension: Failed to load ") + scriptExtensionName.toStdString() + " plugin for QtScript!");

    if (!trusted_)
    {
        QScriptValue exposed;
        foreach (const QString &blacktype, qt_class_blacklist)
        {
            exposed = engine_->globalObject().property(blacktype);
            if (exposed.isValid())
            {
                engine_->globalObject().setProperty(blacktype, QScriptValue()); //passing an invalid val removes the property, http://doc.qt.nokia.com/4.6/qscriptvalue.html#setProperty
                //LogInfo("JavascriptInstance::ImportExtension: removed a type from the untrusted context: " + blacktype.toStdString());
            }
        }
    }
}

void JavascriptInstance::CreateEngine()
{
    if (engine_)
        DeleteEngine();
    engine_ = new QScriptEngine;
    connect(engine_, SIGNAL(signalHandlerException(const QScriptValue &)), SLOT(OnSignalHandlerException(const QScriptValue &)));
//#ifndef QT_NO_SCRIPTTOOLS
//    QScriptEngineDebugger debugger;
//    debugger.attachTo(engine_);
//#endif
    ExposeQtMetaTypes(engine_);
    ExposeNaaliCoreTypes(engine_);
    ExposeCoreApiMetaTypes(engine_);

    EC_Script *ec = dynamic_cast<EC_Script *>(owner_.lock().get());
    module_->PrepareScriptInstance(this, ec);
    evaluated = false;
}

void JavascriptInstance::DeleteEngine()
{
    if (!engine_)
        return;

    program_ = "";
    engine_->abortEvaluation();

    // As a convention, we call a function 'OnScriptDestroyed' for each JS script
    // so that they can clean up their data before the script is removed from the object,
    // or when the system is unloading.

    QScriptValue destructor = engine_->globalObject().property("OnScriptDestroyed");
    if (!destructor.isUndefined())
        destructor.call();
    SAFE_DELETE(engine_);
}

void JavascriptInstance::OnSignalHandlerException(const QScriptValue& exception)
{
    LogError(exception.toString().toStdString());

    QStringList trace = engine_->uncaughtExceptionBacktrace();
    QStringList::const_iterator it;
    for (it = trace.constBegin(); it != trace.constEnd(); ++it)
        LogError((*it).toStdString());

    std::stringstream ss;
    int linenum = engine_->uncaughtExceptionLineNumber();
    ss << linenum;
    LogError(ss.str());
}

<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/
#include <osg/GLExtensions>
#include <osg/GL>
#include <osg/GLU>
#include <osg/Notify>
#include <osg/buffered_value>

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include <string>
#include <vector>
#include <set>

bool osg::isGLExtensionSupported(unsigned int contextID, const char *extension)
{
    typedef std::set<std::string>  ExtensionSet;
    static osg::buffered_object<ExtensionSet> s_extensionSetList;
    static osg::buffered_object<std::string> s_rendererList;
    static osg::buffered_value<int> s_initializedList;

    ExtensionSet& extensionSet = s_extensionSetList[contextID];
    std::string& rendererString = s_rendererList[contextID];

    // if not already set up, initialize all the per graphic context values.
    if (!s_initializedList[contextID])
    {
        s_initializedList[contextID] = 1;

        // set up the renderer
        const GLubyte* renderer = glGetString(GL_RENDERER);
        rendererString = renderer ? (const char*)renderer : "";

        // get the extension list from OpenGL.
        const char* extensions = (const char*)glGetString(GL_EXTENSIONS);
        if (extensions==NULL) return false;

        // insert the ' ' delimiated extensions words into the extensionSet.
        const char *startOfWord = extensions;
        const char *endOfWord;
        while ((endOfWord = strchr(startOfWord,' '))!=NULL)
        {
            extensionSet.insert(std::string(startOfWord,endOfWord));
            startOfWord = endOfWord+1;
        }
        if (*startOfWord!=0) extensionSet.insert(std::string(startOfWord));

        osg::notify(INFO)<<"OpenGL extensions supported by installed OpenGL drivers are:"<<std::endl;
        for(ExtensionSet::iterator itr=extensionSet.begin();
            itr!=extensionSet.end();
            ++itr)
        {
            osg::notify(INFO)<<"    "<<*itr<<std::endl;
        }

    }

    // true if extension found in extensionSet.
    bool result = extensionSet.find(extension)!=extensionSet.end();

    // now see if extension is in the extension disabled list
    bool extensionDisabled = false;
    if (result)
    {

        const std::string& disableString = getGLExtensionDisableString();
        if (!disableString.empty())
        {

            std::string::size_type pos=0;
            while ( pos!=std::string::npos && (pos=disableString.find(extension,pos))!=std::string::npos )
            {
                std::string::size_type previousColon = disableString.find_last_of(':',pos);
                std::string::size_type previousSemiColon = disableString.find_last_of(';',pos);

                std::string renderer = "";
                if (previousColon!=std::string::npos)
                {
                    if (previousSemiColon==std::string::npos) renderer = disableString.substr(0,previousColon);
                    else if (previousSemiColon<previousColon) renderer = disableString.substr(previousSemiColon+1,previousColon-previousSemiColon-1);
                }

                if (!renderer.empty())
                {

                    // remove leading spaces if they exist.
                    std::string::size_type leadingSpaces = renderer.find_first_not_of(' ');
                    if (leadingSpaces==std::string::npos) renderer = ""; // nothing but spaces
                    else if (leadingSpaces!=0) renderer.erase(0,leadingSpaces);

                    // remove trailing spaces if they exist.
                    std::string::size_type trailingSpaces = renderer.find_last_not_of(' ');
                    if (trailingSpaces!=std::string::npos) renderer.erase(trailingSpaces+1,std::string::npos);

                }

                if (renderer.empty())
                {
                    extensionDisabled = true;
                    break;
                }

                if (rendererString.find(renderer)!=std::string::npos)
                {
                    extensionDisabled = true;
                    break;

                }

                // move the position in the disable string along so that the same extension is found multiple times
                ++pos;
            }

        }
    }

    if (result)
    {
        if (!extensionDisabled) osg::notify(INFO)<<"OpenGL extension '"<<extension<<"' is supported."<<std::endl;
        else osg::notify(INFO)<<"OpenGL extension '"<<extension<<"' is supported by OpenGL\ndriver but has been disabled by osg::getGLExtensionDisableString()."<<std::endl;
    }
    else osg::notify(INFO)<<"OpenGL extension '"<<extension<<"' is not supported."<<std::endl;

    return result && !extensionDisabled;
}

void osg::setGLExtensionDisableString(const std::string& disableString)
{
    getGLExtensionDisableString() = disableString;
}

std::string& osg::getGLExtensionDisableString()
{
    static const char* envVar = getenv("OSG_GL_EXTENSION_DISABLE");
    static std::string s_GLExtensionDisableString(envVar?envVar:"Nothing defined");
    return s_GLExtensionDisableString;
}

bool osg::isGLUExtensionSupported(unsigned int contextID, const char *extension)
{
    typedef std::set<std::string>  ExtensionSet;
    static osg::buffered_object<ExtensionSet> s_extensionSetList;
    static osg::buffered_object<std::string> s_rendererList;
    static osg::buffered_value<int> s_initializedList;

    ExtensionSet& extensionSet = s_extensionSetList[contextID];
    std::string& rendererString = s_rendererList[contextID];

    // if not already set up, initialize all the per graphic context values.
    if (!s_initializedList[contextID])
    {
        s_initializedList[contextID] = 1;

        // set up the renderer
        const GLubyte* renderer = glGetString(GL_RENDERER);
        rendererString = renderer ? (const char*)renderer : "";

        // get the extension list from OpenGL.
        const char* extensions = (const char*)gluGetString(GLU_EXTENSIONS);
        if (extensions==NULL) return false;

        // insert the ' ' delimiated extensions words into the extensionSet.
        const char *startOfWord = extensions;
        const char *endOfWord;
        while ((endOfWord = strchr(startOfWord,' '))!=NULL)
        {
            extensionSet.insert(std::string(startOfWord,endOfWord));
            startOfWord = endOfWord+1;
        }
        if (*startOfWord!=0) extensionSet.insert(std::string(startOfWord));

        osg::notify(INFO)<<"OpenGL extensions supported by installed OpenGL drivers are:"<<std::endl;
        for(ExtensionSet::iterator itr=extensionSet.begin();
            itr!=extensionSet.end();
            ++itr)
        {
            osg::notify(INFO)<<"    "<<*itr<<std::endl;
        }

    }

    // true if extension found in extensionSet.
    bool result = extensionSet.find(extension)!=extensionSet.end();

    if (result) osg::notify(INFO)<<"OpenGL utility library extension '"<<extension<<"' is supported."<<std::endl;
    else osg::notify(INFO)<<"OpenGL utility library extension '"<<extension<<"' is not supported."<<std::endl;

    return result;
}

#if defined(WIN32)
    #define WIN32_LEAN_AND_MEAN
    #ifndef NOMINMAX
        #define NOMINMAX
    #endif // NOMINMAX
    #include <windows.h>
#elif defined(__APPLE__)
    #include <mach-o/dyld.h>
#else
    #include <dlfcn.h>
#endif

void* osg::getGLExtensionFuncPtr(const char *funcName)
{
#if defined(WIN32)

    return (void*)wglGetProcAddress(funcName);

#elif defined(__APPLE__)

    std::string temp( "_" );
    temp += funcName;    // Mac OS X prepends an underscore on function names
    if ( NSIsSymbolNameDefined( temp.c_str() ) )
    {
        NSSymbol symbol = NSLookupAndBindSymbol( temp.c_str() );
        return NSAddressOfSymbol( symbol );
    } else
        return NULL;

#elif defined (__sun)

     static void *handle = dlopen((const char *)0L, RTLD_LAZY);
     return dlsym(handle, funcName);

#elif defined (__sgi)

     static void *handle = dlopen((const char *)0L, RTLD_LAZY);
     return dlsym(handle, funcName);

#elif defined (__FreeBSD__)

    return dlsym( RTLD_DEFAULT, funcName );

#else // all other unixes

    return dlsym(0, funcName);

#endif
}
<commit_msg>Changed the linux implement of getGLExtensionFuncPtr to querry for glXGetProcAddressARB and then use this if its available, otherwise fallback to the original dlsym usage.<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/
#include <osg/GLExtensions>
#include <osg/GL>
#include <osg/GLU>
#include <osg/Notify>
#include <osg/buffered_value>

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include <string>
#include <vector>
#include <set>

bool osg::isGLExtensionSupported(unsigned int contextID, const char *extension)
{
    typedef std::set<std::string>  ExtensionSet;
    static osg::buffered_object<ExtensionSet> s_extensionSetList;
    static osg::buffered_object<std::string> s_rendererList;
    static osg::buffered_value<int> s_initializedList;

    ExtensionSet& extensionSet = s_extensionSetList[contextID];
    std::string& rendererString = s_rendererList[contextID];

    // if not already set up, initialize all the per graphic context values.
    if (!s_initializedList[contextID])
    {
        s_initializedList[contextID] = 1;

        // set up the renderer
        const GLubyte* renderer = glGetString(GL_RENDERER);
        rendererString = renderer ? (const char*)renderer : "";

        // get the extension list from OpenGL.
        const char* extensions = (const char*)glGetString(GL_EXTENSIONS);
        if (extensions==NULL) return false;

        // insert the ' ' delimiated extensions words into the extensionSet.
        const char *startOfWord = extensions;
        const char *endOfWord;
        while ((endOfWord = strchr(startOfWord,' '))!=NULL)
        {
            extensionSet.insert(std::string(startOfWord,endOfWord));
            startOfWord = endOfWord+1;
        }
        if (*startOfWord!=0) extensionSet.insert(std::string(startOfWord));

        osg::notify(INFO)<<"OpenGL extensions supported by installed OpenGL drivers are:"<<std::endl;
        for(ExtensionSet::iterator itr=extensionSet.begin();
            itr!=extensionSet.end();
            ++itr)
        {
            osg::notify(INFO)<<"    "<<*itr<<std::endl;
        }

    }

    // true if extension found in extensionSet.
    bool result = extensionSet.find(extension)!=extensionSet.end();

    // now see if extension is in the extension disabled list
    bool extensionDisabled = false;
    if (result)
    {

        const std::string& disableString = getGLExtensionDisableString();
        if (!disableString.empty())
        {

            std::string::size_type pos=0;
            while ( pos!=std::string::npos && (pos=disableString.find(extension,pos))!=std::string::npos )
            {
                std::string::size_type previousColon = disableString.find_last_of(':',pos);
                std::string::size_type previousSemiColon = disableString.find_last_of(';',pos);

                std::string renderer = "";
                if (previousColon!=std::string::npos)
                {
                    if (previousSemiColon==std::string::npos) renderer = disableString.substr(0,previousColon);
                    else if (previousSemiColon<previousColon) renderer = disableString.substr(previousSemiColon+1,previousColon-previousSemiColon-1);
                }

                if (!renderer.empty())
                {

                    // remove leading spaces if they exist.
                    std::string::size_type leadingSpaces = renderer.find_first_not_of(' ');
                    if (leadingSpaces==std::string::npos) renderer = ""; // nothing but spaces
                    else if (leadingSpaces!=0) renderer.erase(0,leadingSpaces);

                    // remove trailing spaces if they exist.
                    std::string::size_type trailingSpaces = renderer.find_last_not_of(' ');
                    if (trailingSpaces!=std::string::npos) renderer.erase(trailingSpaces+1,std::string::npos);

                }

                if (renderer.empty())
                {
                    extensionDisabled = true;
                    break;
                }

                if (rendererString.find(renderer)!=std::string::npos)
                {
                    extensionDisabled = true;
                    break;

                }

                // move the position in the disable string along so that the same extension is found multiple times
                ++pos;
            }

        }
    }

    if (result)
    {
        if (!extensionDisabled) osg::notify(INFO)<<"OpenGL extension '"<<extension<<"' is supported."<<std::endl;
        else osg::notify(INFO)<<"OpenGL extension '"<<extension<<"' is supported by OpenGL\ndriver but has been disabled by osg::getGLExtensionDisableString()."<<std::endl;
    }
    else osg::notify(INFO)<<"OpenGL extension '"<<extension<<"' is not supported."<<std::endl;

    return result && !extensionDisabled;
}

void osg::setGLExtensionDisableString(const std::string& disableString)
{
    getGLExtensionDisableString() = disableString;
}

std::string& osg::getGLExtensionDisableString()
{
    static const char* envVar = getenv("OSG_GL_EXTENSION_DISABLE");
    static std::string s_GLExtensionDisableString(envVar?envVar:"Nothing defined");
    return s_GLExtensionDisableString;
}

bool osg::isGLUExtensionSupported(unsigned int contextID, const char *extension)
{
    typedef std::set<std::string>  ExtensionSet;
    static osg::buffered_object<ExtensionSet> s_extensionSetList;
    static osg::buffered_object<std::string> s_rendererList;
    static osg::buffered_value<int> s_initializedList;

    ExtensionSet& extensionSet = s_extensionSetList[contextID];
    std::string& rendererString = s_rendererList[contextID];

    // if not already set up, initialize all the per graphic context values.
    if (!s_initializedList[contextID])
    {
        s_initializedList[contextID] = 1;

        // set up the renderer
        const GLubyte* renderer = glGetString(GL_RENDERER);
        rendererString = renderer ? (const char*)renderer : "";

        // get the extension list from OpenGL.
        const char* extensions = (const char*)gluGetString(GLU_EXTENSIONS);
        if (extensions==NULL) return false;

        // insert the ' ' delimiated extensions words into the extensionSet.
        const char *startOfWord = extensions;
        const char *endOfWord;
        while ((endOfWord = strchr(startOfWord,' '))!=NULL)
        {
            extensionSet.insert(std::string(startOfWord,endOfWord));
            startOfWord = endOfWord+1;
        }
        if (*startOfWord!=0) extensionSet.insert(std::string(startOfWord));

        osg::notify(INFO)<<"OpenGL extensions supported by installed OpenGL drivers are:"<<std::endl;
        for(ExtensionSet::iterator itr=extensionSet.begin();
            itr!=extensionSet.end();
            ++itr)
        {
            osg::notify(INFO)<<"    "<<*itr<<std::endl;
        }

    }

    // true if extension found in extensionSet.
    bool result = extensionSet.find(extension)!=extensionSet.end();

    if (result) osg::notify(INFO)<<"OpenGL utility library extension '"<<extension<<"' is supported."<<std::endl;
    else osg::notify(INFO)<<"OpenGL utility library extension '"<<extension<<"' is not supported."<<std::endl;

    return result;
}

#if defined(WIN32)
    #define WIN32_LEAN_AND_MEAN
    #ifndef NOMINMAX
        #define NOMINMAX
    #endif // NOMINMAX
    #include <windows.h>
#elif defined(__APPLE__)
    #include <mach-o/dyld.h>
#else
    #include <dlfcn.h>
#endif

void* osg::getGLExtensionFuncPtr(const char *funcName)
{
#if defined(WIN32)

    return (void*)wglGetProcAddress(funcName);

#elif defined(__APPLE__)

    std::string temp( "_" );
    temp += funcName;    // Mac OS X prepends an underscore on function names
    if ( NSIsSymbolNameDefined( temp.c_str() ) )
    {
        NSSymbol symbol = NSLookupAndBindSymbol( temp.c_str() );
        return NSAddressOfSymbol( symbol );
    } else
        return NULL;

#elif defined (__sun)

     static void *handle = dlopen((const char *)0L, RTLD_LAZY);
     return dlsym(handle, funcName);

#elif defined (__sgi)

     static void *handle = dlopen((const char *)0L, RTLD_LAZY);
     return dlsym(handle, funcName);

#elif defined (__FreeBSD__)

    return dlsym( RTLD_DEFAULT, funcName );

#elif defined (__linux__)

    typedef void (*__GLXextFuncPtr)(void);
    typedef __GLXextFuncPtr (*GetProcAddressARBProc)(const char*);
    static GetProcAddressARBProc s_glXGetProcAddressARB = (GetProcAddressARBProc)dlsym(0, "glXGetProcAddressARB");
    if (s_glXGetProcAddressARB)
    {
        return (void*) (s_glXGetProcAddressARB)(funcName);
    }
    else
    {
        return dlsym(0, funcName);
    }

#else // all other unixes

    return dlsym(0, funcName);

#endif
}
<|endoftext|>


<commit_before>/*
 *  Copyright (C) 2010, 2011 Stephen F. Booth <me@sbooth.org>
 *  All Rights Reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *
 *    - Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    - Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *    - Neither the name of Stephen F. Booth nor the names of its
 *      contributors may be used to endorse or promote products derived
 *      from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <openssl/bio.h>
#include <openssl/evp.h>

#include <taglib/flacpicture.h>

#include "AddXiphCommentToDictionary.h"
#include "AudioMetadata.h"

#pragma mark Base64 Utilities

#if 0
// Currently unused
static TagLib::ByteVector EncodeBase64(const TagLib::ByteVector& input)
{
	TagLib::ByteVector result;

	BIO *b64 = BIO_new(BIO_f_base64());
	BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);

	BIO *bio = BIO_new(BIO_s_mem());
	bio = BIO_push(b64, bio);
	BIO_write(bio, input.data(), input.size());

	void *mem = NULL;
	long size = BIO_get_mem_data(bio, &mem);
	if(0 < size)
		result.setData(static_cast<const char *>(mem), static_cast<TagLib::uint>(size));

	BIO_free_all(bio);

	return result;
}
#endif

static TagLib::ByteVector DecodeBase64(const TagLib::ByteVector& input)
{
	TagLib::ByteVector result;

	BIO *b64 = BIO_new(BIO_f_base64());
	BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);

	BIO *bio = BIO_new_mem_buf(reinterpret_cast<void *>(const_cast<char *>(input.data())), input.size());
	bio = BIO_push(b64, bio);

	char inbuf [512];
	int inlen;
	while(0 < (inlen = BIO_read(bio, inbuf, 512)))
		result.append(TagLib::ByteVector(inbuf, inlen));

	BIO_free_all(bio);

	return result;
}

bool
AddXiphCommentToDictionary(CFMutableDictionaryRef dictionary, const TagLib::Ogg::XiphComment *tag)
{
	if(NULL == dictionary || NULL == tag)
		return false;

	CFMutableDictionaryRef additionalMetadata = CFDictionaryCreateMutable(kCFAllocatorDefault,
																		  0,
																		  &kCFTypeDictionaryKeyCallBacks,
																		  &kCFTypeDictionaryValueCallBacks);

	// A map <String, StringList>
	TagLib::Ogg::FieldListMap fieldList = tag->fieldListMap();

	for(TagLib::Ogg::FieldListMap::ConstIterator it = fieldList.begin(); it != fieldList.end(); ++it) {
		CFStringRef key = CFStringCreateWithCString(kCFAllocatorDefault,
													it->first.toCString(true),
													kCFStringEncodingUTF8);

		// Vorbis allows multiple comments with the same key, but this isn't supported by AudioMetadata
		CFStringRef value = CFStringCreateWithCString(kCFAllocatorDefault,
													  it->second.front().toCString(true),
													  kCFStringEncodingUTF8);

		if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("ALBUM"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataAlbumTitleKey, value);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("ARTIST"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataArtistKey, value);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("ALBUMARTIST"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataAlbumArtistKey, value);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("COMPOSER"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataComposerKey, value);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("GENRE"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataGenreKey, value);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("DATE"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataReleaseDateKey, value);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("DESCRIPTION"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataCommentKey, value);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("TITLE"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataTitleKey, value);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("TRACKNUMBER"), kCFCompareCaseInsensitive)) {
			int num = CFStringGetIntValue(value);
			CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &num);
			CFDictionarySetValue(dictionary, kMetadataTrackNumberKey, number);
			CFRelease(number), number = NULL;
		}
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("TRACKTOTAL"), kCFCompareCaseInsensitive)) {
			int num = CFStringGetIntValue(value);
			CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &num);
			CFDictionarySetValue(dictionary, kMetadataTrackTotalKey, number);
			CFRelease(number), number = NULL;
		}
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("COMPILATION"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataCompilationKey, CFStringGetIntValue(value) ? kCFBooleanTrue : kCFBooleanFalse);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("DISCNUMBER"), kCFCompareCaseInsensitive)) {
			int num = CFStringGetIntValue(value);
			CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &num);
			CFDictionarySetValue(dictionary, kMetadataDiscNumberKey, number);
			CFRelease(number), number = NULL;
		}
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("DISCTOTAL"), kCFCompareCaseInsensitive)) {
			int num = CFStringGetIntValue(value);
			CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &num);
			CFDictionarySetValue(dictionary, kMetadataDiscTotalKey, number);
			CFRelease(number), number = NULL;
		}
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("LYRICS"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataLyricsKey, value);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("BPM"), kCFCompareCaseInsensitive)) {
			int num = CFStringGetIntValue(value);
			CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &num);
			CFDictionarySetValue(dictionary, kMetadataBPMKey, number);
			CFRelease(number), number = NULL;
		}
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("RATING"), kCFCompareCaseInsensitive)) {
			int num = CFStringGetIntValue(value);
			CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &num);
			CFDictionarySetValue(dictionary, kMetadataRatingKey, number);
			CFRelease(number), number = NULL;
		}
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("ISRC"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataISRCKey, value);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("MCN"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataMCNKey, value);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("REPLAYGAIN_REFERENCE_LOUDNESS"), kCFCompareCaseInsensitive)) {
			double num = CFStringGetDoubleValue(value);
			CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &num);
			CFDictionarySetValue(dictionary, kReplayGainReferenceLoudnessKey, number);
			CFRelease(number), number = NULL;
		}
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("REPLAYGAIN_TRACK_GAIN"), kCFCompareCaseInsensitive)) {
			double num = CFStringGetDoubleValue(value);
			CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &num);
			CFDictionarySetValue(dictionary, kReplayGainTrackGainKey, number);
			CFRelease(number), number = NULL;
		}
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("REPLAYGAIN_TRACK_PEAK"), kCFCompareCaseInsensitive)) {
			double num = CFStringGetDoubleValue(value);
			CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &num);
			CFDictionarySetValue(dictionary, kReplayGainTrackPeakKey, number);
			CFRelease(number), number = NULL;
		}
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("REPLAYGAIN_ALBUM_GAIN"), kCFCompareCaseInsensitive)) {
			double num = CFStringGetDoubleValue(value);
			CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &num);
			CFDictionarySetValue(dictionary, kReplayGainAlbumGainKey, number);
			CFRelease(number), number = NULL;
		}
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("REPLAYGAIN_ALBUM_PEAK"), kCFCompareCaseInsensitive)) {
			double num = CFStringGetDoubleValue(value);
			CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &num);
			CFDictionarySetValue(dictionary, kReplayGainAlbumPeakKey, number);
			CFRelease(number), number = NULL;
		}
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("METADATA_BLOCK_PICTURE"), kCFCompareCaseInsensitive)) {
			// Handle embedded pictures
			TagLib::StringList encodedBlocks = it->second;
			for(TagLib::StringList::ConstIterator blockIterator = encodedBlocks.begin(); blockIterator != encodedBlocks.end(); ++blockIterator) {
				const TagLib::ByteVector encodedBlock = blockIterator->data(TagLib::String::UTF8);

				// Decode the Base-64 encoded data
				TagLib::ByteVector decodedBlock = DecodeBase64(encodedBlock);

				// Create the picture
				TagLib::FLAC::Picture picture;
				picture.parse(decodedBlock);

				switch (picture.type()) {
					case TagLib::FLAC::Picture::FrontCover:
					{
						CFDataRef data = CFDataCreate(kCFAllocatorDefault, reinterpret_cast<const UInt8 *>(picture.data().data()), picture.data().size());
						CFDictionarySetValue(dictionary, kAlbumArtFrontCoverKey, data);
						CFRelease(data), data = NULL;
						break;
					}

						// TODO: Other artwork types will be handled in the future
					default:
						break;
				}
			}
		}
		// Put all unknown tags into the additional metadata
		else
			CFDictionarySetValue(additionalMetadata, key, value);

		CFRelease(key), key = NULL;
		CFRelease(value), value = NULL;
	}

	if(CFDictionaryGetCount(additionalMetadata))
		CFDictionarySetValue(dictionary, kMetadataAdditionalMetadataKey, additionalMetadata);

	CFRelease(additionalMetadata), additionalMetadata = NULL;

	return true;
}
<commit_msg>Moved EncodeBase64()<commit_after>/*
 *  Copyright (C) 2010, 2011 Stephen F. Booth <me@sbooth.org>
 *  All Rights Reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *
 *    - Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    - Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *    - Neither the name of Stephen F. Booth nor the names of its
 *      contributors may be used to endorse or promote products derived
 *      from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <openssl/bio.h>
#include <openssl/evp.h>

#include <taglib/flacpicture.h>

#include "AddXiphCommentToDictionary.h"
#include "AudioMetadata.h"

#pragma mark Base64 Utilities

static TagLib::ByteVector DecodeBase64(const TagLib::ByteVector& input)
{
	TagLib::ByteVector result;

	BIO *b64 = BIO_new(BIO_f_base64());
	BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);

	BIO *bio = BIO_new_mem_buf(reinterpret_cast<void *>(const_cast<char *>(input.data())), input.size());
	bio = BIO_push(b64, bio);

	char inbuf [512];
	int inlen;
	while(0 < (inlen = BIO_read(bio, inbuf, 512)))
		result.append(TagLib::ByteVector(inbuf, inlen));

	BIO_free_all(bio);

	return result;
}

bool
AddXiphCommentToDictionary(CFMutableDictionaryRef dictionary, const TagLib::Ogg::XiphComment *tag)
{
	if(NULL == dictionary || NULL == tag)
		return false;

	CFMutableDictionaryRef additionalMetadata = CFDictionaryCreateMutable(kCFAllocatorDefault,
																		  0,
																		  &kCFTypeDictionaryKeyCallBacks,
																		  &kCFTypeDictionaryValueCallBacks);

	// A map <String, StringList>
	TagLib::Ogg::FieldListMap fieldList = tag->fieldListMap();

	for(TagLib::Ogg::FieldListMap::ConstIterator it = fieldList.begin(); it != fieldList.end(); ++it) {
		CFStringRef key = CFStringCreateWithCString(kCFAllocatorDefault,
													it->first.toCString(true),
													kCFStringEncodingUTF8);

		// Vorbis allows multiple comments with the same key, but this isn't supported by AudioMetadata
		CFStringRef value = CFStringCreateWithCString(kCFAllocatorDefault,
													  it->second.front().toCString(true),
													  kCFStringEncodingUTF8);

		if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("ALBUM"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataAlbumTitleKey, value);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("ARTIST"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataArtistKey, value);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("ALBUMARTIST"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataAlbumArtistKey, value);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("COMPOSER"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataComposerKey, value);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("GENRE"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataGenreKey, value);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("DATE"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataReleaseDateKey, value);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("DESCRIPTION"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataCommentKey, value);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("TITLE"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataTitleKey, value);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("TRACKNUMBER"), kCFCompareCaseInsensitive)) {
			int num = CFStringGetIntValue(value);
			CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &num);
			CFDictionarySetValue(dictionary, kMetadataTrackNumberKey, number);
			CFRelease(number), number = NULL;
		}
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("TRACKTOTAL"), kCFCompareCaseInsensitive)) {
			int num = CFStringGetIntValue(value);
			CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &num);
			CFDictionarySetValue(dictionary, kMetadataTrackTotalKey, number);
			CFRelease(number), number = NULL;
		}
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("COMPILATION"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataCompilationKey, CFStringGetIntValue(value) ? kCFBooleanTrue : kCFBooleanFalse);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("DISCNUMBER"), kCFCompareCaseInsensitive)) {
			int num = CFStringGetIntValue(value);
			CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &num);
			CFDictionarySetValue(dictionary, kMetadataDiscNumberKey, number);
			CFRelease(number), number = NULL;
		}
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("DISCTOTAL"), kCFCompareCaseInsensitive)) {
			int num = CFStringGetIntValue(value);
			CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &num);
			CFDictionarySetValue(dictionary, kMetadataDiscTotalKey, number);
			CFRelease(number), number = NULL;
		}
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("LYRICS"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataLyricsKey, value);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("BPM"), kCFCompareCaseInsensitive)) {
			int num = CFStringGetIntValue(value);
			CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &num);
			CFDictionarySetValue(dictionary, kMetadataBPMKey, number);
			CFRelease(number), number = NULL;
		}
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("RATING"), kCFCompareCaseInsensitive)) {
			int num = CFStringGetIntValue(value);
			CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &num);
			CFDictionarySetValue(dictionary, kMetadataRatingKey, number);
			CFRelease(number), number = NULL;
		}
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("ISRC"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataISRCKey, value);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("MCN"), kCFCompareCaseInsensitive))
			CFDictionarySetValue(dictionary, kMetadataMCNKey, value);
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("REPLAYGAIN_REFERENCE_LOUDNESS"), kCFCompareCaseInsensitive)) {
			double num = CFStringGetDoubleValue(value);
			CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &num);
			CFDictionarySetValue(dictionary, kReplayGainReferenceLoudnessKey, number);
			CFRelease(number), number = NULL;
		}
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("REPLAYGAIN_TRACK_GAIN"), kCFCompareCaseInsensitive)) {
			double num = CFStringGetDoubleValue(value);
			CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &num);
			CFDictionarySetValue(dictionary, kReplayGainTrackGainKey, number);
			CFRelease(number), number = NULL;
		}
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("REPLAYGAIN_TRACK_PEAK"), kCFCompareCaseInsensitive)) {
			double num = CFStringGetDoubleValue(value);
			CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &num);
			CFDictionarySetValue(dictionary, kReplayGainTrackPeakKey, number);
			CFRelease(number), number = NULL;
		}
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("REPLAYGAIN_ALBUM_GAIN"), kCFCompareCaseInsensitive)) {
			double num = CFStringGetDoubleValue(value);
			CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &num);
			CFDictionarySetValue(dictionary, kReplayGainAlbumGainKey, number);
			CFRelease(number), number = NULL;
		}
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("REPLAYGAIN_ALBUM_PEAK"), kCFCompareCaseInsensitive)) {
			double num = CFStringGetDoubleValue(value);
			CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &num);
			CFDictionarySetValue(dictionary, kReplayGainAlbumPeakKey, number);
			CFRelease(number), number = NULL;
		}
		else if(kCFCompareEqualTo == CFStringCompare(key, CFSTR("METADATA_BLOCK_PICTURE"), kCFCompareCaseInsensitive)) {
			// Handle embedded pictures
			TagLib::StringList encodedBlocks = it->second;
			for(TagLib::StringList::ConstIterator blockIterator = encodedBlocks.begin(); blockIterator != encodedBlocks.end(); ++blockIterator) {
				const TagLib::ByteVector encodedBlock = blockIterator->data(TagLib::String::UTF8);

				// Decode the Base-64 encoded data
				TagLib::ByteVector decodedBlock = DecodeBase64(encodedBlock);

				// Create the picture
				TagLib::FLAC::Picture picture;
				picture.parse(decodedBlock);

				switch(picture.type()) {
					case TagLib::FLAC::Picture::FrontCover:
					{
						CFDataRef data = CFDataCreate(kCFAllocatorDefault, reinterpret_cast<const UInt8 *>(picture.data().data()), picture.data().size());
						CFDictionarySetValue(dictionary, kAlbumArtFrontCoverKey, data);
						CFRelease(data), data = NULL;
						break;
					}

						// TODO: Other artwork types will be handled in the future
					default:
						break;
				}
			}
		}
		// Put all unknown tags into the additional metadata
		else
			CFDictionarySetValue(additionalMetadata, key, value);

		CFRelease(key), key = NULL;
		CFRelease(value), value = NULL;
	}

	if(CFDictionaryGetCount(additionalMetadata))
		CFDictionarySetValue(dictionary, kMetadataAdditionalMetadataKey, additionalMetadata);

	CFRelease(additionalMetadata), additionalMetadata = NULL;

	return true;
}
<|endoftext|>


<commit_before>#pragma once

#include <random>
#include <functional>

namespace dust
{
    template<class State, class Observation>
    class filter
    {
    public:
        using motion_model = std::function<std::pair<float, State>(const State&,
                                                                   const Observation&)>;
        using uniform_state = std::function<State()>;

        filter(unsigned int num_particles)
            : num_particles(num_particles),
              resample_dist(0, 1.0f / num_particles)
        {
            reset();
            sampled_particles.resize(num_particles);
        }
        filter(unsigned int num_particles, const State& init)
            : num_particles(num_particles),
              resample_dist(0, 1.0f / num_particles),
              particles(num_particles, init)
        {
            sampled_particles.resize(num_particles);
        }

        void reset()
        {
            particles.clear();
            particles.reserve(num_particles);
            std::generate_n(std::back_inserter(particles), num_particles,
                            [&]{ return uniform(); });
        }

        void update(const Observation& z)
        {
            sampled_particles.clear();
            sampled_particles.reserve(num_particles);
            std::transform(particles.begin(), particles.end(),
                           std::back_inserter(sampled_particles),
                           [&](const State& particle) {
                               return motion(particle, z);
                           });

            particles.clear();
            auto r = resample_dist(gen);
            auto c = sampled_particles.front().first;
            unsigned int i = 0;
            for (unsigned int m = 0; m < num_particles; m++)
            {
                auto U = r + (m - 1.0f) / num_particles;
                while (U > c)
                {
                    i++;
                    c += sampled_particles[i].first;
                }
                particles.push_back(sampled_particles[i].second);
            }
        }

        std::pair<float, State> estimate_largest_weight()
        {
            std::pair<float, State> largest = { 0, State() };
            for (auto& p : sampled_particles)
            {
                if (p.first > largest.first)
                {
                    largest = p;
                }
            }

            return largest;
        }

        const std::vector<std::pair<float, State>>& get_sampled_particles() const
        {
            return sampled_particles;
        }

    protected:
        virtual std::pair<float, State> motion(const State& state,
                                               const Observation& obs) const = 0;
        virtual State uniform() const = 0;
        mutable std::mt19937 gen;

    private:
        unsigned int num_particles;
        std::vector<State> particles;
        std::vector<std::pair<float, State>> sampled_particles;
        std::uniform_real_distribution<float> resample_dist;
    };
}
<commit_msg>add missing include<commit_after>#pragma once

#include <random>
#include <functional>
#include <algorithm>

namespace dust
{
    template<class State, class Observation>
    class filter
    {
    public:
        using motion_model = std::function<std::pair<float, State>(const State&,
                                                                   const Observation&)>;
        using uniform_state = std::function<State()>;

        filter(unsigned int num_particles)
            : num_particles(num_particles),
              resample_dist(0, 1.0f / num_particles)
        {
            reset();
            sampled_particles.resize(num_particles);
        }
        filter(unsigned int num_particles, const State& init)
            : num_particles(num_particles),
              resample_dist(0, 1.0f / num_particles),
              particles(num_particles, init)
        {
            sampled_particles.resize(num_particles);
        }

        void reset()
        {
            particles.clear();
            particles.reserve(num_particles);
            std::generate_n(std::back_inserter(particles), num_particles,
                            [&]{ return uniform(); });
        }

        void update(const Observation& z)
        {
            sampled_particles.clear();
            sampled_particles.reserve(num_particles);
            std::transform(particles.begin(), particles.end(),
                           std::back_inserter(sampled_particles),
                           [&](const State& particle) {
                               return motion(particle, z);
                           });

            particles.clear();
            auto r = resample_dist(gen);
            auto c = sampled_particles.front().first;
            unsigned int i = 0;
            for (unsigned int m = 0; m < num_particles; m++)
            {
                auto U = r + (m - 1.0f) / num_particles;
                while (U > c)
                {
                    i++;
                    c += sampled_particles[i].first;
                }
                particles.push_back(sampled_particles[i].second);
            }
        }

        std::pair<float, State> estimate_largest_weight()
        {
            std::pair<float, State> largest = { 0, State() };
            for (auto& p : sampled_particles)
            {
                if (p.first > largest.first)
                {
                    largest = p;
                }
            }

            return largest;
        }

        const std::vector<std::pair<float, State>>& get_sampled_particles() const
        {
            return sampled_particles;
        }

    protected:
        virtual std::pair<float, State> motion(const State& state,
                                               const Observation& obs) const = 0;
        virtual State uniform() const = 0;
        mutable std::mt19937 gen;

    private:
        unsigned int num_particles;
        std::vector<State> particles;
        std::vector<std::pair<float, State>> sampled_particles;
        std::uniform_real_distribution<float> resample_dist;
    };
}
<|endoftext|>