<commit_before>// Copyright 2015 Las Venturas Playground. All rights reserved.
// Use of this source code is governed by the MIT license, a copy of which can
// be found in the LICENSE file.

#include "playground/bindings/modules/mysql_module.h"

#include <memory>
#include <string>
#include <unordered_map>

#include <my_global.h>
#include <my_sys.h>
#include <mysql.h>

#include "base/logging.h"
#include "base/macros.h"
#include "playground/bindings/frame_observer.h"
#include "playground/bindings/modules/mysql/connection_delegate.h"
#include "playground/bindings/modules/mysql/connection_host.h"
#include "playground/bindings/modules/mysql/query_result.h"
#include "playground/bindings/promise.h"
#include "playground/bindings/utilities.h"

namespace bindings {

namespace {

// Converts the |data| (of |length|) to a v8 type appropriate for the |type|.
v8::Local<v8::Value> toValue(char* data, unsigned long length, enum_field_types type) {
  v8::Isolate* isolate = v8::Isolate::GetCurrent();

  switch (type) {
  case MYSQL_TYPE_TINY:
  case MYSQL_TYPE_SHORT:
  case MYSQL_TYPE_LONG:
  case MYSQL_TYPE_LONGLONG:
  case MYSQL_TYPE_INT24:
  case MYSQL_TYPE_BIT:
    return v8Number(atoll(data));

  case MYSQL_TYPE_DECIMAL:
  case MYSQL_TYPE_FLOAT:
  case MYSQL_TYPE_DOUBLE:
    return v8Number(atof(data));

  case MYSQL_TYPE_NULL:
    return v8::Null(isolate);

  default:
    return v8String(data, length);
  }

  // We should never hit this case.
  return v8::Undefined(isolate);
}

// The MySQL class encapsulates a single connection to a MySQL server with a given set of
// information. The connection may be used for any number of queries, and will continue to try
// to auto-reconnect when issues with the connection are identified.
class MySQL : public mysql::ConnectionDelegate,
              public FrameObserver {
 public:
  MySQL(const std::string& hostname, const std::string& username, const std::string& password, const std::string& database, int port)
      : frame_observer_(this),
        hostname_(hostname),
        username_(username),
        password_(password),
        database_(database),
        port_(port) {
    // Initialize the |ready| promise, which will be informed of the connection result.
    ready_.reset(new Promise());

    // Begin establishing the connection through the mysql::ConnectionHost.
    connection_.reset(new mysql::ConnectionHost(this));
    connection_->Connect(hostname, username, password, database, port);

    LOG(INFO) << "Connecting to " << hostname << ":" << std::to_string(port) << "...";
  }

  ~MySQL() override { close(); }

  // mysql::ConnectionDelegate implementation.
  void DidConnect(unsigned int request_id,
                  bool succeeded,
                  int error_number,
                  const std::string& error_message) override {
    DCHECK(!ready_->HasSettled());
    LOG(INFO) << "Connection to " << hostname_ << ":" << std::to_string(port_)
              << (succeeded ? " succeeded" : " failed") << ".";

    std::shared_ptr<Runtime> runtime = Runtime::FromIsolate(v8::Isolate::GetCurrent());

    v8::HandleScope handle_scope(runtime->isolate());
    v8::Context::Scope context_scope(runtime->context());

    // If the connection attempt succeeded, resolve the promise immediately.
    if (succeeded) {
      ready_->Resolve(true /* this should be NULL */);
      connected_ = true;
      return;
    }

    // Otherwise it failed. Output the reason to the console, and create an error object with
    // which we can reject the Promise, so that the JavaScript code knows as well.
    LOG(ERROR) << "MySQL (#" << error_number << "): " << error_message;

    v8::Local<v8::Object> error = v8::Object::New(runtime->isolate());
    error->Set(v8String("error"), v8::Integer::New(runtime->isolate(), error_number));
    error->Set(v8String("message"), v8::String::NewFromUtf8(runtime->isolate(), error_message.c_str()));

    ready_->Reject(error);

    // Close the connection. We require the first connection attempt to succeed.
    connection_->Close();
  }

  void DidQuery(unsigned int request_id, std::shared_ptr<mysql::QueryResult> result) override {
    if (!queries_.count(request_id)) {
      LOG(ERROR) << "Received an unexpected response for request " << request_id;
      return;
    }

    v8::Isolate* isolate = v8::Isolate::GetCurrent();

    std::shared_ptr<Runtime> runtime = Runtime::FromIsolate(isolate);
    {
      v8::HandleScope handle_scope(isolate);
      v8::Context::Scope context_scope(runtime->context());

      v8::Local<v8::Value> affected_rows, insert_id;
      if (result->has_affected_rows())
        affected_rows = v8Number(result->affected_rows());
      else
        affected_rows = v8Null();

      if (result->has_insert_id())
        insert_id = v8Number(result->insert_id());
      else
        insert_id = v8Null();

      v8::Local<v8::Array> rows = v8::Array::New(isolate);
      if (result->has_result()) {
        MYSQL_RES* mysql_result = result->result();

        unsigned int column_count = mysql_num_fields(mysql_result);
        my_ulonglong row_count = mysql_num_rows(mysql_result);

        MYSQL_FIELD* columns = mysql_fetch_fields(mysql_result);
        unsigned long* column_lenghts = mysql_fetch_lengths(mysql_result);

        std::vector<v8::Local<v8::String>> column_names(column_count);
        for (size_t i = 0; i < column_count; ++i)
          column_names[i] = v8String(columns[i].name);

        int current_row_index = 0;
        while (auto row = mysql_fetch_row(mysql_result)) {
          v8::Local<v8::Object> js_row = v8::Object::New(isolate);
          for (size_t i = 0; i < column_count; ++i)
            js_row->Set(column_names[i], toValue(row[i], column_lenghts[i], columns[i].type));

          rows->Set(current_row_index++, js_row);
        }
      }

      v8::Local<v8::Object> js_result = v8::Object::New(isolate);
      js_result->Set(v8String("affectedRows"), affected_rows);
      js_result->Set(v8String("insertId"), insert_id);
      js_result->Set(v8String("rows"), rows);

      queries_[request_id]->Resolve(js_result);
    }

    queries_.erase(request_id);
  }

  void DidQueryFail(unsigned int request_id, int error_number, const std::string& error_message) override {
    if (!queries_.count(request_id)) {
      LOG(ERROR) << "Received an unexpected response for request " << request_id;
      return;
    }

    std::shared_ptr<Runtime> runtime = Runtime::FromIsolate(v8::Isolate::GetCurrent());
    {
      v8::HandleScope handle_scope(runtime->isolate());
      v8::Context::Scope context_scope(runtime->context());

      std::string message = "MySQL error (" + std::to_string(error_number) + "): " + error_message;

      v8::Local<v8::Value> error = v8::Exception::Error(v8String(message));

      // TODO: Figure out some way to carry the stack trace past promise rejections.
      queries_[request_id]->Reject(error);
    }

    queries_.erase(request_id);
  }

  // bindings::FrameObserver implementation.
  void OnFrame() override {
    connection_->ProcessUpdates();
  }

  // Executes |query| on this connection. The returned promise will be resolved when the result
  // is known, or rejected when there was a problem when executing the query.
  v8::Local<v8::Promise> query(const std::string& query) {
    ++total_query_count_;

    unsigned int request_id = connection_->Query(query);

    std::shared_ptr<Promise> promise = std::make_shared<Promise>();
    queries_[request_id] = promise;

    return promise->GetPromise();
  }

  // Immediately closes the connection with the MySQL database.
  void close() {
    LOG(INFO) << "Closing the connection to " << hostname_ << ":" << std::to_string(port_) << "...";
    connection_->Close();
  }

  // A promise that will be settled when it's known whether the connection could be established
  // with the database. This will always return the same promise.
  v8::Local<v8::Promise> ready() const { return ready_->GetPromise(); }

  // Returns whether this MySQL instance has successfully connected to a database.
  bool connected() const { return connected_; }

  // Number of queries that have been executed, regardless of whether they succeeded.
  int total_query_count() const { return total_query_count_; }

  // Number of queries which are still in-progress, and no result is known of.
  int unresolved_query_count() const { return queries_.size(); }

  // Returns the information with which the MySQL connection was established.
  v8::Local<v8::String> hostname() const { return v8String(hostname_); }
  v8::Local<v8::String> username() const { return v8String(username_); }
  v8::Local<v8::String> password() const { return v8String(password_); }
  v8::Local<v8::String> database() const { return v8String(database_); }
  int port() const { return port_; }

  // Installs a weak reference to |object|, which is the JavaScript object that owns this instance.
  // A callback will be used to determine when it has been collected, so we can free up resources.
  void WeakBind(v8::Isolate* isolate, v8::Local<v8::Object> object) {
    object_.Reset(isolate, object);
    object_.SetWeak(this, OnGarbageCollected);
  }

 private:
  // Called when a MySQL instance has been garbage collected by the v8 engine. While this mechanism
  // for keeping track of collections is not guaranteed to work, it works now and it solves the
  // lifetime issues we were otherwise facing.
  static void OnGarbageCollected(const v8::WeakCallbackData<v8::Object, MySQL>& data) {
    MySQL* instance = data.GetParameter();

    instance->object_.Reset();
    delete instance;
  }

  ScopedFrameObserver frame_observer_;

  std::string hostname_;
  std::string username_;
  std::string password_;
  std::string database_;
  int port_;

  std::unique_ptr<mysql::ConnectionHost> connection_;
  std::unordered_map<unsigned int, std::shared_ptr<Promise>> queries_;

  std::unique_ptr<Promise> ready_;

  bool connected_ = false;

  int total_query_count_ = 0;

  v8::Persistent<v8::Object> object_;

  DISALLOW_COPY_AND_ASSIGN(MySQL);
};

// -------------------------------------------------------------------------------------------------

MySQL* GetInstanceFromObject(v8::Local<v8::Object> object) {
  if (object.IsEmpty() || object->InternalFieldCount() != 1) {
    ThrowException("Expected a MySQL instance to be the |this| of the call.");
    return nullptr;
  }

  return static_cast<MySQL*>(object->GetAlignedPointerFromInternalField(0));
}

// MySQL.prototype.constructor(string hostname, string username, string password, int port)
void MySQLConstructorCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  if (!arguments.IsConstructCall()) {
    ThrowException("unable to construct MySQL: must only be used as a constructor.");
    return;
  }

  if (arguments.Length() < 5) {
    ThrowException("unable to construct MySQL: 5 argument required, but only " +
                   std::to_string(arguments.Length()) + " provided.");
    return;
  }

  if (!arguments[4]->IsNumber()) {
    ThrowException("unable to construct MySQL: expected an integer for the fifth argument.");
    return;
  }

  v8::Isolate* isolate = v8::Isolate::GetCurrent();

  v8::MaybeLocal<v8::Number> maybe_port = arguments[4]->ToNumber(isolate->GetCallingContext());
  if (maybe_port.IsEmpty())
    return;  // ???

  v8::Local<v8::Number> port = maybe_port.ToLocalChecked();

  MySQL* instance = new MySQL(toString(arguments[0]),  // hostname
                              toString(arguments[1]),  // username
                              toString(arguments[2]),  // password
                              toString(arguments[3]),  // database
                              port->Int32Value());   // port

  instance->WeakBind(isolate, arguments.Holder());

  arguments.Holder()->SetAlignedPointerInInternalField(0, instance);
}

// Promise<sequence<object>> MySQL.prototype.query(string query);
void MySQLQueryCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  MySQL* instance = GetInstanceFromObject(arguments.Holder());
  if (!instance)
    return;

  if (arguments.Length() == 0) {
    ThrowException("unable to execute MySQL.query(): 1 argument required, but only 0 provided.");
    return;
  }

  arguments.GetReturnValue().Set(instance->query(toString(arguments[0])));
}

// void MySQL.prototype.close();
void MySQLCloseCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  MySQL* instance = GetInstanceFromObject(arguments.Holder());
  if (!instance)
    return;

  instance->close();
}

// -------------------------------------------------------------------------------------------------

#define DEFINE_MAPPING(Name, Member) \
  void Name(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Value>& info) { \
    MySQL* instance = GetInstanceFromObject(info.This()); \
    if (!instance) return; \
    info.GetReturnValue().Set(instance->Member()); \
  }

DEFINE_MAPPING(MySQLReadyGetter, ready);

DEFINE_MAPPING(MySQLConnectedGetter, connected);

DEFINE_MAPPING(MySQLTotalQueryCountGetter, total_query_count);
DEFINE_MAPPING(MySQLUnresolvedQueryCountGetter, unresolved_query_count);

DEFINE_MAPPING(MySQLHostnameGetter, hostname);
DEFINE_MAPPING(MySQLUsernameGetter, username);
DEFINE_MAPPING(MySQLPasswordGetter, password);
DEFINE_MAPPING(MySQLDatabaseGetter, database);
DEFINE_MAPPING(MySQLPortGetter, port);

#undef DEFINE_MAPPING

// -------------------------------------------------------------------------------------------------

}  // namespace

MySQLModule::MySQLModule() {}

MySQLModule::~MySQLModule() {}

void MySQLModule::InstallPrototypes(v8::Local<v8::ObjectTemplate> global) {
  v8::Isolate* isolate = v8::Isolate::GetCurrent();

  v8::Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New(isolate, MySQLConstructorCallback);

  v8::Local<v8::ObjectTemplate> instance_template = function_template->InstanceTemplate();
  instance_template->SetInternalFieldCount(1 /** for the native instance **/);

  v8::Local<v8::ObjectTemplate> prototype_template = function_template->PrototypeTemplate();
  prototype_template->Set(v8String("query"), v8::FunctionTemplate::New(isolate, MySQLQueryCallback));
  prototype_template->Set(v8String("close"), v8::FunctionTemplate::New(isolate, MySQLCloseCallback));

  prototype_template->SetAccessor(v8String("ready"), MySQLReadyGetter);

  prototype_template->SetAccessor(v8String("connected"), MySQLConnectedGetter);
  prototype_template->SetAccessor(v8String("totalQueryCount"), MySQLTotalQueryCountGetter);
  prototype_template->SetAccessor(v8String("unresolvedQueryCount"), MySQLUnresolvedQueryCountGetter);

  prototype_template->SetAccessor(v8String("hostname"), MySQLHostnameGetter);
  prototype_template->SetAccessor(v8String("username"), MySQLUsernameGetter);
  prototype_template->SetAccessor(v8String("password"), MySQLPasswordGetter);
  prototype_template->SetAccessor(v8String("database"), MySQLDatabaseGetter);
  prototype_template->SetAccessor(v8String("port"), MySQLPortGetter);

  global->Set(v8String("MySQL"), function_template);
}

}  // namespace bindings
<commit_msg>Fix a crash in the MySQL module<commit_after>// Copyright 2015 Las Venturas Playground. All rights reserved.
// Use of this source code is governed by the MIT license, a copy of which can
// be found in the LICENSE file.

#include "playground/bindings/modules/mysql_module.h"

#include <memory>
#include <string>
#include <unordered_map>

#include <my_global.h>
#include <my_sys.h>
#include <mysql.h>

#include "base/logging.h"
#include "base/macros.h"
#include "playground/bindings/frame_observer.h"
#include "playground/bindings/modules/mysql/connection_delegate.h"
#include "playground/bindings/modules/mysql/connection_host.h"
#include "playground/bindings/modules/mysql/query_result.h"
#include "playground/bindings/promise.h"
#include "playground/bindings/utilities.h"

namespace bindings {

namespace {

// Converts the |data| (of |length|) to a v8 type appropriate for the |type|.
v8::Local<v8::Value> toValue(char* data, unsigned long length, enum_field_types type) {
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
  if (!data)
    return v8::Null(isolate);

  switch (type) {
  case MYSQL_TYPE_TINY:
  case MYSQL_TYPE_SHORT:
  case MYSQL_TYPE_LONG:
  case MYSQL_TYPE_LONGLONG:
  case MYSQL_TYPE_INT24:
  case MYSQL_TYPE_BIT:
    return v8Number(atoll(data));

  case MYSQL_TYPE_DECIMAL:
  case MYSQL_TYPE_FLOAT:
  case MYSQL_TYPE_DOUBLE:
    return v8Number(atof(data));

  case MYSQL_TYPE_NULL:
    return v8::Null(isolate);

  default:
    return v8String(data);
  }

  // We should never hit this case.
  return v8::Undefined(isolate);
}

// The MySQL class encapsulates a single connection to a MySQL server with a given set of
// information. The connection may be used for any number of queries, and will continue to try
// to auto-reconnect when issues with the connection are identified.
class MySQL : public mysql::ConnectionDelegate,
              public FrameObserver {
 public:
  MySQL(const std::string& hostname, const std::string& username, const std::string& password, const std::string& database, int port)
      : frame_observer_(this),
        hostname_(hostname),
        username_(username),
        password_(password),
        database_(database),
        port_(port) {
    // Initialize the |ready| promise, which will be informed of the connection result.
    ready_.reset(new Promise());

    // Begin establishing the connection through the mysql::ConnectionHost.
    connection_.reset(new mysql::ConnectionHost(this));
    connection_->Connect(hostname, username, password, database, port);

    LOG(INFO) << "Connecting to " << hostname << ":" << std::to_string(port) << "...";
  }

  ~MySQL() override { close(); }

  // mysql::ConnectionDelegate implementation.
  void DidConnect(unsigned int request_id,
                  bool succeeded,
                  int error_number,
                  const std::string& error_message) override {
    DCHECK(!ready_->HasSettled());
    LOG(INFO) << "Connection to " << hostname_ << ":" << std::to_string(port_)
              << (succeeded ? " succeeded" : " failed") << ".";

    std::shared_ptr<Runtime> runtime = Runtime::FromIsolate(v8::Isolate::GetCurrent());

    v8::HandleScope handle_scope(runtime->isolate());
    v8::Context::Scope context_scope(runtime->context());

    // If the connection attempt succeeded, resolve the promise immediately.
    if (succeeded) {
      ready_->Resolve(true /* this should be NULL */);
      connected_ = true;
      return;
    }

    // Otherwise it failed. Output the reason to the console, and create an error object with
    // which we can reject the Promise, so that the JavaScript code knows as well.
    LOG(ERROR) << "MySQL (#" << error_number << "): " << error_message;

    v8::Local<v8::Object> error = v8::Object::New(runtime->isolate());
    error->Set(v8String("error"), v8::Integer::New(runtime->isolate(), error_number));
    error->Set(v8String("message"), v8::String::NewFromUtf8(runtime->isolate(), error_message.c_str()));

    ready_->Reject(error);

    // Close the connection. We require the first connection attempt to succeed.
    connection_->Close();
  }

  void DidQuery(unsigned int request_id, std::shared_ptr<mysql::QueryResult> result) override {
    if (!queries_.count(request_id)) {
      LOG(ERROR) << "Received an unexpected response for request " << request_id;
      return;
    }

    v8::Isolate* isolate = v8::Isolate::GetCurrent();

    std::shared_ptr<Runtime> runtime = Runtime::FromIsolate(isolate);
    {
      v8::HandleScope handle_scope(isolate);
      v8::Context::Scope context_scope(runtime->context());

      v8::Local<v8::Value> affected_rows, insert_id;
      if (result->has_affected_rows())
        affected_rows = v8Number(result->affected_rows());
      else
        affected_rows = v8Null();

      if (result->has_insert_id())
        insert_id = v8Number(result->insert_id());
      else
        insert_id = v8Null();

      v8::Local<v8::Array> rows = v8::Array::New(isolate);
      if (result->has_result()) {
        MYSQL_RES* mysql_result = result->result();

        unsigned int column_count = mysql_num_fields(mysql_result);
        my_ulonglong row_count = mysql_num_rows(mysql_result);

        MYSQL_FIELD* columns = mysql_fetch_fields(mysql_result);
        unsigned long* column_lenghts = mysql_fetch_lengths(mysql_result);

        std::vector<v8::Local<v8::String>> column_names(column_count);
        for (size_t i = 0; i < column_count; ++i)
          column_names[i] = v8String(columns[i].name);

        int current_row_index = 0;
        while (auto row = mysql_fetch_row(mysql_result)) {
          v8::Local<v8::Object> js_row = v8::Object::New(isolate);
          for (size_t i = 0; i < column_count; ++i)
            js_row->Set(column_names[i], toValue(row[i], column_lenghts[i], columns[i].type));

          rows->Set(current_row_index++, js_row);
        }
      }

      v8::Local<v8::Object> js_result = v8::Object::New(isolate);
      js_result->Set(v8String("affectedRows"), affected_rows);
      js_result->Set(v8String("insertId"), insert_id);
      js_result->Set(v8String("rows"), rows);

      queries_[request_id]->Resolve(js_result);
    }

    queries_.erase(request_id);
  }

  void DidQueryFail(unsigned int request_id, int error_number, const std::string& error_message) override {
    if (!queries_.count(request_id)) {
      LOG(ERROR) << "Received an unexpected response for request " << request_id;
      return;
    }

    std::shared_ptr<Runtime> runtime = Runtime::FromIsolate(v8::Isolate::GetCurrent());
    {
      v8::HandleScope handle_scope(runtime->isolate());
      v8::Context::Scope context_scope(runtime->context());

      std::string message = "MySQL error (" + std::to_string(error_number) + "): " + error_message;

      v8::Local<v8::Value> error = v8::Exception::Error(v8String(message));

      // TODO: Figure out some way to carry the stack trace past promise rejections.
      queries_[request_id]->Reject(error);
    }

    queries_.erase(request_id);
  }

  // bindings::FrameObserver implementation.
  void OnFrame() override {
    connection_->ProcessUpdates();
  }

  // Executes |query| on this connection. The returned promise will be resolved when the result
  // is known, or rejected when there was a problem when executing the query.
  v8::Local<v8::Promise> query(const std::string& query) {
    ++total_query_count_;

    unsigned int request_id = connection_->Query(query);

    std::shared_ptr<Promise> promise = std::make_shared<Promise>();
    queries_[request_id] = promise;

    return promise->GetPromise();
  }

  // Immediately closes the connection with the MySQL database.
  void close() {
    LOG(INFO) << "Closing the connection to " << hostname_ << ":" << std::to_string(port_) << "...";
    connection_->Close();
  }

  // A promise that will be settled when it's known whether the connection could be established
  // with the database. This will always return the same promise.
  v8::Local<v8::Promise> ready() const { return ready_->GetPromise(); }

  // Returns whether this MySQL instance has successfully connected to a database.
  bool connected() const { return connected_; }

  // Number of queries that have been executed, regardless of whether they succeeded.
  int total_query_count() const { return total_query_count_; }

  // Number of queries which are still in-progress, and no result is known of.
  int unresolved_query_count() const { return queries_.size(); }

  // Returns the information with which the MySQL connection was established.
  v8::Local<v8::String> hostname() const { return v8String(hostname_); }
  v8::Local<v8::String> username() const { return v8String(username_); }
  v8::Local<v8::String> password() const { return v8String(password_); }
  v8::Local<v8::String> database() const { return v8String(database_); }
  int port() const { return port_; }

  // Installs a weak reference to |object|, which is the JavaScript object that owns this instance.
  // A callback will be used to determine when it has been collected, so we can free up resources.
  void WeakBind(v8::Isolate* isolate, v8::Local<v8::Object> object) {
    object_.Reset(isolate, object);
    object_.SetWeak(this, OnGarbageCollected);
  }

 private:
  // Called when a MySQL instance has been garbage collected by the v8 engine. While this mechanism
  // for keeping track of collections is not guaranteed to work, it works now and it solves the
  // lifetime issues we were otherwise facing.
  static void OnGarbageCollected(const v8::WeakCallbackData<v8::Object, MySQL>& data) {
    MySQL* instance = data.GetParameter();

    instance->object_.Reset();
    delete instance;
  }

  ScopedFrameObserver frame_observer_;

  std::string hostname_;
  std::string username_;
  std::string password_;
  std::string database_;
  int port_;

  std::unique_ptr<mysql::ConnectionHost> connection_;
  std::unordered_map<unsigned int, std::shared_ptr<Promise>> queries_;

  std::unique_ptr<Promise> ready_;

  bool connected_ = false;

  int total_query_count_ = 0;

  v8::Persistent<v8::Object> object_;

  DISALLOW_COPY_AND_ASSIGN(MySQL);
};

// -------------------------------------------------------------------------------------------------

MySQL* GetInstanceFromObject(v8::Local<v8::Object> object) {
  if (object.IsEmpty() || object->InternalFieldCount() != 1) {
    ThrowException("Expected a MySQL instance to be the |this| of the call.");
    return nullptr;
  }

  return static_cast<MySQL*>(object->GetAlignedPointerFromInternalField(0));
}

// MySQL.prototype.constructor(string hostname, string username, string password, int port)
void MySQLConstructorCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  if (!arguments.IsConstructCall()) {
    ThrowException("unable to construct MySQL: must only be used as a constructor.");
    return;
  }

  if (arguments.Length() < 5) {
    ThrowException("unable to construct MySQL: 5 argument required, but only " +
                   std::to_string(arguments.Length()) + " provided.");
    return;
  }

  if (!arguments[4]->IsNumber()) {
    ThrowException("unable to construct MySQL: expected an integer for the fifth argument.");
    return;
  }

  v8::Isolate* isolate = v8::Isolate::GetCurrent();

  v8::MaybeLocal<v8::Number> maybe_port = arguments[4]->ToNumber(isolate->GetCallingContext());
  if (maybe_port.IsEmpty())
    return;  // ???

  v8::Local<v8::Number> port = maybe_port.ToLocalChecked();

  MySQL* instance = new MySQL(toString(arguments[0]),  // hostname
                              toString(arguments[1]),  // username
                              toString(arguments[2]),  // password
                              toString(arguments[3]),  // database
                              port->Int32Value());   // port

  instance->WeakBind(isolate, arguments.Holder());

  arguments.Holder()->SetAlignedPointerInInternalField(0, instance);
}

// Promise<sequence<object>> MySQL.prototype.query(string query);
void MySQLQueryCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  MySQL* instance = GetInstanceFromObject(arguments.Holder());
  if (!instance)
    return;

  if (arguments.Length() == 0) {
    ThrowException("unable to execute MySQL.query(): 1 argument required, but only 0 provided.");
    return;
  }

  arguments.GetReturnValue().Set(instance->query(toString(arguments[0])));
}

// void MySQL.prototype.close();
void MySQLCloseCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) {
  MySQL* instance = GetInstanceFromObject(arguments.Holder());
  if (!instance)
    return;

  instance->close();
}

// -------------------------------------------------------------------------------------------------

#define DEFINE_MAPPING(Name, Member) \
  void Name(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Value>& info) { \
    MySQL* instance = GetInstanceFromObject(info.This()); \
    if (!instance) return; \
    info.GetReturnValue().Set(instance->Member()); \
  }

DEFINE_MAPPING(MySQLReadyGetter, ready);

DEFINE_MAPPING(MySQLConnectedGetter, connected);

DEFINE_MAPPING(MySQLTotalQueryCountGetter, total_query_count);
DEFINE_MAPPING(MySQLUnresolvedQueryCountGetter, unresolved_query_count);

DEFINE_MAPPING(MySQLHostnameGetter, hostname);
DEFINE_MAPPING(MySQLUsernameGetter, username);
DEFINE_MAPPING(MySQLPasswordGetter, password);
DEFINE_MAPPING(MySQLDatabaseGetter, database);
DEFINE_MAPPING(MySQLPortGetter, port);

#undef DEFINE_MAPPING

// -------------------------------------------------------------------------------------------------

}  // namespace

MySQLModule::MySQLModule() {}

MySQLModule::~MySQLModule() {}

void MySQLModule::InstallPrototypes(v8::Local<v8::ObjectTemplate> global) {
  v8::Isolate* isolate = v8::Isolate::GetCurrent();

  v8::Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New(isolate, MySQLConstructorCallback);

  v8::Local<v8::ObjectTemplate> instance_template = function_template->InstanceTemplate();
  instance_template->SetInternalFieldCount(1 /** for the native instance **/);

  v8::Local<v8::ObjectTemplate> prototype_template = function_template->PrototypeTemplate();
  prototype_template->Set(v8String("query"), v8::FunctionTemplate::New(isolate, MySQLQueryCallback));
  prototype_template->Set(v8String("close"), v8::FunctionTemplate::New(isolate, MySQLCloseCallback));

  prototype_template->SetAccessor(v8String("ready"), MySQLReadyGetter);

  prototype_template->SetAccessor(v8String("connected"), MySQLConnectedGetter);
  prototype_template->SetAccessor(v8String("totalQueryCount"), MySQLTotalQueryCountGetter);
  prototype_template->SetAccessor(v8String("unresolvedQueryCount"), MySQLUnresolvedQueryCountGetter);

  prototype_template->SetAccessor(v8String("hostname"), MySQLHostnameGetter);
  prototype_template->SetAccessor(v8String("username"), MySQLUsernameGetter);
  prototype_template->SetAccessor(v8String("password"), MySQLPasswordGetter);
  prototype_template->SetAccessor(v8String("database"), MySQLDatabaseGetter);
  prototype_template->SetAccessor(v8String("port"), MySQLPortGetter);

  global->Set(v8String("MySQL"), function_template);
}

}  // namespace bindings
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "../coreplugin.h"

#include "basefilefilter.h"
#include "locatorfiltertest.h"

#include <coreplugin/testdatadir.h>
#include <utils/fileutils.h>

#include <QDir>
#include <QTextStream>
#include <QtTest>

using namespace Core::Tests;

namespace {

QTC_DECLARE_MYTESTDATADIR("../../../../tests/locators/")

class MyBaseFileFilter : public Core::BaseFileFilter
{
public:
    MyBaseFileFilter(const QStringList &theFiles)
    {
        files().clear();
        files().append(theFiles);
        BaseFileFilter::generateFileNames();
    }

    void refresh(QFutureInterface<void> &) {}

protected:
    void updateFiles() {}
};

inline QString _(const QByteArray &ba) { return QString::fromLatin1(ba, ba.size()); }

class ReferenceData
{
public:
    ReferenceData() {}
    ReferenceData(const QString &searchText, const ResultDataList &results)
        : searchText(searchText), results(results) {}

    QString searchText;
    ResultDataList results;
};

} // anonymous namespace

Q_DECLARE_METATYPE(ReferenceData)
Q_DECLARE_METATYPE(QList<ReferenceData>)

void Core::Internal::CorePlugin::test_basefilefilter()
{
    QFETCH(QStringList, testFiles);
    QFETCH(QList<ReferenceData>, referenceDataList);

    MyBaseFileFilter filter(testFiles);
    BasicLocatorFilterTest test(&filter);

    foreach (const ReferenceData &reference, referenceDataList) {
        const QList<LocatorFilterEntry> filterEntries = test.matchesFor(reference.searchText);
        const ResultDataList results = ResultData::fromFilterEntryList(filterEntries);
//        QTextStream(stdout) << "----" << endl;
//        ResultData::printFilterEntries(results);
        QCOMPARE(results, reference.results);
    }
}

void Core::Internal::CorePlugin::test_basefilefilter_data()
{
    QTest::addColumn<QStringList>("testFiles");
    QTest::addColumn<QList<ReferenceData> >("referenceDataList");

    const QChar pathSeparator = QDir::separator();
    const MyTestDataDir testDir(QLatin1String("testdata_basic"));
    const QStringList testFiles = QStringList()
        << QDir::toNativeSeparators(testDir.file(QLatin1String("file.cpp")))
        << QDir::toNativeSeparators(testDir.file(QLatin1String("main.cpp")))
        << QDir::toNativeSeparators(testDir.file(QLatin1String("subdir/main.cpp")));
    QStringList testFilesShort;
    foreach (const QString &file, testFiles)
        testFilesShort << Utils::FileUtils::shortNativePath(Utils::FileName::fromString(file));

    QTest::newRow("BaseFileFilter-EmptyInput")
        << testFiles
        << (QList<ReferenceData>()
            << ReferenceData(
                QString(),
                (QList<ResultData>()
                    << ResultData(_("file.cpp"), testFilesShort.at(0))
                    << ResultData(_("main.cpp"), testFilesShort.at(1))
                    << ResultData(_("main.cpp"), testFilesShort.at(2))))
            );

    QTest::newRow("BaseFileFilter-InputIsFileName")
        << testFiles
        << (QList<ReferenceData>()
            << ReferenceData(
                _("main.cpp"),
                (QList<ResultData>()
                    << ResultData(_("main.cpp"), testFilesShort.at(1))
                    << ResultData(_("main.cpp"), testFilesShort.at(2))))
           );

    QTest::newRow("BaseFileFilter-InputIsFilePath")
        << testFiles
        << (QList<ReferenceData>()
            << ReferenceData(
                QString(_("subdir") + pathSeparator + _("main.cpp")),
                (QList<ResultData>()
                     << ResultData(_("main.cpp"), testFilesShort.at(2))))
            );

    QTest::newRow("BaseFileFilter-InputIsDirIsPath")
        << testFiles
        << (QList<ReferenceData>()
            << ReferenceData( _("subdir"), QList<ResultData>())
            << ReferenceData(
                QString(_("subdir") + pathSeparator + _("main.cpp")),
                (QList<ResultData>()
                     << ResultData(_("main.cpp"), testFilesShort.at(2))))
            );

    QTest::newRow("BaseFileFilter-InputIsFileNameFilePathFileName")
        << testFiles
        << (QList<ReferenceData>()
            << ReferenceData(
                _("main.cpp"),
                (QList<ResultData>()
                    << ResultData(_("main.cpp"), testFilesShort.at(1))
                    << ResultData(_("main.cpp"), testFilesShort.at(2))))
            << ReferenceData(
                QString(_("subdir") + pathSeparator + _("main.cpp")),
                (QList<ResultData>()
                     << ResultData(_("main.cpp"), testFilesShort.at(2))))
            << ReferenceData(
                _("main.cpp"),
                (QList<ResultData>()
                    << ResultData(_("main.cpp"), testFilesShort.at(1))
                    << ResultData(_("main.cpp"), testFilesShort.at(2))))
            );
}
<commit_msg>Core: Fix locator file filter test.<commit_after>/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "../coreplugin.h"

#include "basefilefilter.h"
#include "locatorfiltertest.h"

#include <coreplugin/testdatadir.h>
#include <utils/fileutils.h>

#include <QDir>
#include <QTextStream>
#include <QtTest>

using namespace Core::Tests;

namespace {

QTC_DECLARE_MYTESTDATADIR("../../../../tests/locators/")

class MyBaseFileFilter : public Core::BaseFileFilter
{
public:
    MyBaseFileFilter(const QStringList &theFiles)
    {
        files().clear();
        files().append(theFiles);
        BaseFileFilter::generateFileNames();
    }

    void refresh(QFutureInterface<void> &) {}

protected:
    void updateFiles() {}
};

inline QString _(const QByteArray &ba) { return QString::fromLatin1(ba, ba.size()); }

class ReferenceData
{
public:
    ReferenceData() {}
    ReferenceData(const QString &searchText, const ResultDataList &results)
        : searchText(searchText), results(results) {}

    QString searchText;
    ResultDataList results;
};

} // anonymous namespace

Q_DECLARE_METATYPE(ReferenceData)
Q_DECLARE_METATYPE(QList<ReferenceData>)

void Core::Internal::CorePlugin::test_basefilefilter()
{
    QFETCH(QStringList, testFiles);
    QFETCH(QList<ReferenceData>, referenceDataList);

    MyBaseFileFilter filter(testFiles);
    BasicLocatorFilterTest test(&filter);

    foreach (const ReferenceData &reference, referenceDataList) {
        const QList<LocatorFilterEntry> filterEntries = test.matchesFor(reference.searchText);
        const ResultDataList results = ResultData::fromFilterEntryList(filterEntries);
//        QTextStream(stdout) << "----" << endl;
//        ResultData::printFilterEntries(results);
        QCOMPARE(results, reference.results);
    }
}

void Core::Internal::CorePlugin::test_basefilefilter_data()
{
    QTest::addColumn<QStringList>("testFiles");
    QTest::addColumn<QList<ReferenceData> >("referenceDataList");

    const QChar pathSeparator = QDir::separator();
    const MyTestDataDir testDir(QLatin1String("testdata_basic"));
    const QStringList testFiles = QStringList()
        << QDir::fromNativeSeparators(testDir.file(QLatin1String("file.cpp")))
        << QDir::fromNativeSeparators(testDir.file(QLatin1String("main.cpp")))
        << QDir::fromNativeSeparators(testDir.file(QLatin1String("subdir/main.cpp")));
    QStringList testFilesShort;
    foreach (const QString &file, testFiles)
        testFilesShort << Utils::FileUtils::shortNativePath(Utils::FileName::fromString(file));

    QTest::newRow("BaseFileFilter-EmptyInput")
        << testFiles
        << (QList<ReferenceData>()
            << ReferenceData(
                QString(),
                (QList<ResultData>()
                    << ResultData(_("file.cpp"), testFilesShort.at(0))
                    << ResultData(_("main.cpp"), testFilesShort.at(1))
                    << ResultData(_("main.cpp"), testFilesShort.at(2))))
            );

    QTest::newRow("BaseFileFilter-InputIsFileName")
        << testFiles
        << (QList<ReferenceData>()
            << ReferenceData(
                _("main.cpp"),
                (QList<ResultData>()
                    << ResultData(_("main.cpp"), testFilesShort.at(1))
                    << ResultData(_("main.cpp"), testFilesShort.at(2))))
           );

    QTest::newRow("BaseFileFilter-InputIsFilePath")
        << testFiles
        << (QList<ReferenceData>()
            << ReferenceData(
                QString(_("subdir") + pathSeparator + _("main.cpp")),
                (QList<ResultData>()
                     << ResultData(_("main.cpp"), testFilesShort.at(2))))
            );

    QTest::newRow("BaseFileFilter-InputIsDirIsPath")
        << testFiles
        << (QList<ReferenceData>()
            << ReferenceData( _("subdir"), QList<ResultData>())
            << ReferenceData(
                QString(_("subdir") + pathSeparator + _("main.cpp")),
                (QList<ResultData>()
                     << ResultData(_("main.cpp"), testFilesShort.at(2))))
            );

    QTest::newRow("BaseFileFilter-InputIsFileNameFilePathFileName")
        << testFiles
        << (QList<ReferenceData>()
            << ReferenceData(
                _("main.cpp"),
                (QList<ResultData>()
                    << ResultData(_("main.cpp"), testFilesShort.at(1))
                    << ResultData(_("main.cpp"), testFilesShort.at(2))))
            << ReferenceData(
                QString(_("subdir") + pathSeparator + _("main.cpp")),
                (QList<ResultData>()
                     << ResultData(_("main.cpp"), testFilesShort.at(2))))
            << ReferenceData(
                _("main.cpp"),
                (QList<ResultData>()
                    << ResultData(_("main.cpp"), testFilesShort.at(1))
                    << ResultData(_("main.cpp"), testFilesShort.at(2))))
            );
}
<|endoftext|>


<commit_before>#include <iostream>
#include "TLegend.h"

#include "PlotHists.h"

ClassImp(PlotHists)

//--------------------------------------------------------------------
PlotHists::PlotHists() :
  fNormalizedHists(false),
  fNormalizeTo(-1),
  fEventsPer(0),
  fPrintTests(false)
{}

//--------------------------------------------------------------------
PlotHists::~PlotHists()
{}

//--------------------------------------------------------------------
std::vector<TH1D*>
PlotHists::MakeHists(Int_t NumXBins, Double_t *XBins)
{
  UInt_t NumPlots = 0;

  if (fNormalizeTo != -1)
    fNormalizedHists = true;

  if (fInTrees.size() != 0)
    NumPlots = fInTrees.size();
  else if (fInCuts.size() != 0)
    NumPlots = fInCuts.size();
  else
    NumPlots = fInExpr.size();

  if(NumPlots == 0){
    std::cout << "Nothing has been initialized in hists plot." << std::endl;
    exit(1);
  }

  TTree *inTree = fDefaultTree;
  TString inCut = fDefaultCut;
  TString inExpr = fDefaultExpr;

  TH1D *tempHist;

  std::vector<TH1D*> theHists;

  for (UInt_t iPlot = 0; iPlot != NumPlots; ++iPlot) {

    if (fInTrees.size() != 0)
      inTree = fInTrees[iPlot];
    if (fInCuts.size()  != 0)
      inCut  = fInCuts[iPlot];
    if (fInExpr.size() != 0)
      inExpr = fInExpr[iPlot];

    TString tempName;
    tempName.Form("Hist_%d",fPlotCounter);
    fPlotCounter++;
    tempHist = new TH1D(tempName,tempName,NumXBins,XBins);
    if (fIncludeErrorBars || int(iPlot) == fDataIndex)
      tempHist->Sumw2();

    inTree->Draw(inExpr+">>"+tempName,inCut);

    theHists.push_back(tempHist);
  }

  if (fEventsPer > 0) {
    TString tempName;
    tempName.Form("Hist_%d",fPlotCounter);
    fPlotCounter++;
    tempHist = new TH1D(tempName,tempName,NumXBins,XBins);
    for (Int_t iBin = 1; iBin != NumXBins + 1; ++iBin) {
      tempHist->SetBinContent(iBin,tempHist->GetBinWidth(iBin)/fEventsPer);
    }
    for (UInt_t iHist = 0; iHist != theHists.size(); ++iHist)
      Division(theHists[iHist],tempHist);
  }

  if (fPrintTests) {
    for (UInt_t iHist = 0; iHist != theHists.size(); ++iHist) {

      if (fDataIndex != -1)
        std::cout << "chi2 test: " << fLegendEntries[iHist] << " " << theHists[fDataIndex]->Chi2Test(theHists[iHist],"UW") << std::endl;

      std::cout << fLegendEntries[iHist] << " -> Mean: " << theHists[iHist]->GetMean() << "+-" << theHists[iHist]->GetMeanError();
      std::cout                          << " RMS: " << theHists[iHist]->GetRMS() << "+-" << theHists[iHist]->GetRMSError() << std::endl;

      for (UInt_t i1 = 0; i1 < NumPlots; i1++) {
        if (i1 == iHist)
          continue;
        std::cout << "Test with " << fLegendEntries[i1] << " KS: " << theHists[iHist]->KolmogorovTest(theHists[i1]);
        std::cout << " AD: " << theHists[iHist]->AndersonDarlingTest(theHists[i1]) << std::endl;
      }
    }
  }

  if (fNormalizedHists) {
    Double_t normInt = 1;
    if (fNormalizeTo != -1)
      normInt = theHists[fNormalizeTo]->Integral("width");

    for (UInt_t iHist = 0; iHist != NumPlots; ++iHist)
      theHists[iHist]->Scale(normInt/theHists[iHist]->Integral("width"));
  }

  return theHists;
}

//--------------------------------------------------------------------
std::vector<TH1D*>
PlotHists::MakeHists(Int_t NumXBins, Double_t MinX, Double_t MaxX)
{
  Double_t XBins[NumXBins+1];
  ConvertToArray(NumXBins,MinX,MaxX,XBins);
  return MakeHists(NumXBins,XBins);
}

//--------------------------------------------------------------------
void
PlotHists::MakeCanvas(TString FileBase, Int_t NumXBins, Double_t *XBins,
                      TString XLabel, TString YLabel, Bool_t logY)
{
  std::vector<TH1D*> hists = MakeHists(NumXBins,XBins);
  BaseCanvas(FileBase,hists,XLabel,YLabel,logY);

  for (UInt_t i0 = 0; i0 != hists.size(); ++i0)
    delete hists[i0];
}

//--------------------------------------------------------------------
void
PlotHists::MakeCanvas(TString FileBase, Int_t NumXBins, Double_t MinX, Double_t MaxX,
                      TString XLabel, TString YLabel, Bool_t logY)
{
  Double_t XBins[NumXBins+1];
  ConvertToArray(NumXBins,MinX,MaxX,XBins);
  MakeCanvas(FileBase,NumXBins,XBins,XLabel,YLabel,logY);
}
<commit_msg>Fixed error handling when scaling for bin width.<commit_after>#include <iostream>
#include "TLegend.h"

#include "PlotHists.h"

ClassImp(PlotHists)

//--------------------------------------------------------------------
PlotHists::PlotHists() :
  fNormalizedHists(false),
  fNormalizeTo(-1),
  fEventsPer(0),
  fPrintTests(false)
{}

//--------------------------------------------------------------------
PlotHists::~PlotHists()
{}

//--------------------------------------------------------------------
std::vector<TH1D*>
PlotHists::MakeHists(Int_t NumXBins, Double_t *XBins)
{
  UInt_t NumPlots = 0;

  if (fNormalizeTo != -1)
    fNormalizedHists = true;

  if (fInTrees.size() != 0)
    NumPlots = fInTrees.size();
  else if (fInCuts.size() != 0)
    NumPlots = fInCuts.size();
  else
    NumPlots = fInExpr.size();

  if(NumPlots == 0){
    std::cout << "Nothing has been initialized in hists plot." << std::endl;
    exit(1);
  }

  TTree *inTree = fDefaultTree;
  TString inCut = fDefaultCut;
  TString inExpr = fDefaultExpr;

  TH1D *tempHist;

  std::vector<TH1D*> theHists;

  for (UInt_t iPlot = 0; iPlot != NumPlots; ++iPlot) {

    if (fInTrees.size() != 0)
      inTree = fInTrees[iPlot];
    if (fInCuts.size()  != 0)
      inCut  = fInCuts[iPlot];
    if (fInExpr.size() != 0)
      inExpr = fInExpr[iPlot];

    TString tempName;
    tempName.Form("Hist_%d",fPlotCounter);
    fPlotCounter++;
    tempHist = new TH1D(tempName,tempName,NumXBins,XBins);
    if (fIncludeErrorBars || int(iPlot) == fDataIndex)
      tempHist->Sumw2();

    inTree->Draw(inExpr+">>"+tempName,inCut);

    theHists.push_back(tempHist);
  }

  if (fEventsPer > 0) {
    TString tempName;
    tempName.Form("Hist_%d",fPlotCounter);
    fPlotCounter++;
    tempHist = new TH1D(tempName,tempName,NumXBins,XBins);
    for (Int_t iBin = 1; iBin != NumXBins + 1; ++iBin)
      tempHist->SetBinContent(iBin,tempHist->GetBinWidth(iBin)/fEventsPer);

    SetZeroError(tempHist);
    for (UInt_t iHist = 0; iHist != theHists.size(); ++iHist)
      Division(theHists[iHist],tempHist);

    delete tempHist;
  }

  if (fPrintTests) {
    for (UInt_t iHist = 0; iHist != theHists.size(); ++iHist) {

      if (fDataIndex != -1)
        std::cout << "chi2 test: " << fLegendEntries[iHist] << " " << theHists[fDataIndex]->Chi2Test(theHists[iHist],"UW") << std::endl;

      std::cout << fLegendEntries[iHist] << " -> Mean: " << theHists[iHist]->GetMean() << "+-" << theHists[iHist]->GetMeanError();
      std::cout                          << " RMS: " << theHists[iHist]->GetRMS() << "+-" << theHists[iHist]->GetRMSError() << std::endl;

      for (UInt_t i1 = 0; i1 < NumPlots; i1++) {
        if (i1 == iHist)
          continue;
        std::cout << "Test with " << fLegendEntries[i1] << " KS: " << theHists[iHist]->KolmogorovTest(theHists[i1]);
        std::cout << " AD: " << theHists[iHist]->AndersonDarlingTest(theHists[i1]) << std::endl;
      }
    }
  }

  if (fNormalizedHists) {
    Double_t normInt = 1;
    if (fNormalizeTo != -1)
      normInt = theHists[fNormalizeTo]->Integral("width");

    for (UInt_t iHist = 0; iHist != NumPlots; ++iHist)
      theHists[iHist]->Scale(normInt/theHists[iHist]->Integral("width"));
  }

  return theHists;
}

//--------------------------------------------------------------------
std::vector<TH1D*>
PlotHists::MakeHists(Int_t NumXBins, Double_t MinX, Double_t MaxX)
{
  Double_t XBins[NumXBins+1];
  ConvertToArray(NumXBins,MinX,MaxX,XBins);
  return MakeHists(NumXBins,XBins);
}

//--------------------------------------------------------------------
void
PlotHists::MakeCanvas(TString FileBase, Int_t NumXBins, Double_t *XBins,
                      TString XLabel, TString YLabel, Bool_t logY)
{
  std::vector<TH1D*> hists = MakeHists(NumXBins,XBins);
  BaseCanvas(FileBase,hists,XLabel,YLabel,logY);

  for (UInt_t i0 = 0; i0 != hists.size(); ++i0)
    delete hists[i0];
}

//--------------------------------------------------------------------
void
PlotHists::MakeCanvas(TString FileBase, Int_t NumXBins, Double_t MinX, Double_t MaxX,
                      TString XLabel, TString YLabel, Bool_t logY)
{
  Double_t XBins[NumXBins+1];
  ConvertToArray(NumXBins,MinX,MaxX,XBins);
  MakeCanvas(FileBase,NumXBins,XBins,XLabel,YLabel,logY);
}
<|endoftext|>


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

// OpenGL ES 2.0 code
#include <stdint.h>
#include <jni.h>
#include <android/bitmap.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <android/log.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <string>
#include <vector>
#include <memory>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

#include "NativeBitmap.h"
#include "Texture.h"
#include "GLES2Lesson.h"
#include "NdkGlue.h"

#include "android_asset_operations.h"

std::string gVertexShader;
std::string gFragmentShader;
odb::GLES2Lesson *gles2Lesson = nullptr;
std::vector<std::shared_ptr<odb::NativeBitmap>> textures;

std::array< std::array<int, 20 >, 20 > snapshot;

void loadShaders(JNIEnv *env, jobject &obj) {
    AAssetManager *asset_manager = AAssetManager_fromJava(env, obj);
    FILE *fd;
    fd = android_fopen("vertex.glsl", "r", asset_manager);
    gVertexShader = readToString(fd);
    fclose(fd);
    fd = android_fopen("fragment.glsl", "r", asset_manager);
    gFragmentShader = readToString(fd);
    fclose(fd);
}

bool setupGraphics(int w, int h) {
    gles2Lesson = new odb::GLES2Lesson();
	gles2Lesson->setTexture(textures);
    return gles2Lesson->init(w, h, gVertexShader.c_str(), gFragmentShader.c_str());
}

void renderFrame(std::array<std::array<int, 20>, 20> array) {
    if (gles2Lesson != nullptr) {
	    gles2Lesson->render(array);
    }
}

void shutdown() {
	odb::GLES2Lesson *local = gles2Lesson;
    gles2Lesson = nullptr;
    local->shutdown();
    delete local;
	textures.clear();
}

void tick() {
    if (gles2Lesson != nullptr) {
        gles2Lesson->tick();
    }
}

extern "C" {
JNIEXPORT void JNICALL Java_br_odb_GL2JNILib_onCreate(JNIEnv *env, void *reserved,
                                                                    jobject assetManager);

JNIEXPORT void JNICALL
		Java_br_odb_GL2JNILib_setCameraPosition(JNIEnv *env, jclass type, jfloat x, jfloat y);

JNIEXPORT void JNICALL
    Java_br_odb_GL2JNILib_setTextures(JNIEnv *env, jclass type, jobjectArray bitmaps);

JNIEXPORT void JNICALL Java_br_odb_GL2JNILib_onDestroy(JNIEnv *env, jobject obj);

JNIEXPORT void JNICALL Java_br_odb_GL2JNILib_init(JNIEnv *env, jobject obj,
                                                                jint width, jint height);
JNIEXPORT void JNICALL Java_br_odb_GL2JNILib_step(JNIEnv *env, jobject obj);

JNIEXPORT void JNICALL Java_br_odb_GL2JNILib_tick(JNIEnv *env, jobject obj);

JNIEXPORT void JNICALL
		Java_br_odb_GL2JNILib_setSnapshot(JNIEnv *env, jclass type, jobjectArray map);
};

JNIEXPORT void JNICALL Java_br_odb_GL2JNILib_onCreate(JNIEnv *env, void *reserved,
                                                                    jobject assetManager) {
    loadShaders(env, assetManager);
}

JNIEXPORT void JNICALL Java_br_odb_GL2JNILib_init(JNIEnv *env, jobject obj,
                                                                jint width, jint height) {
    setupGraphics(width, height);
}

JNIEXPORT void JNICALL Java_br_odb_GL2JNILib_step(JNIEnv *env, jobject obj) {
	renderFrame(snapshot);
}

JNIEXPORT void JNICALL Java_br_odb_GL2JNILib_tick(JNIEnv *env, jobject obj) {
    tick();
}

JNIEXPORT void JNICALL Java_br_odb_GL2JNILib_onDestroy(JNIEnv *env, jobject obj) {
    shutdown();
}

std::shared_ptr<odb::NativeBitmap> makeNativeBitmapFromJObject(JNIEnv *env, jobject bitmap) {

	void *addr;
	AndroidBitmapInfo info;
	int errorCode;

	if ((errorCode = AndroidBitmap_lockPixels(env, bitmap, &addr)) != 0) {
		LOGI("error %d", errorCode);
	}

	if ((errorCode = AndroidBitmap_getInfo(env, bitmap, &info)) != 0) {
		LOGI("error %d", errorCode);
	}

	LOGI("bitmap info: %d wide, %d tall, %d ints per pixel", info.width, info.height, info.format);

	long size = info.width * info.height * info.format;
	int *pixels = new int[size];
	memcpy(pixels, addr, size * sizeof(int));
	auto toReturn = std::make_shared<odb::NativeBitmap>(info.width, info.height, pixels);

	if ((errorCode = AndroidBitmap_unlockPixels(env, bitmap)) != 0) {
		LOGI("error %d", errorCode);
	}

	return toReturn;
}

JNIEXPORT void JNICALL
Java_br_odb_GL2JNILib_setTextures(JNIEnv *env, jclass type, jobjectArray bitmaps) {
	int length = env->GetArrayLength( bitmaps );
	textures.clear();
	for ( int c = 0; c < length; ++c ) {
		textures.push_back( makeNativeBitmapFromJObject( env, env->GetObjectArrayElement( bitmaps, c ) ) );
	}
}

JNIEXPORT void JNICALL
Java_br_odb_GL2JNILib_setSnapshot(JNIEnv *env, jclass type, jobjectArray map) {

	int lengthy = env->GetArrayLength( map );

	for ( int y = 0; y < lengthy; ++y ) {
		jintArray column = (jintArray)( env->GetObjectArrayElement(map, y ) );

		int lengthx = env->GetArrayLength( column );
		jint *elements = env->GetIntArrayElements( column, 0 );
		for ( int x = 0; x < lengthx; ++x, ++elements ) {
				snapshot[ y ][ x ] = *elements;
		}
	}
}

JNIEXPORT void JNICALL
Java_br_odb_GL2JNILib_setCameraPosition(JNIEnv *env, jclass type, jfloat x, jfloat y) {
	if (gles2Lesson != nullptr) {
		gles2Lesson->setCameraPosition( x, y );
	}
}<commit_msg>use the proper types for jni array iteration<commit_after>/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// OpenGL ES 2.0 code
#include <stdint.h>
#include <jni.h>
#include <android/bitmap.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <android/log.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <string>
#include <vector>
#include <memory>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

#include "NativeBitmap.h"
#include "Texture.h"
#include "GLES2Lesson.h"
#include "NdkGlue.h"

#include "android_asset_operations.h"

std::string gVertexShader;
std::string gFragmentShader;
odb::GLES2Lesson *gles2Lesson = nullptr;
std::vector<std::shared_ptr<odb::NativeBitmap>> textures;

std::array< std::array<int, 20 >, 20 > snapshot;

void loadShaders(JNIEnv *env, jobject &obj) {
    AAssetManager *asset_manager = AAssetManager_fromJava(env, obj);
    FILE *fd;
    fd = android_fopen("vertex.glsl", "r", asset_manager);
    gVertexShader = readToString(fd);
    fclose(fd);
    fd = android_fopen("fragment.glsl", "r", asset_manager);
    gFragmentShader = readToString(fd);
    fclose(fd);
}

bool setupGraphics(int w, int h) {
    gles2Lesson = new odb::GLES2Lesson();
	gles2Lesson->setTexture(textures);
    return gles2Lesson->init(w, h, gVertexShader.c_str(), gFragmentShader.c_str());
}

void renderFrame(std::array<std::array<int, 20>, 20> array) {
    if (gles2Lesson != nullptr) {
	    gles2Lesson->render(array);
    }
}

void shutdown() {
	odb::GLES2Lesson *local = gles2Lesson;
    gles2Lesson = nullptr;
    local->shutdown();
    delete local;
	textures.clear();
}

void tick() {
    if (gles2Lesson != nullptr) {
        gles2Lesson->tick();
    }
}

extern "C" {
JNIEXPORT void JNICALL Java_br_odb_GL2JNILib_onCreate(JNIEnv *env, void *reserved,
                                                                    jobject assetManager);

JNIEXPORT void JNICALL
		Java_br_odb_GL2JNILib_setCameraPosition(JNIEnv *env, jclass type, jfloat x, jfloat y);

JNIEXPORT void JNICALL
    Java_br_odb_GL2JNILib_setTextures(JNIEnv *env, jclass type, jobjectArray bitmaps);

JNIEXPORT void JNICALL Java_br_odb_GL2JNILib_onDestroy(JNIEnv *env, jobject obj);

JNIEXPORT void JNICALL Java_br_odb_GL2JNILib_init(JNIEnv *env, jobject obj,
                                                                jint width, jint height);
JNIEXPORT void JNICALL Java_br_odb_GL2JNILib_step(JNIEnv *env, jobject obj);

JNIEXPORT void JNICALL Java_br_odb_GL2JNILib_tick(JNIEnv *env, jobject obj);

JNIEXPORT void JNICALL
		Java_br_odb_GL2JNILib_setSnapshot(JNIEnv *env, jclass type, jobjectArray map);
};

JNIEXPORT void JNICALL Java_br_odb_GL2JNILib_onCreate(JNIEnv *env, void *reserved,
                                                                    jobject assetManager) {
    loadShaders(env, assetManager);
}

JNIEXPORT void JNICALL Java_br_odb_GL2JNILib_init(JNIEnv *env, jobject obj,
                                                                jint width, jint height) {
    setupGraphics(width, height);
}

JNIEXPORT void JNICALL Java_br_odb_GL2JNILib_step(JNIEnv *env, jobject obj) {
	renderFrame(snapshot);
}

JNIEXPORT void JNICALL Java_br_odb_GL2JNILib_tick(JNIEnv *env, jobject obj) {
    tick();
}

JNIEXPORT void JNICALL Java_br_odb_GL2JNILib_onDestroy(JNIEnv *env, jobject obj) {
    shutdown();
}

std::shared_ptr<odb::NativeBitmap> makeNativeBitmapFromJObject(JNIEnv *env, jobject bitmap) {

	void *addr;
	AndroidBitmapInfo info;
	int errorCode;

	if ((errorCode = AndroidBitmap_lockPixels(env, bitmap, &addr)) != 0) {
		LOGI("error %d", errorCode);
	}

	if ((errorCode = AndroidBitmap_getInfo(env, bitmap, &info)) != 0) {
		LOGI("error %d", errorCode);
	}

	LOGI("bitmap info: %d wide, %d tall, %d ints per pixel", info.width, info.height, info.format);

	long size = info.width * info.height * info.format;
	int *pixels = new int[size];
	memcpy(pixels, addr, size * sizeof(int));
	auto toReturn = std::make_shared<odb::NativeBitmap>(info.width, info.height, pixels);

	if ((errorCode = AndroidBitmap_unlockPixels(env, bitmap)) != 0) {
		LOGI("error %d", errorCode);
	}

	return toReturn;
}

JNIEXPORT void JNICALL
Java_br_odb_GL2JNILib_setTextures(JNIEnv *env, jclass type, jobjectArray bitmaps) {
	int length = env->GetArrayLength( bitmaps );
	textures.clear();
	for ( int c = 0; c < length; ++c ) {
		textures.push_back( makeNativeBitmapFromJObject( env, env->GetObjectArrayElement( bitmaps, c ) ) );
	}
}

JNIEXPORT void JNICALL
Java_br_odb_GL2JNILib_setSnapshot(JNIEnv *env, jclass type, jobjectArray map) {

	jsize lengthy = env->GetArrayLength( map );

	for ( jsize y = 0; y < lengthy; ++y ) {
		jintArray column = (jintArray)( env->GetObjectArrayElement(map, y ) );

		jsize lengthx = env->GetArrayLength( column );
		jint *elements = env->GetIntArrayElements( column, 0 );
		for ( jsize x = 0; x < lengthx; ++x, ++elements ) {
				snapshot[ y ][ x ] = *elements;
		}
//		env->ReleaseIntArrayElements( column, elements, JNI_ABORT );
	}
}

JNIEXPORT void JNICALL
Java_br_odb_GL2JNILib_setCameraPosition(JNIEnv *env, jclass type, jfloat x, jfloat y) {
	if (gles2Lesson != nullptr) {
		gles2Lesson->setCameraPosition( x, y );
	}
}<|endoftext|>


<commit_before>// - Tested
#define CRB_CONVOYS
#define RMM_ENEMYPOP
#define CRB_TERRORISTS
#define RMM_ZORA

// - To Test
#define SR5_IEDS<commit_msg>- Disabled SR5 until dedi support<commit_after>// - Tested
#define CRB_CONVOYS
#define RMM_ENEMYPOP
#define CRB_TERRORISTS
#define RMM_ZORA

// - To Test
//#define SR5_IEDS<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: ipbm.cxx,v $
 * $Revision: 1.9 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_goodies.hxx"

#include <vcl/graph.hxx>
#include <vcl/bmpacc.hxx>
#include <svtools/fltcall.hxx>

//============================ PBMReader ==================================

class PBMReader {

private:

    SvStream*           mpPBM;          // Die einzulesende PBM-Datei

    BOOL                mbStatus;
    BOOL                mbRemark;       // FALSE wenn sich stream in einem Kommentar befindet
    BOOL                mbRaw;          // RAW/ASCII MODE
    ULONG               mnMode;         // 0->PBM, 1->PGM, 2->PPM
    Bitmap              maBmp;
    BitmapWriteAccess*  mpAcc;
    ULONG               mnWidth, mnHeight;  // Bildausmass in Pixeln
    ULONG               mnCol;
    ULONG               mnMaxVal;           // maximaler wert in den
    BOOL                ImplCallback( USHORT nPercent );
    BOOL                ImplReadBody();
    BOOL                ImplReadHeader();

public:
                        PBMReader();
                        ~PBMReader();
    BOOL                ReadPBM( SvStream & rPBM, Graphic & rGraphic );
};

//=================== Methoden von PBMReader ==============================

PBMReader::PBMReader() :
    mbStatus    ( TRUE ),
    mbRemark    ( FALSE ),
    mbRaw       ( TRUE ),
    mpAcc       ( NULL )
{
}

PBMReader::~PBMReader()
{
}

BOOL PBMReader::ImplCallback( USHORT /*nPercent*/ )
{
/*
    if ( pCallback != NULL )
    {
        if ( ( (*pCallback)( pCallerData, nPercent ) ) == TRUE )
        {
            mpPBM->SetError( SVSTREAM_FILEFORMAT_ERROR );
            return TRUE;
        }
    }
*/
    return FALSE;
}

BOOL PBMReader::ReadPBM( SvStream & rPBM, Graphic & rGraphic )
{
    USHORT i;

    if ( rPBM.GetError() )
        return FALSE;

    mpPBM = &rPBM;
    mpPBM->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );

    // Kopf einlesen:

    if ( ( mbStatus = ImplReadHeader() ) == FALSE )
        return FALSE;

    if ( ( mnMaxVal == 0 ) || ( mnWidth == 0 ) || ( mnHeight == 0 ) )
        return FALSE;

    // 0->PBM, 1->PGM, 2->PPM
    switch ( mnMode )
    {
        case 0 :
            maBmp = Bitmap( Size( mnWidth, mnHeight ), 1 );
            if ( ( mpAcc = maBmp.AcquireWriteAccess() ) == FALSE )
                return FALSE;
            mpAcc->SetPaletteEntryCount( 2 );
            mpAcc->SetPaletteColor( 0, BitmapColor( 0xff, 0xff, 0xff ) );
            mpAcc->SetPaletteColor( 1, BitmapColor( 0x00, 0x00, 0x00 ) );
            break;

        case 1 :
            if ( mnMaxVal <= 1 )
                maBmp = Bitmap( Size( mnWidth, mnHeight ), 1);
            else if ( mnMaxVal <= 15 )
                maBmp = Bitmap( Size( mnWidth, mnHeight ), 4);
            else
                maBmp = Bitmap( Size( mnWidth, mnHeight ), 8);

            if ( ( mpAcc = maBmp.AcquireWriteAccess() ) == FALSE )
                return FALSE;
            mnCol = (USHORT)mnMaxVal + 1;
            if ( mnCol > 256 )
                mnCol = 256;

            mpAcc->SetPaletteEntryCount( 256 );
            for ( i = 0; i < mnCol; i++ )
            {
                ULONG nCount = 255 * i / mnCol;
                mpAcc->SetPaletteColor( i, BitmapColor( (BYTE)nCount, (BYTE)nCount, (BYTE)nCount ) );
            }
            break;
        case 2 :
            maBmp = Bitmap( Size( mnWidth, mnHeight ), 24 );
            if ( ( mpAcc = maBmp.AcquireWriteAccess() ) == FALSE )
                return FALSE;
            break;
    }

    // Bitmap-Daten einlesen
    mbStatus = ImplReadBody();

    if ( mpAcc )
    {
        maBmp.ReleaseAccess( mpAcc ), mpAcc = NULL;
    }
    if ( mbStatus )
        rGraphic = maBmp;

    return mbStatus;
}

BOOL PBMReader::ImplReadHeader()
{
    BYTE    nID[ 2 ];
    BYTE    nDat;
    BYTE    nMax, nCount = 0;
    BOOL    bFinished = FALSE;

    *mpPBM >> nID[ 0 ] >> nID[ 1 ];
    if ( nID[ 0 ] != 'P' )
        return FALSE;
    switch ( nID[ 1 ] )
    {
        case '1' :
            mbRaw = FALSE;
        case '4' :
            mnMode = 0;
            nMax = 2;               // number of parameters in Header
            break;
        case '2' :
            mbRaw = FALSE;
        case '5' :
            mnMode = 1;
            nMax = 3;
            break;
        case '3' :
            mbRaw = FALSE;
        case '6' :
            mnMode = 2;
            nMax = 3;
            break;
        default:
            return FALSE;
    }

    mnMaxVal = mnWidth = mnHeight = 0;

    while ( bFinished == FALSE )
    {
        if ( mpPBM->GetError() )
            return FALSE;

        *mpPBM >> nDat;

        if ( nDat == '#' )
        {
            mbRemark = TRUE;
            continue;
        }
        else if ( ( nDat == 0x0d ) || ( nDat == 0x0a ) )
        {
            mbRemark = FALSE;
            nDat = 0x20;
        }
        if ( mbRemark )
            continue;

        if ( ( nDat == 0x20 ) || ( nDat == 0x09 ) )
        {
            if ( ( nCount == 0 ) && mnWidth )
                nCount++;
            else if ( ( nCount == 1 ) && mnHeight )
            {
                if ( ++nCount == nMax )
                    bFinished = TRUE;
            }
            else if ( ( nCount == 2 ) && mnMaxVal )
            {
                bFinished = TRUE;
            }
            continue;
        }
        if ( ( nDat >= '0' ) && ( nDat <= '9' ) )
        {
            nDat -= '0';
            if ( nCount == 0 )
            {
                mnWidth *= 10;
                mnWidth += nDat;
            }
            else if ( nCount == 1 )
            {
                mnHeight *= 10;
                mnHeight += nDat;
            }
            else if ( nCount == 2 )
            {
                mnMaxVal *= 10;
                mnMaxVal += nDat;
            }
        }
        else
            return FALSE;
    }
    return mbStatus;
}

BOOL PBMReader::ImplReadBody()
{
    BOOL    bPara, bFinished = FALSE;
    BYTE    nDat = 0, nCount;
    ULONG   nGrey, nRGB[3];
    ULONG   nWidth = 0;
    ULONG   nHeight = 0;
    signed char nShift = 0;

    if ( mbRaw )
    {
        switch ( mnMode )
        {

            // PBM
            case 0 :
                while ( nHeight != mnHeight )
                {
                    if ( mpPBM->IsEof() || mpPBM->GetError() )
                        return FALSE;

                    if ( --nShift < 0 )
                    {
                        *mpPBM >> nDat;
                        nShift = 7;
                    }
                    mpAcc->SetPixel( nHeight, nWidth, nDat >> nShift );
                    if ( ++nWidth == mnWidth )
                    {
                        nShift = 0;
                        nWidth = 0;
                        nHeight++;
                        ImplCallback( (USHORT)( ( 100 * nHeight ) / mnHeight ) );   // processing output in percent
                    }
                }
                break;

            // PGM
            case 1 :
                while ( nHeight != mnHeight )
                {
                    if ( mpPBM->IsEof() || mpPBM->GetError() )
                        return FALSE;

                    *mpPBM >> nDat;
                    mpAcc->SetPixel( nHeight, nWidth++, nDat);

                    if ( nWidth == mnWidth )
                    {
                        nWidth = 0;
                        nHeight++;
                        ImplCallback( (USHORT)( ( 100 * nHeight ) / mnHeight ) );   // processing output in percent
                    }
                }
                break;

            // PPM
            case 2 :
                while ( nHeight != mnHeight )
                {
                    if ( mpPBM->IsEof() || mpPBM->GetError() )
                        return FALSE;

                    BYTE    nR, nG, nB;
                    ULONG   nRed, nGreen, nBlue;
                    *mpPBM >> nR >> nG >> nB;
                    nRed = 255 * nR / mnMaxVal;
                    nGreen = 255 * nG / mnMaxVal;
                    nBlue = 255 * nB / mnMaxVal;
                    mpAcc->SetPixel( nHeight, nWidth++, BitmapColor( (BYTE)nRed, (BYTE)nGreen, (BYTE)nBlue ) );
                    if ( nWidth == mnWidth )
                    {
                        nWidth = 0;
                        nHeight++;
                        ImplCallback( (USHORT) ( ( 100 * nHeight ) / mnHeight ) );  // processing output in percent
                    }
                }
                break;
        }
    }
    else switch  ( mnMode )
    {
        // PBM
        case 0 :
            while ( bFinished == FALSE )
            {
                if ( mpPBM->IsEof() || mpPBM->GetError() )
                    return FALSE;

                *mpPBM >> nDat;

                if ( nDat == '#' )
                {
                    mbRemark = TRUE;
                    continue;
                }
                else if ( ( nDat == 0x0d ) || ( nDat == 0x0a ) )
                {
                    mbRemark = FALSE;
                    continue;
                }
                if ( mbRemark || nDat == 0x20 || nDat == 0x09 )
                    continue;

                if ( nDat == '0' || nDat == '1' )
                {
                    mpAcc->SetPixel( nHeight, nWidth, (BYTE)nDat-'0' );
                    nWidth++;
                    if ( nWidth == mnWidth )
                    {
                        nWidth = 0;
                        if ( ++nHeight == mnHeight )
                            bFinished = TRUE;
                        ImplCallback( (USHORT) ( ( 100 * nHeight ) / mnHeight ) );  // processing output in percent
                    }
                }
                else
                    return FALSE;
            }
            break;

        // PGM
        case 1 :

            bPara = FALSE;
            nCount = 0;
            nGrey = 0;

            while ( bFinished == FALSE )
            {
                if ( nCount )
                {
                    nCount--;
                    if ( nGrey <= mnMaxVal )
                        nGrey = 255 * nGrey / mnMaxVal;
                        mpAcc->SetPixel( nHeight, nWidth++, (BYTE)nGrey );
                    nGrey = 0;
                    if ( nWidth == mnWidth )
                    {
                        nWidth = 0;
                        if ( ++nHeight == mnHeight )
                            bFinished = TRUE;
                        ImplCallback( (USHORT) ( ( 100 * nHeight ) / mnHeight ) );  // processing output in percent
                    }
                    continue;
                }

                if ( mpPBM->IsEof() || mpPBM->GetError() )
                    return FALSE;

                *mpPBM >> nDat;

                if ( nDat == '#' )
                {
                    mbRemark = TRUE;
                    if ( bPara )
                    {
                        bPara = FALSE;
                        nCount++;
                    }
                    continue;
                }
                else if ( ( nDat == 0x0d ) || ( nDat == 0x0a ) )
                {
                    mbRemark = FALSE;
                    if ( bPara )
                    {
                        bPara = FALSE;
                        nCount++;
                    }
                    continue;
                }

                if ( nDat == 0x20 || nDat == 0x09 )
                {
                    if ( bPara )
                    {
                        bPara = FALSE;
                        nCount++;
                    }
                    continue;
                }
                if ( nDat >= '0' && nDat <= '9' )
                {
                    bPara = TRUE;
                    nGrey *= 10;
                    nGrey += nDat-'0';
                    continue;
                }
                else
                    return FALSE;
            }
            break;

        // PPM
        case 2 :

            bPara = FALSE;
            nCount = 0;
            nRGB[ 0 ] = nRGB[ 1 ] = nRGB[ 2 ] = 0;

            while ( bFinished == FALSE )
            {
                if ( nCount == 3 )
                {
                    nCount = 0;
                    mpAcc->SetPixel( nHeight, nWidth++, BitmapColor( static_cast< BYTE >( ( nRGB[ 0 ] * 255 ) / mnMaxVal ),
                                                                     static_cast< BYTE >( ( nRGB[ 1 ] * 255 ) / mnMaxVal ),
                                                                     static_cast< BYTE >( ( nRGB[ 2 ] * 255 ) / mnMaxVal ) ) );
                    nCount = 0;
                    nRGB[ 0 ] = nRGB[ 1 ] = nRGB[ 2 ] = 0;
                    if ( nWidth == mnWidth )
                    {
                        nWidth = 0;
                        if ( ++nHeight == mnHeight )
                            bFinished = TRUE;
                        ImplCallback( (USHORT) ( ( 100 * nHeight ) / mnHeight ) );  // processing output in percent
                    }
                    continue;
                }

                if ( mpPBM->IsEof() || mpPBM->GetError() )
                    return FALSE;

                *mpPBM >> nDat;

                if ( nDat == '#' )
                {
                    mbRemark = TRUE;
                    if ( bPara )
                    {
                        bPara = FALSE;
                        nCount++;
                    }
                    continue;
                }
                else if ( ( nDat == 0x0d ) || ( nDat == 0x0a ) )
                {
                    mbRemark = FALSE;
                    if ( bPara )
                    {
                        bPara = FALSE;
                        nCount++;
                    }
                    continue;
                }

                if ( nDat == 0x20 || nDat == 0x09 )
                {
                    if ( bPara )
                    {
                        bPara = FALSE;
                        nCount++;
                    }
                    continue;
                }
                if ( nDat >= '0' && nDat <= '9' )
                {
                    bPara = TRUE;
                    nRGB[ nCount ] *= 10;
                    nRGB[ nCount ] += nDat-'0';
                    continue;
                }
                else
                    return FALSE;
            }
            break;
    }
    return mbStatus;
}

//================== GraphicImport - die exportierte Funktion ================

extern "C" BOOL __LOADONCALLAPI GraphicImport(SvStream & rStream, Graphic & rGraphic, FilterConfigItem*, BOOL )
{
    PBMReader aPBMReader;

    return aPBMReader.ReadPBM( rStream, rGraphic );
}

//================== ein bischen Muell fuer Windows ==========================
#ifndef GCC
#endif

#ifdef WIN

static HINSTANCE hDLLInst = 0;      // HANDLE der DLL

extern "C" int CALLBACK LibMain( HINSTANCE hDLL, WORD, WORD nHeap, LPSTR )
{
#ifndef WNT
    if ( nHeap )
        UnlockData( 0 );
#endif

    hDLLInst = hDLL;

    return TRUE;
}

extern "C" int CALLBACK WEP( int )
{
    return 1;
}

#endif

<commit_msg>impress181: #i74384# correctly interpreting maxcolor value vor ppm (taking care also for pbp)<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: ipbm.cxx,v $
 * $Revision: 1.9 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_goodies.hxx"

#include <vcl/graph.hxx>
#include <vcl/bmpacc.hxx>
#include <svtools/fltcall.hxx>

//============================ PBMReader ==================================

class PBMReader {

private:

    SvStream*           mpPBM;          // Die einzulesende PBM-Datei

    BOOL                mbStatus;
    BOOL                mbRemark;       // FALSE wenn sich stream in einem Kommentar befindet
    BOOL                mbRaw;          // RAW/ASCII MODE
    ULONG               mnMode;         // 0->PBM, 1->PGM, 2->PPM
    Bitmap              maBmp;
    BitmapWriteAccess*  mpAcc;
    ULONG               mnWidth, mnHeight;  // Bildausmass in Pixeln
    ULONG               mnCol;
    ULONG               mnMaxVal;           // maximaler wert in den
    BOOL                ImplCallback( USHORT nPercent );
    BOOL                ImplReadBody();
    BOOL                ImplReadHeader();

public:
                        PBMReader();
                        ~PBMReader();
    BOOL                ReadPBM( SvStream & rPBM, Graphic & rGraphic );
};

//=================== Methoden von PBMReader ==============================

PBMReader::PBMReader() :
    mbStatus    ( TRUE ),
    mbRemark    ( FALSE ),
    mbRaw       ( TRUE ),
    mpAcc       ( NULL )
{
}

PBMReader::~PBMReader()
{
}

BOOL PBMReader::ImplCallback( USHORT /*nPercent*/ )
{
/*
    if ( pCallback != NULL )
    {
        if ( ( (*pCallback)( pCallerData, nPercent ) ) == TRUE )
        {
            mpPBM->SetError( SVSTREAM_FILEFORMAT_ERROR );
            return TRUE;
        }
    }
*/
    return FALSE;
}

BOOL PBMReader::ReadPBM( SvStream & rPBM, Graphic & rGraphic )
{
    USHORT i;

    if ( rPBM.GetError() )
        return FALSE;

    mpPBM = &rPBM;
    mpPBM->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );

    // Kopf einlesen:

    if ( ( mbStatus = ImplReadHeader() ) == FALSE )
        return FALSE;

    if ( ( mnMaxVal == 0 ) || ( mnWidth == 0 ) || ( mnHeight == 0 ) )
        return FALSE;

    // 0->PBM, 1->PGM, 2->PPM
    switch ( mnMode )
    {
        case 0 :
            maBmp = Bitmap( Size( mnWidth, mnHeight ), 1 );
            if ( ( mpAcc = maBmp.AcquireWriteAccess() ) == FALSE )
                return FALSE;
            mpAcc->SetPaletteEntryCount( 2 );
            mpAcc->SetPaletteColor( 0, BitmapColor( 0xff, 0xff, 0xff ) );
            mpAcc->SetPaletteColor( 1, BitmapColor( 0x00, 0x00, 0x00 ) );
            break;

        case 1 :
            if ( mnMaxVal <= 1 )
                maBmp = Bitmap( Size( mnWidth, mnHeight ), 1);
            else if ( mnMaxVal <= 15 )
                maBmp = Bitmap( Size( mnWidth, mnHeight ), 4);
            else
                maBmp = Bitmap( Size( mnWidth, mnHeight ), 8);

            if ( ( mpAcc = maBmp.AcquireWriteAccess() ) == FALSE )
                return FALSE;
            mnCol = (USHORT)mnMaxVal + 1;
            if ( mnCol > 256 )
                mnCol = 256;

            mpAcc->SetPaletteEntryCount( 256 );
            for ( i = 0; i < mnCol; i++ )
            {
                ULONG nCount = 255 * i / mnCol;
                mpAcc->SetPaletteColor( i, BitmapColor( (BYTE)nCount, (BYTE)nCount, (BYTE)nCount ) );
            }
            break;
        case 2 :
            maBmp = Bitmap( Size( mnWidth, mnHeight ), 24 );
            if ( ( mpAcc = maBmp.AcquireWriteAccess() ) == FALSE )
                return FALSE;
            break;
    }

    // Bitmap-Daten einlesen
    mbStatus = ImplReadBody();

    if ( mpAcc )
    {
        maBmp.ReleaseAccess( mpAcc ), mpAcc = NULL;
    }
    if ( mbStatus )
        rGraphic = maBmp;

    return mbStatus;
}

BOOL PBMReader::ImplReadHeader()
{
    BYTE    nID[ 2 ];
    BYTE    nDat;
    BYTE    nMax, nCount = 0;
    BOOL    bFinished = FALSE;

    *mpPBM >> nID[ 0 ] >> nID[ 1 ];
    if ( nID[ 0 ] != 'P' )
        return FALSE;
    mnMaxVal = mnWidth = mnHeight = 0;
    switch ( nID[ 1 ] )
    {
        case '1' :
            mbRaw = FALSE;
        case '4' :
            mnMode = 0;
            nMax = 2;               // number of parameters in Header
            mnMaxVal = 1;
            break;
        case '2' :
            mbRaw = FALSE;
        case '5' :
            mnMode = 1;
            nMax = 3;
            break;
        case '3' :
            mbRaw = FALSE;
        case '6' :
            mnMode = 2;
            nMax = 3;
            break;
        default:
            return FALSE;
    }
    while ( bFinished == FALSE )
    {
        if ( mpPBM->GetError() )
            return FALSE;

        *mpPBM >> nDat;

        if ( nDat == '#' )
        {
            mbRemark = TRUE;
            continue;
        }
        else if ( ( nDat == 0x0d ) || ( nDat == 0x0a ) )
        {
            mbRemark = FALSE;
            nDat = 0x20;
        }
        if ( mbRemark )
            continue;

        if ( ( nDat == 0x20 ) || ( nDat == 0x09 ) )
        {
            if ( ( nCount == 0 ) && mnWidth )
                nCount++;
            else if ( ( nCount == 1 ) && mnHeight )
            {
                if ( ++nCount == nMax )
                    bFinished = TRUE;
            }
            else if ( ( nCount == 2 ) && mnMaxVal )
            {
                bFinished = TRUE;
            }
            continue;
        }
        if ( ( nDat >= '0' ) && ( nDat <= '9' ) )
        {
            nDat -= '0';
            if ( nCount == 0 )
            {
                mnWidth *= 10;
                mnWidth += nDat;
            }
            else if ( nCount == 1 )
            {
                mnHeight *= 10;
                mnHeight += nDat;
            }
            else if ( nCount == 2 )
            {
                mnMaxVal *= 10;
                mnMaxVal += nDat;
            }
        }
        else
            return FALSE;
    }
    return mbStatus;
}

BOOL PBMReader::ImplReadBody()
{
    BOOL    bPara, bFinished = FALSE;
    BYTE    nDat = 0, nCount;
    ULONG   nGrey, nRGB[3];
    ULONG   nWidth = 0;
    ULONG   nHeight = 0;
    signed char nShift = 0;

    if ( mbRaw )
    {
        switch ( mnMode )
        {

            // PBM
            case 0 :
                while ( nHeight != mnHeight )
                {
                    if ( mpPBM->IsEof() || mpPBM->GetError() )
                        return FALSE;

                    if ( --nShift < 0 )
                    {
                        *mpPBM >> nDat;
                        nShift = 7;
                    }
                    mpAcc->SetPixel( nHeight, nWidth, nDat >> nShift );
                    if ( ++nWidth == mnWidth )
                    {
                        nShift = 0;
                        nWidth = 0;
                        nHeight++;
                        ImplCallback( (USHORT)( ( 100 * nHeight ) / mnHeight ) );   // processing output in percent
                    }
                }
                break;

            // PGM
            case 1 :
                while ( nHeight != mnHeight )
                {
                    if ( mpPBM->IsEof() || mpPBM->GetError() )
                        return FALSE;

                    *mpPBM >> nDat;
                    mpAcc->SetPixel( nHeight, nWidth++, nDat);

                    if ( nWidth == mnWidth )
                    {
                        nWidth = 0;
                        nHeight++;
                        ImplCallback( (USHORT)( ( 100 * nHeight ) / mnHeight ) );   // processing output in percent
                    }
                }
                break;

            // PPM
            case 2 :
                while ( nHeight != mnHeight )
                {
                    if ( mpPBM->IsEof() || mpPBM->GetError() )
                        return FALSE;

                    BYTE    nR, nG, nB;
                    ULONG   nRed, nGreen, nBlue;
                    *mpPBM >> nR >> nG >> nB;
                    nRed = 255 * nR / mnMaxVal;
                    nGreen = 255 * nG / mnMaxVal;
                    nBlue = 255 * nB / mnMaxVal;
                    mpAcc->SetPixel( nHeight, nWidth++, BitmapColor( (BYTE)nRed, (BYTE)nGreen, (BYTE)nBlue ) );
                    if ( nWidth == mnWidth )
                    {
                        nWidth = 0;
                        nHeight++;
                        ImplCallback( (USHORT) ( ( 100 * nHeight ) / mnHeight ) );  // processing output in percent
                    }
                }
                break;
        }
    }
    else switch  ( mnMode )
    {
        // PBM
        case 0 :
            while ( bFinished == FALSE )
            {
                if ( mpPBM->IsEof() || mpPBM->GetError() )
                    return FALSE;

                *mpPBM >> nDat;

                if ( nDat == '#' )
                {
                    mbRemark = TRUE;
                    continue;
                }
                else if ( ( nDat == 0x0d ) || ( nDat == 0x0a ) )
                {
                    mbRemark = FALSE;
                    continue;
                }
                if ( mbRemark || nDat == 0x20 || nDat == 0x09 )
                    continue;

                if ( nDat == '0' || nDat == '1' )
                {
                    mpAcc->SetPixel( nHeight, nWidth, (BYTE)nDat-'0' );
                    nWidth++;
                    if ( nWidth == mnWidth )
                    {
                        nWidth = 0;
                        if ( ++nHeight == mnHeight )
                            bFinished = TRUE;
                        ImplCallback( (USHORT) ( ( 100 * nHeight ) / mnHeight ) );  // processing output in percent
                    }
                }
                else
                    return FALSE;
            }
            break;

        // PGM
        case 1 :

            bPara = FALSE;
            nCount = 0;
            nGrey = 0;

            while ( bFinished == FALSE )
            {
                if ( nCount )
                {
                    nCount--;
                    if ( nGrey <= mnMaxVal )
                        nGrey = 255 * nGrey / mnMaxVal;
                        mpAcc->SetPixel( nHeight, nWidth++, (BYTE)nGrey );
                    nGrey = 0;
                    if ( nWidth == mnWidth )
                    {
                        nWidth = 0;
                        if ( ++nHeight == mnHeight )
                            bFinished = TRUE;
                        ImplCallback( (USHORT) ( ( 100 * nHeight ) / mnHeight ) );  // processing output in percent
                    }
                    continue;
                }

                if ( mpPBM->IsEof() || mpPBM->GetError() )
                    return FALSE;

                *mpPBM >> nDat;

                if ( nDat == '#' )
                {
                    mbRemark = TRUE;
                    if ( bPara )
                    {
                        bPara = FALSE;
                        nCount++;
                    }
                    continue;
                }
                else if ( ( nDat == 0x0d ) || ( nDat == 0x0a ) )
                {
                    mbRemark = FALSE;
                    if ( bPara )
                    {
                        bPara = FALSE;
                        nCount++;
                    }
                    continue;
                }

                if ( nDat == 0x20 || nDat == 0x09 )
                {
                    if ( bPara )
                    {
                        bPara = FALSE;
                        nCount++;
                    }
                    continue;
                }
                if ( nDat >= '0' && nDat <= '9' )
                {
                    bPara = TRUE;
                    nGrey *= 10;
                    nGrey += nDat-'0';
                    continue;
                }
                else
                    return FALSE;
            }
            break;

        // PPM
        case 2 :

            bPara = FALSE;
            nCount = 0;
            nRGB[ 0 ] = nRGB[ 1 ] = nRGB[ 2 ] = 0;

            while ( bFinished == FALSE )
            {
                if ( nCount == 3 )
                {
                    nCount = 0;
                    mpAcc->SetPixel( nHeight, nWidth++, BitmapColor( static_cast< BYTE >( ( nRGB[ 0 ] * 255 ) / mnMaxVal ),
                                                                     static_cast< BYTE >( ( nRGB[ 1 ] * 255 ) / mnMaxVal ),
                                                                     static_cast< BYTE >( ( nRGB[ 2 ] * 255 ) / mnMaxVal ) ) );
                    nCount = 0;
                    nRGB[ 0 ] = nRGB[ 1 ] = nRGB[ 2 ] = 0;
                    if ( nWidth == mnWidth )
                    {
                        nWidth = 0;
                        if ( ++nHeight == mnHeight )
                            bFinished = TRUE;
                        ImplCallback( (USHORT) ( ( 100 * nHeight ) / mnHeight ) );  // processing output in percent
                    }
                    continue;
                }

                if ( mpPBM->IsEof() || mpPBM->GetError() )
                    return FALSE;

                *mpPBM >> nDat;

                if ( nDat == '#' )
                {
                    mbRemark = TRUE;
                    if ( bPara )
                    {
                        bPara = FALSE;
                        nCount++;
                    }
                    continue;
                }
                else if ( ( nDat == 0x0d ) || ( nDat == 0x0a ) )
                {
                    mbRemark = FALSE;
                    if ( bPara )
                    {
                        bPara = FALSE;
                        nCount++;
                    }
                    continue;
                }

                if ( nDat == 0x20 || nDat == 0x09 )
                {
                    if ( bPara )
                    {
                        bPara = FALSE;
                        nCount++;
                    }
                    continue;
                }
                if ( nDat >= '0' && nDat <= '9' )
                {
                    bPara = TRUE;
                    nRGB[ nCount ] *= 10;
                    nRGB[ nCount ] += nDat-'0';
                    continue;
                }
                else
                    return FALSE;
            }
            break;
    }
    return mbStatus;
}

//================== GraphicImport - die exportierte Funktion ================

extern "C" BOOL __LOADONCALLAPI GraphicImport(SvStream & rStream, Graphic & rGraphic, FilterConfigItem*, BOOL )
{
    PBMReader aPBMReader;

    return aPBMReader.ReadPBM( rStream, rGraphic );
}

//================== ein bischen Muell fuer Windows ==========================
#ifndef GCC
#endif

#ifdef WIN

static HINSTANCE hDLLInst = 0;      // HANDLE der DLL

extern "C" int CALLBACK LibMain( HINSTANCE hDLL, WORD, WORD nHeap, LPSTR )
{
#ifndef WNT
    if ( nHeap )
        UnlockData( 0 );
#endif

    hDLLInst = hDLL;

    return TRUE;
}

extern "C" int CALLBACK WEP( int )
{
    return 1;
}

#endif

<|endoftext|>