<commit_before>// v8
#include <v8.h>

// node
#include <node.h>
#include <node_version.h>
#include <node_object_wrap.h>

// OSRM
#include <osrm/OSRM.h>
#include <osrm/RouteParameters.h>
#include <osrm/Reply.h>

// STL
#include <memory>

namespace node_osrm {

using namespace v8;

typedef std::shared_ptr<OSRM> osrm_ptr;
typedef std::shared_ptr<ServerPaths> server_paths_ptr;
typedef std::shared_ptr<RouteParameters> route_parameters_ptr;

class Engine: public node::ObjectWrap {
public:
    static Persistent<FunctionTemplate> constructor;
    static void Initialize(Handle<Object>);
    static Handle<Value> New(const Arguments&);

    static Handle<Value> route(const Arguments&);
    static Handle<Value> locate(const Arguments&);
    static Handle<Value> nearest(const Arguments&);

    static Handle<Value> Run(const Arguments&, route_parameters_ptr);
    static void AsyncRun(uv_work_t*);
    static void AfterRun(uv_work_t*);

    Engine(server_paths_ptr paths, bool use_shared_memory)
        : ObjectWrap(),
          paths_(paths),
          this_(std::make_shared<OSRM>(*paths, use_shared_memory))
    {}

    ~Engine() {}

    server_paths_ptr paths_;
    osrm_ptr this_;
};

Persistent<FunctionTemplate> Engine::constructor;

void Engine::Initialize(Handle<Object> target) {
    HandleScope scope;

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

    NODE_SET_PROTOTYPE_METHOD(constructor, "route", route);
    NODE_SET_PROTOTYPE_METHOD(constructor, "locate", locate);
    NODE_SET_PROTOTYPE_METHOD(constructor, "nearest", nearest);

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

Handle<Value> Engine::New(const Arguments& args)
{
    HandleScope scope;

    if (!args.IsConstructCall()) {
        return ThrowException(Exception::Error(String::New(
            "Cannot call constructor as function, you need to use 'new' keyword")));
    }

    try {
        server_paths_ptr paths = std::make_shared<ServerPaths>();

        if (args.Length() == 1) {
            if (!args[0]->IsString()) {
                return ThrowException(Exception::TypeError(String::New("OSRM base path must be a string")));
            }
            std::string base = *String::Utf8Value(args[0]->ToString());
            (*paths)["hsgrdata"] = base + ".hsgr";
            (*paths)["nodesdata"] = base + ".nodes";
            (*paths)["edgesdata"] = base + ".edges";
            (*paths)["geometries"] = base + ".geometry";
            (*paths)["ramindex"] = base + ".ramIndex";
            (*paths)["fileindex"] = base + ".fileIndex";
            (*paths)["namesdata"] = base + ".names";
            (*paths)["timestamp"] = base + ".timestamp";
        }

        Engine* im = new Engine(paths, args.Length() == 0);
        im->Wrap(args.This());
        return args.This();
    } catch (std::exception const& ex) {
        return ThrowException(Exception::Error(String::New(ex.what())));
    }

    return Undefined();
}

typedef struct {
    uv_work_t request;
    Engine * machine;
    route_parameters_ptr params;
    bool error;
    std::string result;
    Persistent<Function> cb;
} run_query_baton_t;

Handle<Value> Engine::route(const Arguments& args)
{
    HandleScope scope;

    if (args.Length() < 2) {
        return ThrowException(Exception::TypeError(
            String::New("two arguments required")));
    }

    if (!args[0]->IsObject()) {
        return ThrowException(Exception::TypeError(
            String::New("first argument must be an object")));
    }

    Local<Object> obj = args[0]->ToObject();
    if (obj->IsNull() || obj->IsUndefined()) {
        return ThrowException(Exception::TypeError(String::New(
            "first arg must be an object")));
    }

    route_parameters_ptr params = std::make_shared<RouteParameters>();

    params->zoom_level = 18; //no generalization
    params->print_instructions = false; //turn by turn instructions
    params->alternate_route = true; //get an alternate route, too
    params->geometry = true; //retrieve geometry of route
    params->compression = true; //polyline encoding
    params->check_sum = UINT_MAX; //see wiki
    params->service = "viaroute"; //that's routing
    params->output_format = "json";
    params->jsonp_parameter = ""; //set for jsonp wrapping
    params->language = ""; //unused atm

    if (!obj->Has(String::New("coordinates"))) {
        return ThrowException(Exception::TypeError(String::New(
            "must provide a coordinates property")));
    }

    Local<Value> coordinates = obj->Get(String::New("coordinates"));
    if (!coordinates->IsArray()) {
        return ThrowException(Exception::TypeError(String::New(
            "coordinates must be an array of (lat/long) pairs")));
    }

    Local<Array> coordinates_array = Local<Array>::Cast(coordinates);
    if (coordinates_array->Length() < 2) {
        return ThrowException(Exception::TypeError(String::New(
            "at least two coordinates must be provided")));
    }

    for (uint32_t i = 0; i < coordinates_array->Length(); ++i) {
        Local<Value> coordinate = coordinates_array->Get(i);

        if (!coordinate->IsArray()) {
            return ThrowException(Exception::TypeError(String::New("coordinates must be an array of (lat/long) pairs")));
        }

        Local<Array> coordinate_array = Local<Array>::Cast(coordinate);
        if (coordinate_array->Length() != 2) {
            return ThrowException(Exception::TypeError(String::New("coordinates must be an array of (lat/long) pairs")));
        }

        params->coordinates.push_back(
            FixedPointCoordinate(coordinate_array->Get(0)->NumberValue()*COORDINATE_PRECISION,
                                 coordinate_array->Get(1)->NumberValue()*COORDINATE_PRECISION));
    }

    if (obj->Has(String::New("alternateRoute"))) {
        params->alternate_route = obj->Get(String::New("alternateRoute"))->BooleanValue();
    }

    if (obj->Has(String::New("checksum"))) {
        params->check_sum = static_cast<unsigned>(obj->Get(String::New("checksum"))->Uint32Value());
    }

    if (obj->Has(String::New("zoomLevel"))) {
        params->zoom_level = static_cast<short>(obj->Get(String::New("zoomLevel"))->Int32Value());
    }

    if (obj->Has(String::New("printInstructions"))) {
        params->print_instructions = obj->Get(String::New("printInstructions"))->BooleanValue();
    }

    if (obj->Has(String::New("jsonpParameter"))) {
        params->jsonp_parameter = *v8::String::Utf8Value(obj->Get(String::New("jsonpParameter")));
    }

    if (obj->Has(String::New("hints"))) {
        Local<Value> hints = obj->Get(String::New("hints"));

        if (!hints->IsArray()) {
            return ThrowException(Exception::TypeError(String::New("hints must be an array of strings/null")));
        }

        Local<Array> hints_array = Local<Array>::Cast(hints);
        for (uint32_t i = 0; i < hints_array->Length(); ++i) {
            Local<Value> hint = hints_array->Get(i);
            if (hint->IsString()) {
                params->hints.push_back(*v8::String::Utf8Value(hint));
            } else if(hint->IsNull()){
                params->hints.push_back("");
            }else{
                return ThrowException(Exception::TypeError(String::New("hint must be null or string")));
            }
        }
    }

    return Run(args, params);
}

Handle<Value> Engine::locate(const Arguments& args)
{
    if (args.Length() < 2) {
        return ThrowException(Exception::TypeError(
            String::New("two arguments required")));
    }

    Local<Value> coordinate = args[0];
    if (!coordinate->IsArray()) {
        return ThrowException(Exception::TypeError(String::New(
            "first argument must be an array of lat, long")));
    }

    Local<Array> coordinate_array = Local<Array>::Cast(coordinate);
    if (coordinate_array->Length() != 2) {
        return ThrowException(Exception::TypeError(String::New(
            "first argument must be an array of lat, long")));
    }

    route_parameters_ptr params = std::make_shared<RouteParameters>();

    params->service = "locate";
    params->coordinates.push_back(
        FixedPointCoordinate(coordinate_array->Get(0)->NumberValue()*COORDINATE_PRECISION,
                             coordinate_array->Get(1)->NumberValue()*COORDINATE_PRECISION));

    return Run(args, params);
}

Handle<Value> Engine::nearest(const Arguments& args)
{
    if (args.Length() < 2) {
        return ThrowException(Exception::TypeError(
            String::New("two arguments required")));
    }

    Local<Value> coordinate = args[0];
    if (!coordinate->IsArray()) {
        return ThrowException(Exception::TypeError(String::New(
            "first argument must be an array of lat, long")));
    }

    Local<Array> coordinate_array = Local<Array>::Cast(coordinate);
    if (coordinate_array->Length() != 2) {
        return ThrowException(Exception::TypeError(String::New(
            "first argument must be an array of lat, long")));
    }

    route_parameters_ptr params = std::make_shared<RouteParameters>();

    params->service = "nearest";
    params->coordinates.push_back(
        FixedPointCoordinate(coordinate_array->Get(0)->NumberValue()*COORDINATE_PRECISION,
                             coordinate_array->Get(1)->NumberValue()*COORDINATE_PRECISION));

    return Run(args, params);
}

Handle<Value> Engine::Run(const Arguments& args, route_parameters_ptr params)
{
    if (!args[1]->IsFunction()) {
        return ThrowException(Exception::TypeError(String::New(
            "second argument must be a callback function")));
    }

    run_query_baton_t *closure = new run_query_baton_t();
    closure->request.data = closure;
    closure->machine = ObjectWrap::Unwrap<Engine>(args.This());
    closure->params = params;
    closure->error = false;
    closure->cb = Persistent<Function>::New(Handle<Function>::Cast(args[1]));

    uv_queue_work(uv_default_loop(), &closure->request, AsyncRun, (uv_after_work_cb)AfterRun);
    closure->machine->Ref();

    return Undefined();
}

void Engine::AsyncRun(uv_work_t* req) {
    run_query_baton_t *closure = static_cast<run_query_baton_t *>(req->data);
    try {
        http::Reply osrm_reply;
        closure->machine->this_->RunQuery(*closure->params, osrm_reply);
        closure->result = std::string(osrm_reply.content.begin(), osrm_reply.content.end());
    } catch(std::exception const& ex) {
        closure->error = true;
        closure->result = ex.what();
    }
}

void Engine::AfterRun(uv_work_t* req) {
    HandleScope scope;
    run_query_baton_t *closure = static_cast<run_query_baton_t *>(req->data);
    TryCatch try_catch;
    if (closure->error) {
        Local<Value> argv[1] = { Exception::Error(String::New(closure->result.c_str())) };
        closure->cb->Call(Context::GetCurrent()->Global(), 1, argv);
    } else {
        Local<Value> argv[2] = { Local<Value>::New(Null()),
                                 String::New(closure->result.c_str()) };
        closure->cb->Call(Context::GetCurrent()->Global(), 2, argv);
    }
    if (try_catch.HasCaught()) {
        node::FatalException(try_catch);
    }
    closure->machine->Unref();
    closure->cb.Dispose();
    delete closure;
}

extern "C" {
    static void start(Handle<Object> target) {
        Engine::Initialize(target);
    }
}

} // namespace node_osrm

NODE_MODULE(osrm, node_osrm::start)
<commit_msg>add missing include<commit_after>// v8
#include <v8.h>

// node
#include <node.h>
#include <node_version.h>
#include <node_object_wrap.h>

// OSRM
#include <osrm/OSRM.h>
#include <osrm/RouteParameters.h>
#include <osrm/Reply.h>
#include <osrm/ServerPaths.h>

// STL
#include <memory>

namespace node_osrm {

using namespace v8;

typedef std::shared_ptr<OSRM> osrm_ptr;
typedef std::shared_ptr<ServerPaths> server_paths_ptr;
typedef std::shared_ptr<RouteParameters> route_parameters_ptr;

class Engine: public node::ObjectWrap {
public:
    static Persistent<FunctionTemplate> constructor;
    static void Initialize(Handle<Object>);
    static Handle<Value> New(const Arguments&);

    static Handle<Value> route(const Arguments&);
    static Handle<Value> locate(const Arguments&);
    static Handle<Value> nearest(const Arguments&);

    static Handle<Value> Run(const Arguments&, route_parameters_ptr);
    static void AsyncRun(uv_work_t*);
    static void AfterRun(uv_work_t*);

    Engine(server_paths_ptr paths, bool use_shared_memory)
        : ObjectWrap(),
          paths_(paths),
          this_(std::make_shared<OSRM>(*paths, use_shared_memory))
    {}

    ~Engine() {}

    server_paths_ptr paths_;
    osrm_ptr this_;
};

Persistent<FunctionTemplate> Engine::constructor;

void Engine::Initialize(Handle<Object> target) {
    HandleScope scope;

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

    NODE_SET_PROTOTYPE_METHOD(constructor, "route", route);
    NODE_SET_PROTOTYPE_METHOD(constructor, "locate", locate);
    NODE_SET_PROTOTYPE_METHOD(constructor, "nearest", nearest);

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

Handle<Value> Engine::New(const Arguments& args)
{
    HandleScope scope;

    if (!args.IsConstructCall()) {
        return ThrowException(Exception::Error(String::New(
            "Cannot call constructor as function, you need to use 'new' keyword")));
    }

    try {
        server_paths_ptr paths = std::make_shared<ServerPaths>();

        if (args.Length() == 1) {
            if (!args[0]->IsString()) {
                return ThrowException(Exception::TypeError(String::New("OSRM base path must be a string")));
            }
            std::string base = *String::Utf8Value(args[0]->ToString());
            (*paths)["hsgrdata"] = base + ".hsgr";
            (*paths)["nodesdata"] = base + ".nodes";
            (*paths)["edgesdata"] = base + ".edges";
            (*paths)["geometries"] = base + ".geometry";
            (*paths)["ramindex"] = base + ".ramIndex";
            (*paths)["fileindex"] = base + ".fileIndex";
            (*paths)["namesdata"] = base + ".names";
            (*paths)["timestamp"] = base + ".timestamp";
        }

        Engine* im = new Engine(paths, args.Length() == 0);
        im->Wrap(args.This());
        return args.This();
    } catch (std::exception const& ex) {
        return ThrowException(Exception::Error(String::New(ex.what())));
    }

    return Undefined();
}

typedef struct {
    uv_work_t request;
    Engine * machine;
    route_parameters_ptr params;
    bool error;
    std::string result;
    Persistent<Function> cb;
} run_query_baton_t;

Handle<Value> Engine::route(const Arguments& args)
{
    HandleScope scope;

    if (args.Length() < 2) {
        return ThrowException(Exception::TypeError(
            String::New("two arguments required")));
    }

    if (!args[0]->IsObject()) {
        return ThrowException(Exception::TypeError(
            String::New("first argument must be an object")));
    }

    Local<Object> obj = args[0]->ToObject();
    if (obj->IsNull() || obj->IsUndefined()) {
        return ThrowException(Exception::TypeError(String::New(
            "first arg must be an object")));
    }

    route_parameters_ptr params = std::make_shared<RouteParameters>();

    params->zoom_level = 18; //no generalization
    params->print_instructions = false; //turn by turn instructions
    params->alternate_route = true; //get an alternate route, too
    params->geometry = true; //retrieve geometry of route
    params->compression = true; //polyline encoding
    params->check_sum = UINT_MAX; //see wiki
    params->service = "viaroute"; //that's routing
    params->output_format = "json";
    params->jsonp_parameter = ""; //set for jsonp wrapping
    params->language = ""; //unused atm

    if (!obj->Has(String::New("coordinates"))) {
        return ThrowException(Exception::TypeError(String::New(
            "must provide a coordinates property")));
    }

    Local<Value> coordinates = obj->Get(String::New("coordinates"));
    if (!coordinates->IsArray()) {
        return ThrowException(Exception::TypeError(String::New(
            "coordinates must be an array of (lat/long) pairs")));
    }

    Local<Array> coordinates_array = Local<Array>::Cast(coordinates);
    if (coordinates_array->Length() < 2) {
        return ThrowException(Exception::TypeError(String::New(
            "at least two coordinates must be provided")));
    }

    for (uint32_t i = 0; i < coordinates_array->Length(); ++i) {
        Local<Value> coordinate = coordinates_array->Get(i);

        if (!coordinate->IsArray()) {
            return ThrowException(Exception::TypeError(String::New("coordinates must be an array of (lat/long) pairs")));
        }

        Local<Array> coordinate_array = Local<Array>::Cast(coordinate);
        if (coordinate_array->Length() != 2) {
            return ThrowException(Exception::TypeError(String::New("coordinates must be an array of (lat/long) pairs")));
        }

        params->coordinates.push_back(
            FixedPointCoordinate(coordinate_array->Get(0)->NumberValue()*COORDINATE_PRECISION,
                                 coordinate_array->Get(1)->NumberValue()*COORDINATE_PRECISION));
    }

    if (obj->Has(String::New("alternateRoute"))) {
        params->alternate_route = obj->Get(String::New("alternateRoute"))->BooleanValue();
    }

    if (obj->Has(String::New("checksum"))) {
        params->check_sum = static_cast<unsigned>(obj->Get(String::New("checksum"))->Uint32Value());
    }

    if (obj->Has(String::New("zoomLevel"))) {
        params->zoom_level = static_cast<short>(obj->Get(String::New("zoomLevel"))->Int32Value());
    }

    if (obj->Has(String::New("printInstructions"))) {
        params->print_instructions = obj->Get(String::New("printInstructions"))->BooleanValue();
    }

    if (obj->Has(String::New("jsonpParameter"))) {
        params->jsonp_parameter = *v8::String::Utf8Value(obj->Get(String::New("jsonpParameter")));
    }

    if (obj->Has(String::New("hints"))) {
        Local<Value> hints = obj->Get(String::New("hints"));

        if (!hints->IsArray()) {
            return ThrowException(Exception::TypeError(String::New("hints must be an array of strings/null")));
        }

        Local<Array> hints_array = Local<Array>::Cast(hints);
        for (uint32_t i = 0; i < hints_array->Length(); ++i) {
            Local<Value> hint = hints_array->Get(i);
            if (hint->IsString()) {
                params->hints.push_back(*v8::String::Utf8Value(hint));
            } else if(hint->IsNull()){
                params->hints.push_back("");
            }else{
                return ThrowException(Exception::TypeError(String::New("hint must be null or string")));
            }
        }
    }

    return Run(args, params);
}

Handle<Value> Engine::locate(const Arguments& args)
{
    if (args.Length() < 2) {
        return ThrowException(Exception::TypeError(
            String::New("two arguments required")));
    }

    Local<Value> coordinate = args[0];
    if (!coordinate->IsArray()) {
        return ThrowException(Exception::TypeError(String::New(
            "first argument must be an array of lat, long")));
    }

    Local<Array> coordinate_array = Local<Array>::Cast(coordinate);
    if (coordinate_array->Length() != 2) {
        return ThrowException(Exception::TypeError(String::New(
            "first argument must be an array of lat, long")));
    }

    route_parameters_ptr params = std::make_shared<RouteParameters>();

    params->service = "locate";
    params->coordinates.push_back(
        FixedPointCoordinate(coordinate_array->Get(0)->NumberValue()*COORDINATE_PRECISION,
                             coordinate_array->Get(1)->NumberValue()*COORDINATE_PRECISION));

    return Run(args, params);
}

Handle<Value> Engine::nearest(const Arguments& args)
{
    if (args.Length() < 2) {
        return ThrowException(Exception::TypeError(
            String::New("two arguments required")));
    }

    Local<Value> coordinate = args[0];
    if (!coordinate->IsArray()) {
        return ThrowException(Exception::TypeError(String::New(
            "first argument must be an array of lat, long")));
    }

    Local<Array> coordinate_array = Local<Array>::Cast(coordinate);
    if (coordinate_array->Length() != 2) {
        return ThrowException(Exception::TypeError(String::New(
            "first argument must be an array of lat, long")));
    }

    route_parameters_ptr params = std::make_shared<RouteParameters>();

    params->service = "nearest";
    params->coordinates.push_back(
        FixedPointCoordinate(coordinate_array->Get(0)->NumberValue()*COORDINATE_PRECISION,
                             coordinate_array->Get(1)->NumberValue()*COORDINATE_PRECISION));

    return Run(args, params);
}

Handle<Value> Engine::Run(const Arguments& args, route_parameters_ptr params)
{
    if (!args[1]->IsFunction()) {
        return ThrowException(Exception::TypeError(String::New(
            "second argument must be a callback function")));
    }

    run_query_baton_t *closure = new run_query_baton_t();
    closure->request.data = closure;
    closure->machine = ObjectWrap::Unwrap<Engine>(args.This());
    closure->params = params;
    closure->error = false;
    closure->cb = Persistent<Function>::New(Handle<Function>::Cast(args[1]));

    uv_queue_work(uv_default_loop(), &closure->request, AsyncRun, (uv_after_work_cb)AfterRun);
    closure->machine->Ref();

    return Undefined();
}

void Engine::AsyncRun(uv_work_t* req) {
    run_query_baton_t *closure = static_cast<run_query_baton_t *>(req->data);
    try {
        http::Reply osrm_reply;
        closure->machine->this_->RunQuery(*closure->params, osrm_reply);
        closure->result = std::string(osrm_reply.content.begin(), osrm_reply.content.end());
    } catch(std::exception const& ex) {
        closure->error = true;
        closure->result = ex.what();
    }
}

void Engine::AfterRun(uv_work_t* req) {
    HandleScope scope;
    run_query_baton_t *closure = static_cast<run_query_baton_t *>(req->data);
    TryCatch try_catch;
    if (closure->error) {
        Local<Value> argv[1] = { Exception::Error(String::New(closure->result.c_str())) };
        closure->cb->Call(Context::GetCurrent()->Global(), 1, argv);
    } else {
        Local<Value> argv[2] = { Local<Value>::New(Null()),
                                 String::New(closure->result.c_str()) };
        closure->cb->Call(Context::GetCurrent()->Global(), 2, argv);
    }
    if (try_catch.HasCaught()) {
        node::FatalException(try_catch);
    }
    closure->machine->Unref();
    closure->cb.Dispose();
    delete closure;
}

extern "C" {
    static void start(Handle<Object> target) {
        Engine::Initialize(target);
    }
}

} // namespace node_osrm

NODE_MODULE(osrm, node_osrm::start)
<|endoftext|>


<commit_before>#include "occaTools.hpp"
#include "occa.hpp"      // For kernelInfo

namespace occa {
  mutex_t::mutex_t(){
#if (OCL_OS == OCL_LINUX_OS) || (OCL_OS == OCL_OSX_OS)
    int error = pthread_mutex_init(&mutexHandle, NULL);

    if(error){
      std::cout << "Error initializing mutex\n";
      throw 1;
    }
#else
    mutexHandle = CreateMutex(NULL, FALSE, NULL);
#endif
  }

  void mutex_t::free(){
#if (OCL_OS == OCL_LINUX_OS) || (OCL_OS == OCL_OSX_OS)
    int error = pthread_mutex_destroy(&mutexHandle);

    if(error){
      std::cout << "Error freeing mutex\n";
      throw 1;
    }
#else
    CloseHandle(mutexHandle);
#endif
  }

  void mutex_t::lock(){
#if (OCL_OS == OCL_LINUX_OS) || (OCL_OS == OCL_OSX_OS)
    pthread_mutex_lock(&mutexHandle);
#else
    WaitForSingleObject(mutexHandle, INFINITE);
#endif
  }

  void mutex_t::unlock(){
#if (OCL_OS == OCL_LINUX_OS) || (OCL_OS == OCL_OSX_OS)
    pthread_mutex_unlock(&mutexHandle);
#else
    ReleaseMutex(mutexHandle);
#endif
  }

  double currentTime(){
#if OCCA_OS == LINUX_OS

    timespec ct;
    clock_gettime(CLOCK_MONOTONIC, &ct);

    return (double) (ct.tv_sec + (1.0e-9 * ct.tv_nsec));

#elif OCCA_OS == OSX_OS

    uint64_t ct;
    ct = mach_absolute_time();

    const Nanoseconds ct2 = AbsoluteToNanoseconds(*(AbsoluteTime *) &ct);

    return ((double) 1.0e-9) * ((double) ( *((uint64_t*) &ct2) ));

#elif OCCA_OS == WINDOWS_OS
    LARGE_INTEGER timestamp, timerfreq;

    QueryPerformanceFrequency(&timerfreq);
    QueryPerformanceCounter(&timestamp);

    return ((double) timestamp.QuadPart) / ((double) timerfreq.QuadPart);
#endif
  }

  std::string getFileExtension(const std::string &filename){
    const char *c = filename.c_str();
    const char *i = NULL;

    while(*c != '\0'){
      if(*c == '.')
        i = c;

      ++c;
    }

    if(i != NULL)
      return filename.substr(i - filename.c_str() + 1);

    return "";
  }

  void getFilePrefixAndName(const std::string &fullFilename,
                            std::string &prefix,
                            std::string &filename){
    int lastSlash = 0;
    const int chars = fullFilename.size();

#if (OCCA_OS == LINUX_OS) || (OCCA_OS == OSX_OS)
    for(int i = 0; i < chars; ++i)
      if(fullFilename[i] == '/')
        lastSlash = i;
#else
    for(int i = 0; i < chars; ++i)
      if((fullFilename[i] == '/') ||
         (fullFilename[i] == '\\'))
        lastSlash = i;
#endif

    ++lastSlash;

    prefix   = fullFilename.substr(0, lastSlash);
    filename = fullFilename.substr(lastSlash, chars - lastSlash);
  }

  std::string getMidCachedBinaryName(const std::string &cachedBinary,
                                     const std::string &namePrefix){
    std::string prefix, name;
    getFilePrefixAndName(cachedBinary, prefix, name);

    return (prefix + namePrefix + "_" + name);
  }

  std::string getFileLock(const std::string &filename){
    std::string prefix, name;
    getFilePrefixAndName(filename, prefix, name);

    return (prefix + "._occa_dir_" + name);
  }

  bool haveFile(const std::string &filename){
    std::string lockDir = getFileLock(filename);
#if (OCCA_OS == LINUX_OS) || (OCCA_OS == OSX_OS)
    int mkdirStatus = mkdir(lockDir.c_str(), 0755);

    // Someone else is making it
    if(mkdirStatus && (errno == EEXIST))
      return false;

    return true;
#else
    LPCSTR lockDirStr = lockDir.c_str();
    BOOL mkdirStatus = CreateDirectoryA(lockDirStr, NULL);

    if( mkdirStatus == FALSE) {
      assert(GetLastError() == ERROR_ALREADY_EXISTS);
      return false;
    }
    return true;
#endif
  }

  void waitForFile(const std::string &filename){
    struct stat buffer;

    std::string lockDir   = getFileLock(filename);
    const char *c_lockDir = lockDir.c_str();

    while(stat(c_lockDir, &buffer) == 0)
      /* Do Nothing */;
  }

  void releaseFile(const std::string &filename){
    std::string lockDir = getFileLock(filename);
#if (OCCA_OS == LINUX_OS) || (OCCA_OS == OSX_OS)
    rmdir(lockDir.c_str());
#else
    BOOL retStatus = RemoveDirectoryA(lockDir.c_str());
    assert(retStatus == TRUE);
#endif
  }

  parsedKernelInfo parseFileForFunction(const std::string &filename,
                                        const std::string &cachedBinary,
                                        const std::string &functionName,
                                        const kernelInfo &info){
    const std::string iCachedBinary = getMidCachedBinaryName(cachedBinary, "i");
    const std::string pCachedBinary = getMidCachedBinaryName(cachedBinary, "p");

    parser fileParser;

    std::ofstream fs;
    fs.open(pCachedBinary.c_str());

    fs << info.header << readFile(filename);

    fs.close();
    fs.clear();

    fs.open(iCachedBinary.c_str());
    fs << info.occaKeywords << fileParser.parseFile(pCachedBinary);

    fs.close();

    kernelInfoIterator kIt = fileParser.kernelInfoMap.find(functionName);

    if(kIt != fileParser.kernelInfoMap.end()){
      return parsedKernelInfo( *((kIt++)->second) );
    }

    std::cout << "Could not find function ["
              << functionName << "] in file ["
              << filename     << "].\n";
    throw 1;

    return parsedKernelInfo();
  }

  std::string fnv(const std::string &saltedString){
    const int len = saltedString.size();
    std::stringstream ss;

    int h[8] = {101527, 101531,
                101533, 101537,
                101561, 101573,
                101581, 101599};

    const int p[8] = {102679, 102701,
                      102761, 102763,
                      102769, 102793,
                      102797, 102811};

    for(int c = 0; c < len; ++c)
      for(int i = 0; i < 8; ++i)
        h[i] = (h[i] * p[i]) ^ saltedString[c];

    // int h2[8];

    // for(int i = 0; i < 8; ++i)
    //   h2[i] = ((h[0] & (0xFF << (8*i))) << (8*i + 0))
    //     |     ((h[1] & (0xFF << (8*i))) << (8*i + 1))
    //     |     ((h[2] & (0xFF << (8*i))) << (8*i + 2))
    //     |     ((h[3] & (0xFF << (8*i))) << (8*i + 3))
    //     |     ((h[4] & (0xFF << (8*i))) << (8*i + 4))
    //     |     ((h[5] & (0xFF << (8*i))) << (8*i + 5))
    //     |     ((h[6] & (0xFF << (8*i))) << (8*i + 6))
    //     |     ((h[7] & (0xFF << (8*i))) << (8*i + 7));

    for(int i = 0; i < 8; ++i)
      ss <<  std::hex << h[i];

    return ss.str();
  }

  bool fileExists(const std::string &filename){
    struct stat buffer;
    return (stat(filename.c_str(), &buffer) == 0);
  }

  std::string readFile(const std::string &filename){
    // NBN: handle EOL chars on Windows
    FILE *fp = fopen(filename.c_str(), "r");

    if(!fp){
      printf("Failed to open: %s\n", filename.c_str());
      throw 1;
    }

    struct stat statbuf;
    stat(filename.c_str(), &statbuf);

    const size_t nchars = statbuf.st_size;

    char *buffer = (char*) calloc(nchars + 1, sizeof(char));
    size_t nread = fread(buffer, sizeof(char), nchars, fp);

    buffer[nread] = '\0';

    fclose(fp);

    std::string contents(buffer, nread + 1);

    free(buffer);

    return contents;
  }

  std::string getOCCADir(){
    char *c_occaPath = getenv("OCCA_DIR");

    if(c_occaPath != NULL)
      return c_occaPath;

    std::cout << "Environment variable [OCCA_DIR] is not set.\n";
    throw 1;

    return "";
  }

  std::string getCachePath(){
    char *c_cachePath = getenv("OCCA_CACHE_DIR");

    bool hasDir = false;

    std::string occaCachePath;

    if(c_cachePath != NULL)
      occaCachePath = c_cachePath;
    else{
      std::stringstream ss;
#if (OCCA_OS == LINUX_OS) || (OCCA_OS == OSX_OS)
      char *c_home = getenv("HOME");
      ss << c_home << "/._occa";

      occaCachePath = ss.str();
#else
      char *c_home = getenv("USERPROFILE");

      ss << c_home << "\\AppData\\Local\\OCCA";

#  if OCCA_64_BIT
      ss << "_amd64";  // use different dir's fro 32 and 64 bit
#  else
      ss << "_x86";    // use different dir's fro 32 and 64 bit
#  endif

      occaCachePath = ss.str();
#endif
    }

    const int chars = occaCachePath.size();

    OCCA_CHECK(0 < chars);

#if (OCCA_OS == LINUX_OS) || (OCCA_OS == OSX_OS)
    const char slashChar = '/';
#else
    const char slashChar = '\\';
#endif

    // Take out the pesky //'s
    int pos = 0;

    for(int i = 0; i < chars; ++i){
      if(occaCachePath[i] == slashChar)
        while(i < (chars - 1) && occaCachePath[i + 1] == slashChar)
          ++i;

      occaCachePath[pos++] = occaCachePath[i];
    }

    if(occaCachePath[pos - 1] != slashChar){
      if(pos != chars)
        occaCachePath[pos] = slashChar;
      else
        occaCachePath += slashChar;
    }

    if(!fileExists(occaCachePath)){
#if (OCCA_OS == LINUX_OS) || (OCCA_OS == OSX_OS)
      mkdir(occaCachePath.c_str(), 0755);
#else
      LPCSTR w_occaCachePath = occaCachePath.c_str();
      BOOL mkdirStatus = CreateDirectoryA(w_occaCachePath, NULL);

      if(mkdirStatus == FALSE)
        assert(GetLastError() == ERROR_ALREADY_EXISTS);
#endif
    }

    return occaCachePath;
  }

  bool fileNeedsParser(const std::string &filename){
    std::string ext = getFileExtension(filename);

    return ((ext == "okl") ||
            (ext == "cl") ||
            (ext == "cu"));
  }

  std::string getCachedName(const std::string &filename,
                            const std::string &salt){

    std::string occaCachePath = getCachePath();
    //================================

    const std::string fileContents = readFile(filename);
    const std::string contentsSHA  = fnv(fileContents + salt);

    // Only taking the first 16 characters
    return occaCachePath + contentsSHA.substr(0, 16);
  }

  std::string createIntermediateSource(const std::string &filename,
                                       const std::string &cachedBinary,
                                       const kernelInfo &info){
    std::string prefix, name;
    getFilePrefixAndName(cachedBinary, prefix, name);

    const std::string iCachedBinary = prefix + "i_" + name;

    if(fileNeedsParser(filename)){
      const std::string pCachedBinary = prefix + "p_" + name;
      parser fileParser;

      std::ofstream fs;
      fs.open(pCachedBinary.c_str());

      fs << info.header << readFile(filename);

      fs.close();

      fs.open(iCachedBinary.c_str());
      fs << info.occaKeywords << fileParser.parseFile(pCachedBinary);

      fs.close();
    }
    else{
      std::ofstream fs;
      fs.open(iCachedBinary.c_str());

      fs << info.occaKeywords << info.header << readFile(filename);

      fs.close();
    }

    return iCachedBinary;
  }
};
<commit_msg>[Core] Another fix on loading binaries<commit_after>#include "occaTools.hpp"
#include "occa.hpp"      // For kernelInfo

namespace occa {
  mutex_t::mutex_t(){
#if (OCL_OS == OCL_LINUX_OS) || (OCL_OS == OCL_OSX_OS)
    int error = pthread_mutex_init(&mutexHandle, NULL);

    if(error){
      std::cout << "Error initializing mutex\n";
      throw 1;
    }
#else
    mutexHandle = CreateMutex(NULL, FALSE, NULL);
#endif
  }

  void mutex_t::free(){
#if (OCL_OS == OCL_LINUX_OS) || (OCL_OS == OCL_OSX_OS)
    int error = pthread_mutex_destroy(&mutexHandle);

    if(error){
      std::cout << "Error freeing mutex\n";
      throw 1;
    }
#else
    CloseHandle(mutexHandle);
#endif
  }

  void mutex_t::lock(){
#if (OCL_OS == OCL_LINUX_OS) || (OCL_OS == OCL_OSX_OS)
    pthread_mutex_lock(&mutexHandle);
#else
    WaitForSingleObject(mutexHandle, INFINITE);
#endif
  }

  void mutex_t::unlock(){
#if (OCL_OS == OCL_LINUX_OS) || (OCL_OS == OCL_OSX_OS)
    pthread_mutex_unlock(&mutexHandle);
#else
    ReleaseMutex(mutexHandle);
#endif
  }

  double currentTime(){
#if OCCA_OS == LINUX_OS

    timespec ct;
    clock_gettime(CLOCK_MONOTONIC, &ct);

    return (double) (ct.tv_sec + (1.0e-9 * ct.tv_nsec));

#elif OCCA_OS == OSX_OS

    uint64_t ct;
    ct = mach_absolute_time();

    const Nanoseconds ct2 = AbsoluteToNanoseconds(*(AbsoluteTime *) &ct);

    return ((double) 1.0e-9) * ((double) ( *((uint64_t*) &ct2) ));

#elif OCCA_OS == WINDOWS_OS
    LARGE_INTEGER timestamp, timerfreq;

    QueryPerformanceFrequency(&timerfreq);
    QueryPerformanceCounter(&timestamp);

    return ((double) timestamp.QuadPart) / ((double) timerfreq.QuadPart);
#endif
  }

  std::string getFileExtension(const std::string &filename){
    const char *c = filename.c_str();
    const char *i = NULL;

    while(*c != '\0'){
      if(*c == '.')
        i = c;

      ++c;
    }

    if(i != NULL)
      return filename.substr(i - filename.c_str() + 1);

    return "";
  }

  void getFilePrefixAndName(const std::string &fullFilename,
                            std::string &prefix,
                            std::string &filename){
    int lastSlash = 0;
    const int chars = fullFilename.size();

#if (OCCA_OS == LINUX_OS) || (OCCA_OS == OSX_OS)
    for(int i = 0; i < chars; ++i)
      if(fullFilename[i] == '/')
        lastSlash = i;
#else
    for(int i = 0; i < chars; ++i)
      if((fullFilename[i] == '/') ||
         (fullFilename[i] == '\\'))
        lastSlash = i;
#endif

    ++lastSlash;

    prefix   = fullFilename.substr(0, lastSlash);
    filename = fullFilename.substr(lastSlash, chars - lastSlash);
  }

  std::string getMidCachedBinaryName(const std::string &cachedBinary,
                                     const std::string &namePrefix){
    std::string prefix, name;
    getFilePrefixAndName(cachedBinary, prefix, name);

    return (prefix + namePrefix + "_" + name);
  }

  std::string getFileLock(const std::string &filename){
    std::string prefix, name;
    getFilePrefixAndName(filename, prefix, name);

    return (prefix + "._occa_dir_" + name);
  }

  bool haveFile(const std::string &filename){
    std::string lockDir = getFileLock(filename);
#if (OCCA_OS == LINUX_OS) || (OCCA_OS == OSX_OS)
    int mkdirStatus = mkdir(lockDir.c_str(), 0755);

    // Someone else is making it
    if(mkdirStatus && (errno == EEXIST))
      return false;

    return true;
#else
    LPCSTR lockDirStr = lockDir.c_str();
    BOOL mkdirStatus = CreateDirectoryA(lockDirStr, NULL);

    if( mkdirStatus == FALSE) {
      assert(GetLastError() == ERROR_ALREADY_EXISTS);
      return false;
    }
    return true;
#endif
  }

  void waitForFile(const std::string &filename){
    struct stat buffer;

    std::string lockDir   = getFileLock(filename);
    const char *c_lockDir = lockDir.c_str();

    while(stat(c_lockDir, &buffer) == 0)
      /* Do Nothing */;
  }

  void releaseFile(const std::string &filename){
    std::string lockDir = getFileLock(filename);
#if (OCCA_OS == LINUX_OS) || (OCCA_OS == OSX_OS)
    rmdir(lockDir.c_str());
#else
    BOOL retStatus = RemoveDirectoryA(lockDir.c_str());
    assert(retStatus == TRUE);
#endif
  }

  parsedKernelInfo parseFileForFunction(const std::string &filename,
                                        const std::string &cachedBinary,
                                        const std::string &functionName,
                                        const kernelInfo &info){
    const std::string iCachedBinary = getMidCachedBinaryName(cachedBinary, "i");
    const std::string pCachedBinary = getMidCachedBinaryName(cachedBinary, "p");

    parser fileParser;

    std::ofstream fs;
    fs.open(pCachedBinary.c_str());

    fs << info.header << readFile(filename);

    fs.close();
    fs.clear();

    fs.open(iCachedBinary.c_str());
    fs << info.occaKeywords << fileParser.parseFile(pCachedBinary);

    fs.close();

    kernelInfoIterator kIt = fileParser.kernelInfoMap.find(functionName);

    if(kIt != fileParser.kernelInfoMap.end()){
      return parsedKernelInfo( *((kIt++)->second) );
    }

    std::cout << "Could not find function ["
              << functionName << "] in file ["
              << filename     << "].\n";
    throw 1;

    return parsedKernelInfo();
  }

  std::string fnv(const std::string &saltedString){
    const int len = saltedString.size();
    std::stringstream ss;

    int h[8] = {101527, 101531,
                101533, 101537,
                101561, 101573,
                101581, 101599};

    const int p[8] = {102679, 102701,
                      102761, 102763,
                      102769, 102793,
                      102797, 102811};

    for(int c = 0; c < len; ++c)
      for(int i = 0; i < 8; ++i)
        h[i] = (h[i] * p[i]) ^ saltedString[c];

    // int h2[8];

    // for(int i = 0; i < 8; ++i)
    //   h2[i] = ((h[0] & (0xFF << (8*i))) << (8*i + 0))
    //     |     ((h[1] & (0xFF << (8*i))) << (8*i + 1))
    //     |     ((h[2] & (0xFF << (8*i))) << (8*i + 2))
    //     |     ((h[3] & (0xFF << (8*i))) << (8*i + 3))
    //     |     ((h[4] & (0xFF << (8*i))) << (8*i + 4))
    //     |     ((h[5] & (0xFF << (8*i))) << (8*i + 5))
    //     |     ((h[6] & (0xFF << (8*i))) << (8*i + 6))
    //     |     ((h[7] & (0xFF << (8*i))) << (8*i + 7));

    for(int i = 0; i < 8; ++i)
      ss <<  std::hex << h[i];

    return ss.str();
  }

  bool fileExists(const std::string &filename){
    struct stat buffer;
    return (stat(filename.c_str(), &buffer) == 0);
  }

  std::string readFile(const std::string &filename){
    // NBN: handle EOL chars on Windows
    FILE *fp = fopen(filename.c_str(), "r");

    if(!fp){
      printf("Failed to open: %s\n", filename.c_str());
      throw 1;
    }

    struct stat statbuf;
    stat(filename.c_str(), &statbuf);

    const size_t nchars = statbuf.st_size;

    char *buffer = (char*) calloc(nchars, sizeof(char));
    size_t nread = fread(buffer, sizeof(char), nchars, fp);

    fclose(fp);

    std::string contents(buffer, nread);

    free(buffer);

    return contents;
  }

  std::string getOCCADir(){
    char *c_occaPath = getenv("OCCA_DIR");

    if(c_occaPath != NULL)
      return c_occaPath;

    std::cout << "Environment variable [OCCA_DIR] is not set.\n";
    throw 1;

    return "";
  }

  std::string getCachePath(){
    char *c_cachePath = getenv("OCCA_CACHE_DIR");

    bool hasDir = false;

    std::string occaCachePath;

    if(c_cachePath != NULL)
      occaCachePath = c_cachePath;
    else{
      std::stringstream ss;
#if (OCCA_OS == LINUX_OS) || (OCCA_OS == OSX_OS)
      char *c_home = getenv("HOME");
      ss << c_home << "/._occa";

      occaCachePath = ss.str();
#else
      char *c_home = getenv("USERPROFILE");

      ss << c_home << "\\AppData\\Local\\OCCA";

#  if OCCA_64_BIT
      ss << "_amd64";  // use different dir's fro 32 and 64 bit
#  else
      ss << "_x86";    // use different dir's fro 32 and 64 bit
#  endif

      occaCachePath = ss.str();
#endif
    }

    const int chars = occaCachePath.size();

    OCCA_CHECK(0 < chars);

#if (OCCA_OS == LINUX_OS) || (OCCA_OS == OSX_OS)
    const char slashChar = '/';
#else
    const char slashChar = '\\';
#endif

    // Take out the pesky //'s
    int pos = 0;

    for(int i = 0; i < chars; ++i){
      if(occaCachePath[i] == slashChar)
        while(i < (chars - 1) && occaCachePath[i + 1] == slashChar)
          ++i;

      occaCachePath[pos++] = occaCachePath[i];
    }

    if(occaCachePath[pos - 1] != slashChar){
      if(pos != chars)
        occaCachePath[pos] = slashChar;
      else
        occaCachePath += slashChar;
    }

    if(!fileExists(occaCachePath)){
#if (OCCA_OS == LINUX_OS) || (OCCA_OS == OSX_OS)
      mkdir(occaCachePath.c_str(), 0755);
#else
      LPCSTR w_occaCachePath = occaCachePath.c_str();
      BOOL mkdirStatus = CreateDirectoryA(w_occaCachePath, NULL);

      if(mkdirStatus == FALSE)
        assert(GetLastError() == ERROR_ALREADY_EXISTS);
#endif
    }

    return occaCachePath;
  }

  bool fileNeedsParser(const std::string &filename){
    std::string ext = getFileExtension(filename);

    return ((ext == "okl") ||
            (ext == "cl") ||
            (ext == "cu"));
  }

  std::string getCachedName(const std::string &filename,
                            const std::string &salt){

    std::string occaCachePath = getCachePath();
    //================================

    const std::string fileContents = readFile(filename);
    const std::string contentsSHA  = fnv(fileContents + salt);

    // Only taking the first 16 characters
    return occaCachePath + contentsSHA.substr(0, 16);
  }

  std::string createIntermediateSource(const std::string &filename,
                                       const std::string &cachedBinary,
                                       const kernelInfo &info){
    std::string prefix, name;
    getFilePrefixAndName(cachedBinary, prefix, name);

    const std::string iCachedBinary = prefix + "i_" + name;

    if(fileNeedsParser(filename)){
      const std::string pCachedBinary = prefix + "p_" + name;
      parser fileParser;

      std::ofstream fs;
      fs.open(pCachedBinary.c_str());

      fs << info.header << readFile(filename);

      fs.close();

      fs.open(iCachedBinary.c_str());
      fs << info.occaKeywords << fileParser.parseFile(pCachedBinary);

      fs.close();
    }
    else{
      std::ofstream fs;
      fs.open(iCachedBinary.c_str());

      fs << info.occaKeywords << info.header << readFile(filename);

      fs.close();
    }

    return iCachedBinary;
  }
};
<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Un Shyam & Arvid Norberg
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 the author 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 OWNER 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.

*/

#ifndef TORRENT_DISABLE_ENCRYPTION

#include <algorithm>

#include <openssl/dh.h>
#include <openssl/engine.h>

#include "libtorrent/pe_crypto.hpp"
#include "libtorrent/assert.hpp"

namespace libtorrent
{

	// Set the prime P and the generator, generate local public key
	DH_key_exchange::DH_key_exchange()
	{
		m_DH = DH_new();
		if (m_DH == 0) throw std::bad_alloc();

		m_DH->p = BN_bin2bn(m_dh_prime, sizeof(m_dh_prime), NULL);
		m_DH->g = BN_bin2bn(m_dh_generator, sizeof(m_dh_generator), NULL);
		if (m_DH->p == 0 || m_DH->g == 0)
		{
			DH_free(m_DH);
			throw std::bad_alloc();
		}

		m_DH->length = 160l;

		TORRENT_ASSERT(sizeof(m_dh_prime) == DH_size(m_DH));

		DH_generate_key(m_DH);
		if (m_DH->pub_key == 0)
		{
			DH_free(m_DH);
			throw std::bad_alloc();
		}

		// DH can generate key sizes that are smaller than the size of
		// P with exponentially decreasing probability, in which case
		// the msb's of m_dh_local_key need to be zeroed
		// appropriately.
		int key_size = get_local_key_size();
		int len_dh = sizeof(m_dh_prime); // must equal DH_size(m_DH)
		if (key_size != len_dh)
		{
			TORRENT_ASSERT(key_size > 0 && key_size < len_dh);

			int pad_zero_size = len_dh - key_size;
			std::fill(m_dh_local_key, m_dh_local_key + pad_zero_size, 0);
			BN_bn2bin(m_DH->pub_key, (unsigned char*)m_dh_local_key + pad_zero_size);
		}
		else
			BN_bn2bin(m_DH->pub_key, (unsigned char*)m_dh_local_key); // TODO Check return value
	}

	DH_key_exchange::~DH_key_exchange()
	{
		TORRENT_ASSERT(m_DH);
		DH_free(m_DH);
	}

	char const* DH_key_exchange::get_local_key() const
	{
		return m_dh_local_key;
	}

	// compute shared secret given remote public key
	void DH_key_exchange::compute_secret(char const* remote_pubkey)
	{
		TORRENT_ASSERT(remote_pubkey);
		BIGNUM* bn_remote_pubkey = BN_bin2bn ((unsigned char*)remote_pubkey, 96, NULL);
		if (bn_remote_pubkey == 0) throw std::bad_alloc();
		char dh_secret[96];

		int secret_size = DH_compute_key((unsigned char*)dh_secret
			, bn_remote_pubkey, m_DH);
		if (secret_size < 0 || secret_size > 96) throw std::bad_alloc();

		if (secret_size != 96)
		{
			TORRENT_ASSERT(secret_size < 96 && secret_size > 0);
			std::fill(m_dh_secret, m_dh_secret + 96 - secret_size, 0);
		}
		std::copy(dh_secret, dh_secret + secret_size, m_dh_secret + 96 - secret_size);
		BN_free(bn_remote_pubkey);
	}

	char const* DH_key_exchange::get_secret() const
	{
		return m_dh_secret;
	}

	const unsigned char DH_key_exchange::m_dh_prime[96] = {
		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
		0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
		0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
		0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
		0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
		0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
		0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
		0xA6, 0x3A, 0x36, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, 0x63
	};

	const unsigned char DH_key_exchange::m_dh_generator[1] = { 2 };

} // namespace libtorrent

#endif // #ifndef TORRENT_DISABLE_ENCRYPTION

<commit_msg>fixed error handling in pe-crypto<commit_after>/*

Copyright (c) 2007, Un Shyam & Arvid Norberg
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 the author 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 OWNER 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.

*/

#ifndef TORRENT_DISABLE_ENCRYPTION

#include <algorithm>

#include <openssl/dh.h>
#include <openssl/engine.h>

#include "libtorrent/pe_crypto.hpp"
#include "libtorrent/assert.hpp"

namespace libtorrent
{

	// Set the prime P and the generator, generate local public key
	DH_key_exchange::DH_key_exchange()
	{
		m_DH = DH_new();
		if (m_DH == 0) throw std::bad_alloc();

		m_DH->p = BN_bin2bn(m_dh_prime, sizeof(m_dh_prime), NULL);
		m_DH->g = BN_bin2bn(m_dh_generator, sizeof(m_dh_generator), NULL);
		if (m_DH->p == 0 || m_DH->g == 0)
		{
			DH_free(m_DH);
			throw std::bad_alloc();
		}

		m_DH->length = 160l;

		TORRENT_ASSERT(sizeof(m_dh_prime) == DH_size(m_DH));

		if (DH_generate_key(m_DH) == 0 || m_DH->pub_key == 0)
		{
			DH_free(m_DH);
			throw std::bad_alloc();
		}

		// DH can generate key sizes that are smaller than the size of
		// P with exponentially decreasing probability, in which case
		// the msb's of m_dh_local_key need to be zeroed
		// appropriately.
		int key_size = get_local_key_size();
		int len_dh = sizeof(m_dh_prime); // must equal DH_size(m_DH)
		if (key_size != len_dh)
		{
			TORRENT_ASSERT(key_size > 0 && key_size < len_dh);

			int pad_zero_size = len_dh - key_size;
			std::fill(m_dh_local_key, m_dh_local_key + pad_zero_size, 0);
			BN_bn2bin(m_DH->pub_key, (unsigned char*)m_dh_local_key + pad_zero_size);
		}
		else
			BN_bn2bin(m_DH->pub_key, (unsigned char*)m_dh_local_key); // TODO Check return value
	}

	DH_key_exchange::~DH_key_exchange()
	{
		TORRENT_ASSERT(m_DH);
		DH_free(m_DH);
	}

	char const* DH_key_exchange::get_local_key() const
	{
		return m_dh_local_key;
	}

	// compute shared secret given remote public key
	void DH_key_exchange::compute_secret(char const* remote_pubkey)
	{
		TORRENT_ASSERT(remote_pubkey);
		BIGNUM* bn_remote_pubkey = BN_bin2bn ((unsigned char*)remote_pubkey, 96, NULL);
		if (bn_remote_pubkey == 0) throw std::bad_alloc();
		char dh_secret[96];

		int secret_size = DH_compute_key((unsigned char*)dh_secret
			, bn_remote_pubkey, m_DH);
		if (secret_size < 0 || secret_size > 96) throw std::bad_alloc();

		if (secret_size != 96)
		{
			TORRENT_ASSERT(secret_size < 96 && secret_size > 0);
			std::fill(m_dh_secret, m_dh_secret + 96 - secret_size, 0);
		}
		std::copy(dh_secret, dh_secret + secret_size, m_dh_secret + 96 - secret_size);
		BN_free(bn_remote_pubkey);
	}

	char const* DH_key_exchange::get_secret() const
	{
		return m_dh_secret;
	}

	const unsigned char DH_key_exchange::m_dh_prime[96] = {
		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
		0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
		0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
		0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
		0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
		0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
		0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
		0xA6, 0x3A, 0x36, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, 0x63
	};

	const unsigned char DH_key_exchange::m_dh_generator[1] = { 2 };

} // namespace libtorrent

#endif // #ifndef TORRENT_DISABLE_ENCRYPTION

<|endoftext|>


<commit_before>/*
  This file is part of the PhantomJS project from Ofi Labs.

  Copyright (C) 2010 Ariya Hidayat <ariya.hidayat@gmail.com>

  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 the <organization> 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 <COPYRIGHT HOLDER> 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 <QtGui>
#include <QtWebKit>
#include <iostream>

#if QT_VERSION < QT_VERSION_CHECK(4, 5, 0)
#error Use Qt 4.5 or later version
#endif

#define PHANTOMJS_VERSION_MAJOR  1
#define PHANTOMJS_VERSION_MINOR  1
#define PHANTOMJS_VERSION_PATCH  0
#define PHANTOMJS_VERSION_STRING "1.1.0"

class WebPage: public QWebPage
{
    Q_OBJECT
public:
    WebPage(QObject *parent = 0);

public slots:
    bool shouldInterruptJavaScript();

protected:
    void javaScriptAlert(QWebFrame *originatingFrame, const QString &msg);
    void javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID);
    QString userAgentForUrl(const QUrl &url) const;

private:
    QString m_userAgent;
    friend class Phantom;
};

WebPage::WebPage(QObject *parent)
    : QWebPage(parent)
{
    m_userAgent = QWebPage::userAgentForUrl(QUrl());
}

void WebPage::javaScriptAlert(QWebFrame *originatingFrame, const QString &msg)
{
    Q_UNUSED(originatingFrame);
    std::cout << "JavaScript alert: " << qPrintable(msg) << std::endl;
}

void WebPage::javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID)
{
    if (!sourceID.isEmpty())
        std::cout << qPrintable(sourceID) << ":" << lineNumber << " ";
    std::cout << qPrintable(message) << std::endl;
}

bool WebPage::shouldInterruptJavaScript()
{
    QApplication::processEvents(QEventLoop::AllEvents, 42);
    return false;
}

QString WebPage::userAgentForUrl(const QUrl &url) const
{
    Q_UNUSED(url);
    return m_userAgent;
}

class Phantom: public QObject
{
    Q_OBJECT
    Q_PROPERTY(QStringList args READ args)
    Q_PROPERTY(QString content READ content WRITE setContent)
    Q_PROPERTY(QString loadStatus READ loadStatus)
    Q_PROPERTY(QString state READ state WRITE setState)
    Q_PROPERTY(QString userAgent READ userAgent WRITE setUserAgent)
    Q_PROPERTY(QVariantMap version READ version)
    Q_PROPERTY(QVariantMap viewportSize READ viewportSize WRITE setViewportSize)

public:
    Phantom(QObject *parent = 0);

    QStringList args() const;

    QString content() const;
    void setContent(const QString &content);

    void execute(const QString &fileName);
    int returnValue() const;

    QString loadStatus() const;

    void setState(const QString &value);
    QString state() const;

    void setUserAgent(const QString &ua);
    QString userAgent() const;

    QVariantMap version() const;

    void setViewportSize(const QVariantMap &size);
    QVariantMap viewportSize() const;

public slots:
    void exit(int code = 0);
    void open(const QString &address);
    bool render(const QString &fileName);
    void sleep(int ms);

private slots:
    void inject();
    void finish(bool);

private:
    QStringList m_args;
    QString m_loadStatus;
    WebPage m_page;
    int m_returnValue;
    QString m_script;
    QString m_state;
};

Phantom::Phantom(QObject *parent)
    : QObject(parent)
    , m_returnValue(0)
{
    QPalette palette = m_page.palette();
    palette.setBrush(QPalette::Base, Qt::transparent);
    m_page.setPalette(palette);

    // first argument: program name (phantomjs)
    // second argument: script name
    m_args = QApplication::arguments();
    m_args.removeFirst();
    m_args.removeFirst();

    connect(m_page.mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), SLOT(inject()));
    connect(&m_page, SIGNAL(loadFinished(bool)), this, SLOT(finish(bool)));

    m_page.settings()->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, true);
    m_page.settings()->setOfflineStoragePath(QDesktopServices::storageLocation(QDesktopServices::DataLocation));

    m_page.settings()->setAttribute(QWebSettings::LocalStorageDatabaseEnabled, true);

#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
    m_page.settings()->setAttribute(QWebSettings::FrameFlatteningEnabled, true);
#endif

#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
    m_page.settings()->setAttribute(QWebSettings::LocalStorageEnabled, true);
    m_page.settings()->setLocalStoragePath(QDesktopServices::storageLocation(QDesktopServices::DataLocation));
#endif

    // Ensure we have document.body.
    m_page.mainFrame()->setHtml("");

    m_page.mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
    m_page.mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
}

QStringList Phantom::args() const
{
     return m_args;
}

QString Phantom::content() const
{
    return m_page.mainFrame()->toHtml();
}

void Phantom::setContent(const QString &content)
{
    m_page.mainFrame()->setHtml(content);
}

void Phantom::execute(const QString &fileName)
{
    QFile file;
    file.setFileName(fileName);
    if (!file.open(QFile::ReadOnly)) {
        std::cerr << "Can't open " << qPrintable(fileName) << std::endl << std::endl;
        exit(1);
        return;
    }
    m_script =  QString::fromUtf8(file.readAll());
    file.close();

    if (m_script.startsWith("#!")) {
        m_script.prepend("//");
    }

    m_page.mainFrame()->evaluateJavaScript(m_script);
}

void Phantom::exit(int code)
{
    m_returnValue = code;
    disconnect(&m_page, SIGNAL(loadFinished(bool)), this, SLOT(finish(bool)));
    QTimer::singleShot(0, qApp, SLOT(quit()));
}

void Phantom::finish(bool success)
{
    m_loadStatus = success ? "success" : "fail";
    m_page.mainFrame()->evaluateJavaScript(m_script);
}

void Phantom::inject()
{
    m_page.mainFrame()->addToJavaScriptWindowObject("phantom", this);
}

QString Phantom::loadStatus() const
{
    return m_loadStatus;
}

void Phantom::open(const QString &address)
{
    m_page.triggerAction(QWebPage::Stop);
    m_loadStatus = "loading";
    m_page.mainFrame()->setUrl(address);
}

bool Phantom::render(const QString &fileName)
{
    QFileInfo fileInfo(fileName);
    QDir dir;
    dir.mkpath(fileInfo.absolutePath());

    if (fileName.toLower().endsWith(".pdf")) {
        QPrinter printer;
        printer.setOutputFormat(QPrinter::PdfFormat);
        printer.setOutputFileName(fileName);
        m_page.mainFrame()->print(&printer);
        return true;
    }

    QSize viewportSize = m_page.viewportSize();
    QSize pageSize = m_page.mainFrame()->contentsSize();
    if (pageSize.isEmpty())
        return false;

    QImage buffer(pageSize, QImage::Format_ARGB32);
    buffer.fill(qRgba(255, 255, 255, 0));
    QPainter p(&buffer);
    p.setRenderHint(QPainter::Antialiasing, true);
    p.setRenderHint(QPainter::TextAntialiasing, true);
    p.setRenderHint(QPainter::SmoothPixmapTransform, true);
    m_page.setViewportSize(pageSize);
    m_page.mainFrame()->render(&p);
    p.end();
    m_page.setViewportSize(viewportSize);
    return buffer.save(fileName);
}

int Phantom::returnValue() const
{
    return m_returnValue;
}

void Phantom::sleep(int ms)
{
    QTime startTime = QTime::currentTime();
    while (true) {
        QApplication::processEvents(QEventLoop::AllEvents, 25);
        if (startTime.msecsTo(QTime::currentTime()) > ms)
            break;
    }
}

void Phantom::setState(const QString &value)
{
    m_state = value;
}

QString Phantom::state() const
{
    return m_state;
}

void Phantom::setUserAgent(const QString &ua)
{
    m_page.m_userAgent = ua;
}

QString Phantom::userAgent() const
{
    return m_page.m_userAgent;
}

QVariantMap Phantom::version() const
{
    QVariantMap result;
    result["major"] = PHANTOMJS_VERSION_MAJOR;
    result["minor"] = PHANTOMJS_VERSION_MINOR;
    result["patch"] = PHANTOMJS_VERSION_PATCH;
    return result;
}

void Phantom::setViewportSize(const QVariantMap &size)
{
    int w = size.value("width").toInt();
    int h = size.value("height").toInt();
    if (w > 0 && h > 0)
        m_page.setViewportSize(QSize(w, h));
}

QVariantMap Phantom::viewportSize() const
{
    QVariantMap result;
    QSize size = m_page.viewportSize();
    result["width"] = size.width();
    result["height"] = size.height();
    return result;
}

#include "phantomjs.moc"

int main(int argc, char** argv)
{
    if (argc < 2) {
        std::cerr << "phantomjs script.js" << std::endl << std::endl;
        return 1;
    }

    QNetworkProxyFactory::setUseSystemConfiguration(true);

    QApplication app(argc, argv);

    app.setWindowIcon(QIcon(":/phantomjs-icon.png"));
    app.setApplicationName("PhantomJS");
    app.setOrganizationName("Ofi Labs");
    app.setOrganizationDomain("www.ofilabs.com");
    app.setApplicationVersion(PHANTOMJS_VERSION_STRING);

    Phantom phantom;
    phantom.execute(QString::fromLocal8Bit(argv[1]));
    app.exec();
    return phantom.returnValue();
}
<commit_msg>File Uploads pass --upload-file fileTag=/path/to/file as an argument and set the file of <input type="file" id="foo"/> by calling phantom.setFormInputFile(document.getElementById('foo'), 'fileTag');<commit_after>/*
  This file is part of the PhantomJS project from Ofi Labs.

  Copyright (C) 2010 Ariya Hidayat <ariya.hidayat@gmail.com>

  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 the <organization> 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 <COPYRIGHT HOLDER> 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 <QtGui>
#include <QtWebKit>
#include <iostream>

#if QT_VERSION < QT_VERSION_CHECK(4, 5, 0)
#error Use Qt 4.5 or later version
#endif

#define PHANTOMJS_VERSION_MAJOR  1
#define PHANTOMJS_VERSION_MINOR  1
#define PHANTOMJS_VERSION_PATCH  0
#define PHANTOMJS_VERSION_STRING "1.1.0"

class WebPage: public QWebPage
{
    Q_OBJECT
public:
    WebPage(QObject *parent = 0);

public slots:
    bool shouldInterruptJavaScript();

protected:
    void javaScriptAlert(QWebFrame *originatingFrame, const QString &msg);
    void javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID);
    QString userAgentForUrl(const QUrl &url) const;
    QString chooseFile (QWebFrame * parentFrame, const QString & suggestedFile );

private:
    QString m_userAgent;
    QMap<QString, QString> m_allowedFiles;
    QString m_nextFileTag;
    friend class Phantom;
};

WebPage::WebPage(QObject *parent)
    : QWebPage(parent)
{
    m_userAgent = QWebPage::userAgentForUrl(QUrl());
}

void WebPage::javaScriptAlert(QWebFrame *originatingFrame, const QString &msg)
{
    Q_UNUSED(originatingFrame);
    std::cout << "JavaScript alert: " << qPrintable(msg) << std::endl;
}

void WebPage::javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID)
{
    if (!sourceID.isEmpty())
        std::cout << qPrintable(sourceID) << ":" << lineNumber << " ";
    std::cout << qPrintable(message) << std::endl;
}

bool WebPage::shouldInterruptJavaScript()
{
    QApplication::processEvents(QEventLoop::AllEvents, 42);
    return false;
}

QString WebPage::userAgentForUrl(const QUrl &url) const
{
    Q_UNUSED(url);
    return m_userAgent;
}

QString WebPage::chooseFile (QWebFrame * parentFrame, const QString & suggestedFile )
{
    Q_UNUSED(parentFrame);
    Q_UNUSED(suggestedFile);
    if (m_allowedFiles.contains(m_nextFileTag))
        return m_allowedFiles.value(m_nextFileTag);
    return NULL;
}

class Phantom: public QObject
{
    Q_OBJECT
    Q_PROPERTY(QStringList args READ args)
    Q_PROPERTY(QString content READ content WRITE setContent)
    Q_PROPERTY(QString loadStatus READ loadStatus)
    Q_PROPERTY(QString state READ state WRITE setState)
    Q_PROPERTY(QString userAgent READ userAgent WRITE setUserAgent)
    Q_PROPERTY(QVariantMap version READ version)
    Q_PROPERTY(QVariantMap viewportSize READ viewportSize WRITE setViewportSize)

public:
    Phantom(QObject *parent = 0);

    QStringList args() const;

    QString content() const;
    void setContent(const QString &content);

    void execute(const QString &fileName);
    int returnValue() const;

    QString loadStatus() const;

    void setState(const QString &value);
    QString state() const;

    void setUserAgent(const QString &ua);
    QString userAgent() const;

    QVariantMap version() const;

    void setViewportSize(const QVariantMap &size);
    QVariantMap viewportSize() const;

public slots:
    void exit(int code = 0);
    void open(const QString &address);
    void setFormInputFile(QWebElement el, const QString &fileTag);
    bool render(const QString &fileName);
    void sleep(int ms);

private slots:
    void inject();
    void finish(bool);

private:
    QStringList m_args;
    QString m_loadStatus;
    WebPage m_page;
    int m_returnValue;
    QString m_script;
    QString m_state;
};

Phantom::Phantom(QObject *parent)
    : QObject(parent)
    , m_returnValue(0)
{
    QPalette palette = m_page.palette();
    palette.setBrush(QPalette::Base, Qt::transparent);
    m_page.setPalette(palette);

    // first argument: program name (phantomjs)
    // second argument: script name
    m_args = QApplication::arguments();
    m_args.removeFirst();
    m_args.removeFirst();

    QStringListIterator argIterator(m_args);
    while (argIterator.hasNext()) {
        const QString &arg = argIterator.next();
        if (arg.startsWith("--upload-file") && argIterator.hasNext()) {
            const QString &fileInfoString = argIterator.next();
            QStringList fileInfo = fileInfoString.split("=");
            const QString &tag = fileInfo.at(0);
            const QString &fileName = fileInfo.at(1);
            m_page.m_allowedFiles[tag] = fileName;
        }
    }

    connect(m_page.mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), SLOT(inject()));
    connect(&m_page, SIGNAL(loadFinished(bool)), this, SLOT(finish(bool)));

    m_page.settings()->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, true);
    m_page.settings()->setOfflineStoragePath(QDesktopServices::storageLocation(QDesktopServices::DataLocation));

    m_page.settings()->setAttribute(QWebSettings::LocalStorageDatabaseEnabled, true);

#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
    m_page.settings()->setAttribute(QWebSettings::FrameFlatteningEnabled, true);
#endif

#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
    m_page.settings()->setAttribute(QWebSettings::LocalStorageEnabled, true);
    m_page.settings()->setLocalStoragePath(QDesktopServices::storageLocation(QDesktopServices::DataLocation));
#endif

    // Ensure we have document.body.
    m_page.mainFrame()->setHtml("");

    m_page.mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
    m_page.mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
}

QStringList Phantom::args() const
{
     return m_args;
}

QString Phantom::content() const
{
    return m_page.mainFrame()->toHtml();
}

void Phantom::setContent(const QString &content)
{
    m_page.mainFrame()->setHtml(content);
}

void Phantom::execute(const QString &fileName)
{
    QFile file;
    file.setFileName(fileName);
    if (!file.open(QFile::ReadOnly)) {
        std::cerr << "Can't open " << qPrintable(fileName) << std::endl << std::endl;
        exit(1);
        return;
    }
    m_script =  QString::fromUtf8(file.readAll());
    file.close();

    if (m_script.startsWith("#!")) {
        m_script.prepend("//");
    }

    m_page.mainFrame()->evaluateJavaScript(m_script);
}

void Phantom::exit(int code)
{
    m_returnValue = code;
    disconnect(&m_page, SIGNAL(loadFinished(bool)), this, SLOT(finish(bool)));
    QTimer::singleShot(0, qApp, SLOT(quit()));
}

void Phantom::finish(bool success)
{
    m_loadStatus = success ? "success" : "fail";
    m_page.mainFrame()->evaluateJavaScript(m_script);
}

void Phantom::inject()
{
    m_page.mainFrame()->addToJavaScriptWindowObject("phantom", this);
}

QString Phantom::loadStatus() const
{
    return m_loadStatus;
}

void Phantom::open(const QString &address)
{
    m_page.triggerAction(QWebPage::Stop);
    m_loadStatus = "loading";
    m_page.mainFrame()->setUrl(address);
}

bool Phantom::render(const QString &fileName)
{
    QFileInfo fileInfo(fileName);
    QDir dir;
    dir.mkpath(fileInfo.absolutePath());

    if (fileName.toLower().endsWith(".pdf")) {
        QPrinter printer;
        printer.setOutputFormat(QPrinter::PdfFormat);
        printer.setOutputFileName(fileName);
        m_page.mainFrame()->print(&printer);
        return true;
    }

    QSize viewportSize = m_page.viewportSize();
    QSize pageSize = m_page.mainFrame()->contentsSize();
    if (pageSize.isEmpty())
        return false;

    QImage buffer(pageSize, QImage::Format_ARGB32);
    buffer.fill(qRgba(255, 255, 255, 0));
    QPainter p(&buffer);
    p.setRenderHint(QPainter::Antialiasing, true);
    p.setRenderHint(QPainter::TextAntialiasing, true);
    p.setRenderHint(QPainter::SmoothPixmapTransform, true);
    m_page.setViewportSize(pageSize);
    m_page.mainFrame()->render(&p);
    p.end();
    m_page.setViewportSize(viewportSize);
    return buffer.save(fileName);
}

int Phantom::returnValue() const
{
    return m_returnValue;
}

void Phantom::sleep(int ms)
{
    QTime startTime = QTime::currentTime();
    while (true) {
        QApplication::processEvents(QEventLoop::AllEvents, 25);
        if (startTime.msecsTo(QTime::currentTime()) > ms)
            break;
    }
}

void Phantom::setFormInputFile(QWebElement el, const QString &fileTag) {
    m_page.m_nextFileTag = fileTag;
    el.evaluateJavaScript("(function(target){  \
                          var evt = document.createEvent('MouseEvents'); \
                          evt.initMouseEvent(\"click\", true, true, window, \
                          0, 0, 0, 0, 0, false, false, false, false, 0, null); \
                          target.dispatchEvent(evt);})(this);");
}

void Phantom::setState(const QString &value)
{
    m_state = value;
}

QString Phantom::state() const
{
    return m_state;
}

void Phantom::setUserAgent(const QString &ua)
{
    m_page.m_userAgent = ua;
}

QString Phantom::userAgent() const
{
    return m_page.m_userAgent;
}

QVariantMap Phantom::version() const
{
    QVariantMap result;
    result["major"] = PHANTOMJS_VERSION_MAJOR;
    result["minor"] = PHANTOMJS_VERSION_MINOR;
    result["patch"] = PHANTOMJS_VERSION_PATCH;
    return result;
}

void Phantom::setViewportSize(const QVariantMap &size)
{
    int w = size.value("width").toInt();
    int h = size.value("height").toInt();
    if (w > 0 && h > 0)
        m_page.setViewportSize(QSize(w, h));
}

QVariantMap Phantom::viewportSize() const
{
    QVariantMap result;
    QSize size = m_page.viewportSize();
    result["width"] = size.width();
    result["height"] = size.height();
    return result;
}

#include "phantomjs.moc"

int main(int argc, char** argv)
{
    if (argc < 2) {
        std::cerr << "phantomjs script.js" << std::endl << std::endl;
        return 1;
    }

    QNetworkProxyFactory::setUseSystemConfiguration(true);

    QApplication app(argc, argv);

    app.setWindowIcon(QIcon(":/phantomjs-icon.png"));
    app.setApplicationName("PhantomJS");
    app.setOrganizationName("Ofi Labs");
    app.setOrganizationDomain("www.ofilabs.com");
    app.setApplicationVersion(PHANTOMJS_VERSION_STRING);

    Phantom phantom;
    phantom.execute(QString::fromLocal8Bit(argv[1]));
    app.exec();
    return phantom.returnValue();
}
<|endoftext|>


<commit_before>/*
  This file is part of the PhantomJS project from Ofi Labs.

  Copyright (C) 2010 Ariya Hidayat <ariya.hidayat@gmail.com>

  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 the <organization> 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 <COPYRIGHT HOLDER> 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 <QtGui>
#include <QtWebKit>
#include <iostream>

#if QT_VERSION < QT_VERSION_CHECK(4, 5, 0)
#error Use Qt 4.5 or later version
#endif

#define PHANTOMJS_VERSION_MAJOR  1
#define PHANTOMJS_VERSION_MINOR  0
#define PHANTOMJS_VERSION_PATCH  0
#define PHANTOMJS_VERSION_STRING "1.0.0"

class WebPage: public QWebPage
{
    Q_OBJECT
public:
    WebPage(QObject *parent = 0);

public slots:
    bool shouldInterruptJavaScript();

protected:
    void javaScriptAlert(QWebFrame *originatingFrame, const QString &msg);
    void javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID);
    QString userAgentForUrl(const QUrl &url) const;

private:
    QString m_userAgent;
    friend class Phantom;
};

WebPage::WebPage(QObject *parent)
    : QWebPage(parent)
{
    m_userAgent = QWebPage::userAgentForUrl(QUrl());
}

void WebPage::javaScriptAlert(QWebFrame *originatingFrame, const QString &msg)
{
    Q_UNUSED(originatingFrame);
    std::cout << "JavaScript alert: " << qPrintable(msg) << std::endl;
}

void WebPage::javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID)
{
    if (!sourceID.isEmpty())
        std::cout << qPrintable(sourceID) << ":" << lineNumber << " ";
    std::cout << qPrintable(message) << std::endl;
}

bool WebPage::shouldInterruptJavaScript()
{
    QApplication::processEvents(QEventLoop::AllEvents, 42);
    return false;
}

QString WebPage::userAgentForUrl(const QUrl &url) const
{
    Q_UNUSED(url);
    return m_userAgent;
}

class Phantom: public QObject
{
    Q_OBJECT
    Q_PROPERTY(QStringList args READ args)
    Q_PROPERTY(QString content READ content WRITE setContent)
    Q_PROPERTY(QString loadStatus READ loadStatus)
    Q_PROPERTY(QString state READ state WRITE setState)
    Q_PROPERTY(QString userAgent READ userAgent WRITE setUserAgent)
    Q_PROPERTY(QVariantMap version READ version)
    Q_PROPERTY(QVariantMap viewportSize READ viewportSize WRITE setViewportSize)

public:
    Phantom(QObject *parent = 0);

    QStringList args() const;

    QString content() const;
    void setContent(const QString &content);

    void execute(const QString &fileName);
    int returnValue() const;

    QString loadStatus() const;

    void setState(const QString &value);
    QString state() const;

    void setUserAgent(const QString &ua);
    QString userAgent() const;

    QVariantMap version() const;

    void setViewportSize(const QVariantMap &size);
    QVariantMap viewportSize() const;

public slots:
    void exit(int code = 0);
    void open(const QString &address);
    bool render(const QString &fileName);
    void sleep(int ms);

private slots:
    void inject();
    void finish(bool);

private:
    QStringList m_args;
    QString m_loadStatus;
    WebPage m_page;
    int m_returnValue;
    QString m_script;
    QString m_state;
};

Phantom::Phantom(QObject *parent)
    : QObject(parent)
    , m_returnValue(0)
{
    QPalette palette = m_page.palette();
    palette.setBrush(QPalette::Base, Qt::transparent);
    m_page.setPalette(palette);

    // first argument: program name (phantomjs)
    // second argument: script name
    m_args = QApplication::arguments();
    m_args.removeFirst();
    m_args.removeFirst();

    connect(m_page.mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), SLOT(inject()));
    connect(&m_page, SIGNAL(loadFinished(bool)), this, SLOT(finish(bool)));

    m_page.settings()->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, true);
    m_page.settings()->setOfflineStoragePath(QDesktopServices::storageLocation(QDesktopServices::DataLocation));

    #if QT_VERSION < QT_VERSION_CHECK(4, 6, 0)
      m_page.settings()->setAttribute(QWebSettings::LocalStorageDatabaseEnabled, true);
    #else
      m_page.settings()->setAttribute(QWebSettings::FrameFlatteningEnabled, true);
      m_page.settings()->setAttribute(QWebSettings::LocalStorageEnabled, true);
      m_page.settings()->setLocalStoragePath(QDesktopServices::storageLocation(QDesktopServices::DataLocation));
    #endif

    // Ensure we have document.body.
    m_page.mainFrame()->setHtml("");

    m_page.mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
    m_page.mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
}

QStringList Phantom::args() const
{
     return m_args;
}

QString Phantom::content() const
{
    return m_page.mainFrame()->toHtml();
}

void Phantom::setContent(const QString &content)
{
    m_page.mainFrame()->setHtml(content);
}

void Phantom::execute(const QString &fileName)
{
    QFile file;
    file.setFileName(fileName);
    if (!file.open(QFile::ReadOnly)) {
        std::cerr << "Can't open " << qPrintable(fileName) << std::endl << std::endl;
        exit(1);
        return;
    }
    m_script = file.readAll();
    file.close();

    m_page.mainFrame()->evaluateJavaScript(m_script);
}

void Phantom::exit(int code)
{
    m_returnValue = code;
    disconnect(&m_page, SIGNAL(loadFinished(bool)), this, SLOT(finish(bool)));
    QTimer::singleShot(0, qApp, SLOT(quit()));
}

void Phantom::finish(bool success)
{
    m_loadStatus = success ? "success" : "fail";
    m_page.mainFrame()->evaluateJavaScript(m_script);
}

void Phantom::inject()
{
    m_page.mainFrame()->addToJavaScriptWindowObject("phantom", this);
}

QString Phantom::loadStatus() const
{
    return m_loadStatus;
}

void Phantom::open(const QString &address)
{
    m_page.triggerAction(QWebPage::Stop);
    m_loadStatus = "loading";
    m_page.mainFrame()->setUrl(address);
}

bool Phantom::render(const QString &fileName)
{
    QFileInfo fileInfo(fileName);
    QDir dir;
    dir.mkpath(fileInfo.absolutePath());

    if (fileName.toLower().endsWith(".pdf")) {
        QPrinter printer;
        printer.setOutputFormat(QPrinter::PdfFormat);
        printer.setOutputFileName(fileName);
        m_page.mainFrame()->print(&printer);
        return true;
    }

    QSize viewportSize = m_page.viewportSize();
    QSize pageSize = m_page.mainFrame()->contentsSize();
    if (pageSize.isEmpty())
        return false;

    QImage buffer(pageSize, QImage::Format_ARGB32);
    buffer.fill(qRgba(255, 255, 255, 0));
    QPainter p(&buffer);
    p.setRenderHint(QPainter::Antialiasing, true);
    p.setRenderHint(QPainter::TextAntialiasing, true);
    p.setRenderHint(QPainter::SmoothPixmapTransform, true);
    m_page.setViewportSize(pageSize);
    m_page.mainFrame()->render(&p);
    p.end();
    m_page.setViewportSize(viewportSize);
    return buffer.save(fileName);
}

int Phantom::returnValue() const
{
    return m_returnValue;
}

void Phantom::sleep(int ms)
{
    QTime startTime = QTime::currentTime();
    while (true) {
        QApplication::processEvents(QEventLoop::AllEvents, 25);
        if (startTime.msecsTo(QTime::currentTime()) > ms)
            break;
    }
}

void Phantom::setState(const QString &value)
{
    m_state = value;
}

QString Phantom::state() const
{
    return m_state;
}

void Phantom::setUserAgent(const QString &ua)
{
    m_page.m_userAgent = ua;
}

QString Phantom::userAgent() const
{
    return m_page.m_userAgent;
}

QVariantMap Phantom::version() const
{
    QVariantMap result;
    result["major"] = PHANTOMJS_VERSION_MAJOR;
    result["minor"] = PHANTOMJS_VERSION_MINOR;
    result["patch"] = PHANTOMJS_VERSION_PATCH;
    return result;
}

void Phantom::setViewportSize(const QVariantMap &size)
{
    int w = size.value("width").toInt();
    int h = size.value("height").toInt();
    if (w > 0 && h > 0)
        m_page.setViewportSize(QSize(w, h));
}

QVariantMap Phantom::viewportSize() const
{
    QVariantMap result;
    QSize size = m_page.viewportSize();
    result["width"] = size.width();
    result["height"] = size.height();
    return result;
}

#include "phantomjs.moc"

int main(int argc, char** argv)
{
    if (argc < 2) {
        std::cerr << "phantomjs script.js" << std::endl << std::endl;
        return 1;
    }

    QApplication app(argc, argv);

    app.setWindowIcon(QIcon(":/phantomjs-icon.png"));
    app.setApplicationName("PhantomJS");
    app.setOrganizationName("Ofi Labs");
    app.setOrganizationDomain("www.ofilabs.com");
    app.setApplicationVersion(PHANTOMJS_VERSION_STRING);

    Phantom phantom;
    phantom.execute(QString::fromLocal8Bit(argv[1]));
    app.exec();
    return phantom.returnValue();
}
<commit_msg>Fix coding style.<commit_after>/*
  This file is part of the PhantomJS project from Ofi Labs.

  Copyright (C) 2010 Ariya Hidayat <ariya.hidayat@gmail.com>

  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 the <organization> 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 <COPYRIGHT HOLDER> 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 <QtGui>
#include <QtWebKit>
#include <iostream>

#if QT_VERSION < QT_VERSION_CHECK(4, 5, 0)
#error Use Qt 4.5 or later version
#endif

#define PHANTOMJS_VERSION_MAJOR  1
#define PHANTOMJS_VERSION_MINOR  0
#define PHANTOMJS_VERSION_PATCH  0
#define PHANTOMJS_VERSION_STRING "1.0.0"

class WebPage: public QWebPage
{
    Q_OBJECT
public:
    WebPage(QObject *parent = 0);

public slots:
    bool shouldInterruptJavaScript();

protected:
    void javaScriptAlert(QWebFrame *originatingFrame, const QString &msg);
    void javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID);
    QString userAgentForUrl(const QUrl &url) const;

private:
    QString m_userAgent;
    friend class Phantom;
};

WebPage::WebPage(QObject *parent)
    : QWebPage(parent)
{
    m_userAgent = QWebPage::userAgentForUrl(QUrl());
}

void WebPage::javaScriptAlert(QWebFrame *originatingFrame, const QString &msg)
{
    Q_UNUSED(originatingFrame);
    std::cout << "JavaScript alert: " << qPrintable(msg) << std::endl;
}

void WebPage::javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID)
{
    if (!sourceID.isEmpty())
        std::cout << qPrintable(sourceID) << ":" << lineNumber << " ";
    std::cout << qPrintable(message) << std::endl;
}

bool WebPage::shouldInterruptJavaScript()
{
    QApplication::processEvents(QEventLoop::AllEvents, 42);
    return false;
}

QString WebPage::userAgentForUrl(const QUrl &url) const
{
    Q_UNUSED(url);
    return m_userAgent;
}

class Phantom: public QObject
{
    Q_OBJECT
    Q_PROPERTY(QStringList args READ args)
    Q_PROPERTY(QString content READ content WRITE setContent)
    Q_PROPERTY(QString loadStatus READ loadStatus)
    Q_PROPERTY(QString state READ state WRITE setState)
    Q_PROPERTY(QString userAgent READ userAgent WRITE setUserAgent)
    Q_PROPERTY(QVariantMap version READ version)
    Q_PROPERTY(QVariantMap viewportSize READ viewportSize WRITE setViewportSize)

public:
    Phantom(QObject *parent = 0);

    QStringList args() const;

    QString content() const;
    void setContent(const QString &content);

    void execute(const QString &fileName);
    int returnValue() const;

    QString loadStatus() const;

    void setState(const QString &value);
    QString state() const;

    void setUserAgent(const QString &ua);
    QString userAgent() const;

    QVariantMap version() const;

    void setViewportSize(const QVariantMap &size);
    QVariantMap viewportSize() const;

public slots:
    void exit(int code = 0);
    void open(const QString &address);
    bool render(const QString &fileName);
    void sleep(int ms);

private slots:
    void inject();
    void finish(bool);

private:
    QStringList m_args;
    QString m_loadStatus;
    WebPage m_page;
    int m_returnValue;
    QString m_script;
    QString m_state;
};

Phantom::Phantom(QObject *parent)
    : QObject(parent)
    , m_returnValue(0)
{
    QPalette palette = m_page.palette();
    palette.setBrush(QPalette::Base, Qt::transparent);
    m_page.setPalette(palette);

    // first argument: program name (phantomjs)
    // second argument: script name
    m_args = QApplication::arguments();
    m_args.removeFirst();
    m_args.removeFirst();

    connect(m_page.mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), SLOT(inject()));
    connect(&m_page, SIGNAL(loadFinished(bool)), this, SLOT(finish(bool)));

    m_page.settings()->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, true);
    m_page.settings()->setOfflineStoragePath(QDesktopServices::storageLocation(QDesktopServices::DataLocation));

#if QT_VERSION < QT_VERSION_CHECK(4, 6, 0)
    m_page.settings()->setAttribute(QWebSettings::LocalStorageDatabaseEnabled, true);
#else
    m_page.settings()->setAttribute(QWebSettings::FrameFlatteningEnabled, true);
    m_page.settings()->setAttribute(QWebSettings::LocalStorageEnabled, true);
    m_page.settings()->setLocalStoragePath(QDesktopServices::storageLocation(QDesktopServices::DataLocation));
#endif

    // Ensure we have document.body.
    m_page.mainFrame()->setHtml("");

    m_page.mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
    m_page.mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
}

QStringList Phantom::args() const
{
     return m_args;
}

QString Phantom::content() const
{
    return m_page.mainFrame()->toHtml();
}

void Phantom::setContent(const QString &content)
{
    m_page.mainFrame()->setHtml(content);
}

void Phantom::execute(const QString &fileName)
{
    QFile file;
    file.setFileName(fileName);
    if (!file.open(QFile::ReadOnly)) {
        std::cerr << "Can't open " << qPrintable(fileName) << std::endl << std::endl;
        exit(1);
        return;
    }
    m_script = file.readAll();
    file.close();

    m_page.mainFrame()->evaluateJavaScript(m_script);
}

void Phantom::exit(int code)
{
    m_returnValue = code;
    disconnect(&m_page, SIGNAL(loadFinished(bool)), this, SLOT(finish(bool)));
    QTimer::singleShot(0, qApp, SLOT(quit()));
}

void Phantom::finish(bool success)
{
    m_loadStatus = success ? "success" : "fail";
    m_page.mainFrame()->evaluateJavaScript(m_script);
}

void Phantom::inject()
{
    m_page.mainFrame()->addToJavaScriptWindowObject("phantom", this);
}

QString Phantom::loadStatus() const
{
    return m_loadStatus;
}

void Phantom::open(const QString &address)
{
    m_page.triggerAction(QWebPage::Stop);
    m_loadStatus = "loading";
    m_page.mainFrame()->setUrl(address);
}

bool Phantom::render(const QString &fileName)
{
    QFileInfo fileInfo(fileName);
    QDir dir;
    dir.mkpath(fileInfo.absolutePath());

    if (fileName.toLower().endsWith(".pdf")) {
        QPrinter printer;
        printer.setOutputFormat(QPrinter::PdfFormat);
        printer.setOutputFileName(fileName);
        m_page.mainFrame()->print(&printer);
        return true;
    }

    QSize viewportSize = m_page.viewportSize();
    QSize pageSize = m_page.mainFrame()->contentsSize();
    if (pageSize.isEmpty())
        return false;

    QImage buffer(pageSize, QImage::Format_ARGB32);
    buffer.fill(qRgba(255, 255, 255, 0));
    QPainter p(&buffer);
    p.setRenderHint(QPainter::Antialiasing, true);
    p.setRenderHint(QPainter::TextAntialiasing, true);
    p.setRenderHint(QPainter::SmoothPixmapTransform, true);
    m_page.setViewportSize(pageSize);
    m_page.mainFrame()->render(&p);
    p.end();
    m_page.setViewportSize(viewportSize);
    return buffer.save(fileName);
}

int Phantom::returnValue() const
{
    return m_returnValue;
}

void Phantom::sleep(int ms)
{
    QTime startTime = QTime::currentTime();
    while (true) {
        QApplication::processEvents(QEventLoop::AllEvents, 25);
        if (startTime.msecsTo(QTime::currentTime()) > ms)
            break;
    }
}

void Phantom::setState(const QString &value)
{
    m_state = value;
}

QString Phantom::state() const
{
    return m_state;
}

void Phantom::setUserAgent(const QString &ua)
{
    m_page.m_userAgent = ua;
}

QString Phantom::userAgent() const
{
    return m_page.m_userAgent;
}

QVariantMap Phantom::version() const
{
    QVariantMap result;
    result["major"] = PHANTOMJS_VERSION_MAJOR;
    result["minor"] = PHANTOMJS_VERSION_MINOR;
    result["patch"] = PHANTOMJS_VERSION_PATCH;
    return result;
}

void Phantom::setViewportSize(const QVariantMap &size)
{
    int w = size.value("width").toInt();
    int h = size.value("height").toInt();
    if (w > 0 && h > 0)
        m_page.setViewportSize(QSize(w, h));
}

QVariantMap Phantom::viewportSize() const
{
    QVariantMap result;
    QSize size = m_page.viewportSize();
    result["width"] = size.width();
    result["height"] = size.height();
    return result;
}

#include "phantomjs.moc"

int main(int argc, char** argv)
{
    if (argc < 2) {
        std::cerr << "phantomjs script.js" << std::endl << std::endl;
        return 1;
    }

    QApplication app(argc, argv);

    app.setWindowIcon(QIcon(":/phantomjs-icon.png"));
    app.setApplicationName("PhantomJS");
    app.setOrganizationName("Ofi Labs");
    app.setOrganizationDomain("www.ofilabs.com");
    app.setApplicationVersion(PHANTOMJS_VERSION_STRING);

    Phantom phantom;
    phantom.execute(QString::fromLocal8Bit(argv[1]));
    app.exec();
    return phantom.returnValue();
}
<|endoftext|>


<commit_before>/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*  Fluent Bit Demo
 *  ===============
 *  Copyright (C) 2015 Treasure Data 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 <unistd.h>
#include <fluent-bit.h>

int main()
{
    int i;
    int n;
    int ret;
    char tmp[256];
    struct flb_config *config;

    /* Create configuration context */
    config = flb_config_init();
    if (!config) {
        exit(EXIT_FAILURE);
    }

    flb_config_verbose(FLB_TRUE);

    /* Initialize library */
    ret = flb_lib_init(config, (char *) "stdout");
    if (ret != 0) {
        exit(EXIT_FAILURE);
    }

    /* Start the background worker */
    flb_lib_start(config);

    sleep(1);

    /* Push some data */
    for (i = 0; i < 100; i++) {
        n = snprintf(tmp, sizeof(tmp) - 1, "{\"key\": \"val %i\"}", i);
        flb_lib_push(config, tmp, n);
    }

    flb_lib_stop(config);

    return 0;
}
<commit_msg>Example: hello world.cc: remove unnecessary sleep call<commit_after>/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

/*  Fluent Bit Demo
 *  ===============
 *  Copyright (C) 2015 Treasure Data 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 <unistd.h>
#include <fluent-bit.h>

int main()
{
    int i;
    int n;
    int ret;
    char tmp[256];
    struct flb_config *config;

    /* Create configuration context */
    config = flb_config_init();
    if (!config) {
        exit(EXIT_FAILURE);
    }

    flb_config_verbose(FLB_TRUE);

    /* Initialize library */
    ret = flb_lib_init(config, (char *) "stdout");
    if (ret != 0) {
        exit(EXIT_FAILURE);
    }

    /* Start the background worker */
    flb_lib_start(config);

    /* Push some data */
    for (i = 0; i < 100; i++) {
        n = snprintf(tmp, sizeof(tmp) - 1, "{\"key\": \"val %i\"}", i);
        flb_lib_push(config, tmp, n);
    }

    flb_lib_stop(config);

    return 0;
}
<|endoftext|>