<commit_before>//  Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
 // LICENSE file in the root directory of this source tree.

#include "jsireact/JSIExecutor.h"

#include <cxxreact/JSBigString.h>
#include <cxxreact/ModuleRegistry.h>
#include <cxxreact/ReactMarker.h>
#include <cxxreact/SystraceSection.h>
#include <folly/Conv.h>
#include <folly/json.h>
#include <glog/logging.h>
#include <jsi/JSIDynamic.h>

#include <sstream>
#include <stdexcept>

using namespace facebook::jsi;

namespace facebook {
namespace react {

class JSIExecutor::NativeModuleProxy : public jsi::HostObject {
 public:
  NativeModuleProxy(JSIExecutor& executor) : executor_(executor) {}

  Value get(Runtime& rt, const PropNameID& name) override {
    if (name.utf8(rt) == "name") {
      return jsi::String::createFromAscii(rt, "NativeModules");
    }

    return executor_.nativeModules_.getModule(rt, name);
  }

  void set(Runtime&, const PropNameID&, const Value&) override {
    throw std::runtime_error(
        "Unable to put on NativeModules: Operation unsupported");
  }

 private:
  JSIExecutor& executor_;
};

namespace {

// basename_r isn't in all iOS SDKs, so use this simple version instead.
std::string simpleBasename(const std::string& path) {
  size_t pos = path.rfind("/");
  return (pos != std::string::npos) ? path.substr(pos) : path;
}

} // namespace

JSIExecutor::JSIExecutor(
    std::shared_ptr<jsi::Runtime> runtime,
    std::shared_ptr<ExecutorDelegate> delegate,
    Logger logger,
    const JSIScopedTimeoutInvoker& scopedTimeoutInvoker,
    RuntimeInstaller runtimeInstaller)
    : runtime_(runtime),
      delegate_(delegate),
      nativeModules_(delegate ? delegate->getModuleRegistry() : nullptr),
      logger_(logger),
      scopedTimeoutInvoker_(scopedTimeoutInvoker),
      runtimeInstaller_(runtimeInstaller) {
  runtime_->global().setProperty(
      *runtime, "__jsiExecutorDescription", runtime->description());
}

void JSIExecutor::loadApplicationScript(
    std::unique_ptr<const JSBigString> script,
    std::string sourceURL) {
  SystraceSection s("JSIExecutor::loadApplicationScript");

  // TODO: check for and use precompiled HBC

  runtime_->global().setProperty(
      *runtime_,
      "nativeModuleProxy",
      Object::createFromHostObject(
          *runtime_, std::make_shared<NativeModuleProxy>(*this)));

  runtime_->global().setProperty(
      *runtime_,
      "nativeFlushQueueImmediate",
      Function::createFromHostFunction(
          *runtime_,
          PropNameID::forAscii(*runtime_, "nativeFlushQueueImmediate"),
          1,
          [this](
              jsi::Runtime&,
              const jsi::Value&,
              const jsi::Value* args,
              size_t count) {
            if (count != 1) {
              throw std::invalid_argument(
                  "nativeFlushQueueImmediate arg count must be 1");
            }
            callNativeModules(args[0], false);
            return Value::undefined();
          }));

  runtime_->global().setProperty(
      *runtime_,
      "nativeCallSyncHook",
      Function::createFromHostFunction(
          *runtime_,
          PropNameID::forAscii(*runtime_, "nativeCallSyncHook"),
          1,
          [this](
              jsi::Runtime&,
              const jsi::Value&,
              const jsi::Value* args,
              size_t count) { return nativeCallSyncHook(args, count); }));

  if (logger_) {
    // Only inject the logging function if it was supplied by the caller.
    runtime_->global().setProperty(
        *runtime_,
        "nativeLoggingHook",
        Function::createFromHostFunction(
            *runtime_,
            PropNameID::forAscii(*runtime_, "nativeLoggingHook"),
            2,
            [this](
                jsi::Runtime&,
                const jsi::Value&,
                const jsi::Value* args,
                size_t count) {
              if (count != 2) {
                throw std::invalid_argument(
                    "nativeLoggingHook takes 2 arguments");
              }
              logger_(
                  args[0].asString(*runtime_).utf8(*runtime_),
                  folly::to<unsigned int>(args[1].asNumber()));
              return Value::undefined();
            }));
  }

  if (runtimeInstaller_) {
    runtimeInstaller_(*runtime_);
  }

  bool hasLogger(ReactMarker::logTaggedMarker);
  std::string scriptName = simpleBasename(sourceURL);
  if (hasLogger) {
    ReactMarker::logTaggedMarker(
        ReactMarker::RUN_JS_BUNDLE_START, scriptName.c_str());
  }
  runtime_->evaluateJavaScript(
      std::make_unique<BigStringBuffer>(std::move(script)), sourceURL);
  flush();
  if (hasLogger) {
    ReactMarker::logMarker(ReactMarker::CREATE_REACT_CONTEXT_STOP);
    ReactMarker::logTaggedMarker(
        ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str());
  }
}

void JSIExecutor::setBundleRegistry(std::unique_ptr<RAMBundleRegistry> r) {
  if (!bundleRegistry_) {
    runtime_->global().setProperty(
        *runtime_,
        "nativeRequire",
        Function::createFromHostFunction(
            *runtime_,
            PropNameID::forAscii(*runtime_, "nativeRequire"),
            2,
            [this](
                Runtime& rt,
                const facebook::jsi::Value&,
                const facebook::jsi::Value* args,
                size_t count) { return nativeRequire(args, count); }));
  }
  bundleRegistry_ = std::move(r);
}

void JSIExecutor::registerBundle(
    uint32_t bundleId,
    const std::string& bundlePath) {
  const auto tag = folly::to<std::string>(bundleId);
  ReactMarker::logTaggedMarker(
      ReactMarker::REGISTER_JS_SEGMENT_START, tag.c_str());
  if (bundleRegistry_) {
    bundleRegistry_->registerBundle(bundleId, bundlePath);
  } else {
    auto script = JSBigFileString::fromPath(bundlePath);
    runtime_->evaluateJavaScript(
        std::make_unique<BigStringBuffer>(std::move(script)),
        JSExecutor::getSyntheticBundlePath(bundleId, bundlePath));
  }
  ReactMarker::logTaggedMarker(
      ReactMarker::REGISTER_JS_SEGMENT_STOP, tag.c_str());
}

void JSIExecutor::callFunction(
    const std::string& moduleId,
    const std::string& methodId,
    const folly::dynamic& arguments) {
  SystraceSection s(
      "JSIExecutor::callFunction", "moduleId", moduleId, "methodId", methodId);
  if (!callFunctionReturnFlushedQueue_) {
    bindBridge();
  }

  // Construct the error message producer in case this times out.
  // This is executed on a background thread, so it must capture its parameters
  // by value.
  auto errorProducer = [=] {
    std::stringstream ss;
    ss << "moduleID: " << moduleId << " methodID: " << methodId
       << " arguments: " << folly::toJson(arguments);
    return ss.str();
  };

  Value ret = Value::undefined();
  try {
    scopedTimeoutInvoker_(
        [&] {
          ret = callFunctionReturnFlushedQueue_->call(
              *runtime_,
              moduleId,
              methodId,
              valueFromDynamic(*runtime_, arguments));
        },
        std::move(errorProducer));
  } catch (...) {
    std::throw_with_nested(
        std::runtime_error("Error calling " + moduleId + "." + methodId));
  }

  callNativeModules(ret, true);
}

void JSIExecutor::invokeCallback(
    const double callbackId,
    const folly::dynamic& arguments) {
  SystraceSection s("JSIExecutor::invokeCallback", "callbackId", callbackId);
  if (!invokeCallbackAndReturnFlushedQueue_) {
    bindBridge();
  }
  Value ret;
  try {
    ret = invokeCallbackAndReturnFlushedQueue_->call(
        *runtime_, callbackId, valueFromDynamic(*runtime_, arguments));
  } catch (...) {
    std::throw_with_nested(std::runtime_error(
        folly::to<std::string>("Error invoking callback ", callbackId)));
  }

  callNativeModules(ret, true);
}

void JSIExecutor::setGlobalVariable(
    std::string propName,
    std::unique_ptr<const JSBigString> jsonValue) {
  SystraceSection s("JSIExecutor::setGlobalVariable", "propName", propName);
  runtime_->global().setProperty(
      *runtime_,
      propName.c_str(),
      Value::createFromJsonUtf8(
          *runtime_,
          reinterpret_cast<const uint8_t*>(jsonValue->c_str()),
          jsonValue->size()));
}

std::string JSIExecutor::getDescription() {
  return "JSI " + runtime_->description();
}

void* JSIExecutor::getJavaScriptContext() {
  return runtime_.get();
}

bool JSIExecutor::isInspectable() {
  return runtime_->isInspectable();
}

void JSIExecutor::bindBridge() {
  std::call_once(bindFlag_, [this] {
    SystraceSection s("JSIExecutor::bindBridge (once)");
    Value batchedBridgeValue =
        runtime_->global().getProperty(*runtime_, "__fbBatchedBridge");
    if (batchedBridgeValue.isUndefined()) {
      Function requireBatchedBridge = runtime_->global().getPropertyAsFunction(
          *runtime_, "__fbRequireBatchedBridge");
      batchedBridgeValue = requireBatchedBridge.call(*runtime_);
      if (batchedBridgeValue.isUndefined()) {
        throw JSINativeException(
            "Could not get BatchedBridge, make sure your bundle is packaged correctly");
      }
    }

    Object batchedBridge = batchedBridgeValue.asObject(*runtime_);
    callFunctionReturnFlushedQueue_ = batchedBridge.getPropertyAsFunction(
        *runtime_, "callFunctionReturnFlushedQueue");
    invokeCallbackAndReturnFlushedQueue_ = batchedBridge.getPropertyAsFunction(
        *runtime_, "invokeCallbackAndReturnFlushedQueue");
    flushedQueue_ =
        batchedBridge.getPropertyAsFunction(*runtime_, "flushedQueue");
    callFunctionReturnResultAndFlushedQueue_ =
        batchedBridge.getPropertyAsFunction(
            *runtime_, "callFunctionReturnResultAndFlushedQueue");
  });
}

void JSIExecutor::callNativeModules(const Value& queue, bool isEndOfBatch) {
  SystraceSection s("JSIExecutor::callNativeModules");
  // If this fails, you need to pass a fully functional delegate with a
  // module registry to the factory/ctor.
  CHECK(delegate_) << "Attempting to use native modules without a delegate";
#if 0 // maybe useful for debugging
  std::string json = runtime_->global().getPropertyAsObject(*runtime_, "JSON")
    .getPropertyAsFunction(*runtime_, "stringify").call(*runtime_, queue)
    .getString(*runtime_).utf8(*runtime_);
#endif
  delegate_->callNativeModules(
      *this, dynamicFromValue(*runtime_, queue), isEndOfBatch);
}

void JSIExecutor::flush() {
  SystraceSection s("JSIExecutor::flush");
  if (flushedQueue_) {
    callNativeModules(flushedQueue_->call(*runtime_), true);
    return;
  }

  // When a native module is called from JS, BatchedBridge.enqueueNativeCall()
  // is invoked.  For that to work, require('BatchedBridge') has to be called,
  // and when that happens, __fbBatchedBridge is set as a side effect.
  Value batchedBridge =
      runtime_->global().getProperty(*runtime_, "__fbBatchedBridge");
  // So here, if __fbBatchedBridge doesn't exist, then we know no native calls
  // have happened, and we were able to determine this without forcing
  // BatchedBridge to be loaded as a side effect.
  if (!batchedBridge.isUndefined()) {
    // If calls were made, we bind to the JS bridge methods, and use them to
    // get the pending queue of native calls.
    bindBridge();
    callNativeModules(flushedQueue_->call(*runtime_), true);
  } else if (delegate_) {
    // If we have a delegate, we need to call it; we pass a null list to
    // callNativeModules, since we know there are no native calls, without
    // calling into JS again.  If no calls were made and there's no delegate,
    // nothing happens, which is correct.
    callNativeModules(nullptr, true);
  }
}

Value JSIExecutor::nativeRequire(const Value* args, size_t count) {
  if (count > 2 || count == 0) {
    throw std::invalid_argument("Got wrong number of args");
  }

  uint32_t moduleId = folly::to<uint32_t>(args[0].getNumber());
  uint32_t bundleId = count == 2 ? folly::to<uint32_t>(args[1].getNumber()) : 0;
  auto module = bundleRegistry_->getModule(bundleId, moduleId);

  runtime_->evaluateJavaScript(
      std::make_unique<StringBuffer>(module.code), module.name);
  return facebook::jsi::Value();
}

Value JSIExecutor::nativeCallSyncHook(const Value* args, size_t count) {
  if (count != 3) {
    throw std::invalid_argument("nativeCallSyncHook arg count must be 3");
  }

  if (!args[2].asObject(*runtime_).isArray(*runtime_)) {
    throw std::invalid_argument(
        folly::to<std::string>("method parameters should be array"));
  }

  MethodCallResult result = delegate_->callSerializableNativeHook(
      *this,
      static_cast<unsigned int>(args[0].getNumber()), // moduleId
      static_cast<unsigned int>(args[1].getNumber()), // methodId
      dynamicFromValue(*runtime_, args[2])); // args

  if (!result.hasValue()) {
    return Value::undefined();
  }
  return valueFromDynamic(*runtime_, result.value());
}

} // namespace react
} // namespace facebook
<commit_msg>Remove __fbRequireBatchedBridge call when not get batchedBridge (#23547)<commit_after>//  Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
 // LICENSE file in the root directory of this source tree.

#include "jsireact/JSIExecutor.h"

#include <cxxreact/JSBigString.h>
#include <cxxreact/ModuleRegistry.h>
#include <cxxreact/ReactMarker.h>
#include <cxxreact/SystraceSection.h>
#include <folly/Conv.h>
#include <folly/json.h>
#include <glog/logging.h>
#include <jsi/JSIDynamic.h>

#include <sstream>
#include <stdexcept>

using namespace facebook::jsi;

namespace facebook {
namespace react {

class JSIExecutor::NativeModuleProxy : public jsi::HostObject {
 public:
  NativeModuleProxy(JSIExecutor& executor) : executor_(executor) {}

  Value get(Runtime& rt, const PropNameID& name) override {
    if (name.utf8(rt) == "name") {
      return jsi::String::createFromAscii(rt, "NativeModules");
    }

    return executor_.nativeModules_.getModule(rt, name);
  }

  void set(Runtime&, const PropNameID&, const Value&) override {
    throw std::runtime_error(
        "Unable to put on NativeModules: Operation unsupported");
  }

 private:
  JSIExecutor& executor_;
};

namespace {

// basename_r isn't in all iOS SDKs, so use this simple version instead.
std::string simpleBasename(const std::string& path) {
  size_t pos = path.rfind("/");
  return (pos != std::string::npos) ? path.substr(pos) : path;
}

} // namespace

JSIExecutor::JSIExecutor(
    std::shared_ptr<jsi::Runtime> runtime,
    std::shared_ptr<ExecutorDelegate> delegate,
    Logger logger,
    const JSIScopedTimeoutInvoker& scopedTimeoutInvoker,
    RuntimeInstaller runtimeInstaller)
    : runtime_(runtime),
      delegate_(delegate),
      nativeModules_(delegate ? delegate->getModuleRegistry() : nullptr),
      logger_(logger),
      scopedTimeoutInvoker_(scopedTimeoutInvoker),
      runtimeInstaller_(runtimeInstaller) {
  runtime_->global().setProperty(
      *runtime, "__jsiExecutorDescription", runtime->description());
}

void JSIExecutor::loadApplicationScript(
    std::unique_ptr<const JSBigString> script,
    std::string sourceURL) {
  SystraceSection s("JSIExecutor::loadApplicationScript");

  // TODO: check for and use precompiled HBC

  runtime_->global().setProperty(
      *runtime_,
      "nativeModuleProxy",
      Object::createFromHostObject(
          *runtime_, std::make_shared<NativeModuleProxy>(*this)));

  runtime_->global().setProperty(
      *runtime_,
      "nativeFlushQueueImmediate",
      Function::createFromHostFunction(
          *runtime_,
          PropNameID::forAscii(*runtime_, "nativeFlushQueueImmediate"),
          1,
          [this](
              jsi::Runtime&,
              const jsi::Value&,
              const jsi::Value* args,
              size_t count) {
            if (count != 1) {
              throw std::invalid_argument(
                  "nativeFlushQueueImmediate arg count must be 1");
            }
            callNativeModules(args[0], false);
            return Value::undefined();
          }));

  runtime_->global().setProperty(
      *runtime_,
      "nativeCallSyncHook",
      Function::createFromHostFunction(
          *runtime_,
          PropNameID::forAscii(*runtime_, "nativeCallSyncHook"),
          1,
          [this](
              jsi::Runtime&,
              const jsi::Value&,
              const jsi::Value* args,
              size_t count) { return nativeCallSyncHook(args, count); }));

  if (logger_) {
    // Only inject the logging function if it was supplied by the caller.
    runtime_->global().setProperty(
        *runtime_,
        "nativeLoggingHook",
        Function::createFromHostFunction(
            *runtime_,
            PropNameID::forAscii(*runtime_, "nativeLoggingHook"),
            2,
            [this](
                jsi::Runtime&,
                const jsi::Value&,
                const jsi::Value* args,
                size_t count) {
              if (count != 2) {
                throw std::invalid_argument(
                    "nativeLoggingHook takes 2 arguments");
              }
              logger_(
                  args[0].asString(*runtime_).utf8(*runtime_),
                  folly::to<unsigned int>(args[1].asNumber()));
              return Value::undefined();
            }));
  }

  if (runtimeInstaller_) {
    runtimeInstaller_(*runtime_);
  }

  bool hasLogger(ReactMarker::logTaggedMarker);
  std::string scriptName = simpleBasename(sourceURL);
  if (hasLogger) {
    ReactMarker::logTaggedMarker(
        ReactMarker::RUN_JS_BUNDLE_START, scriptName.c_str());
  }
  runtime_->evaluateJavaScript(
      std::make_unique<BigStringBuffer>(std::move(script)), sourceURL);
  flush();
  if (hasLogger) {
    ReactMarker::logMarker(ReactMarker::CREATE_REACT_CONTEXT_STOP);
    ReactMarker::logTaggedMarker(
        ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str());
  }
}

void JSIExecutor::setBundleRegistry(std::unique_ptr<RAMBundleRegistry> r) {
  if (!bundleRegistry_) {
    runtime_->global().setProperty(
        *runtime_,
        "nativeRequire",
        Function::createFromHostFunction(
            *runtime_,
            PropNameID::forAscii(*runtime_, "nativeRequire"),
            2,
            [this](
                Runtime& rt,
                const facebook::jsi::Value&,
                const facebook::jsi::Value* args,
                size_t count) { return nativeRequire(args, count); }));
  }
  bundleRegistry_ = std::move(r);
}

void JSIExecutor::registerBundle(
    uint32_t bundleId,
    const std::string& bundlePath) {
  const auto tag = folly::to<std::string>(bundleId);
  ReactMarker::logTaggedMarker(
      ReactMarker::REGISTER_JS_SEGMENT_START, tag.c_str());
  if (bundleRegistry_) {
    bundleRegistry_->registerBundle(bundleId, bundlePath);
  } else {
    auto script = JSBigFileString::fromPath(bundlePath);
    runtime_->evaluateJavaScript(
        std::make_unique<BigStringBuffer>(std::move(script)),
        JSExecutor::getSyntheticBundlePath(bundleId, bundlePath));
  }
  ReactMarker::logTaggedMarker(
      ReactMarker::REGISTER_JS_SEGMENT_STOP, tag.c_str());
}

void JSIExecutor::callFunction(
    const std::string& moduleId,
    const std::string& methodId,
    const folly::dynamic& arguments) {
  SystraceSection s(
      "JSIExecutor::callFunction", "moduleId", moduleId, "methodId", methodId);
  if (!callFunctionReturnFlushedQueue_) {
    bindBridge();
  }

  // Construct the error message producer in case this times out.
  // This is executed on a background thread, so it must capture its parameters
  // by value.
  auto errorProducer = [=] {
    std::stringstream ss;
    ss << "moduleID: " << moduleId << " methodID: " << methodId
       << " arguments: " << folly::toJson(arguments);
    return ss.str();
  };

  Value ret = Value::undefined();
  try {
    scopedTimeoutInvoker_(
        [&] {
          ret = callFunctionReturnFlushedQueue_->call(
              *runtime_,
              moduleId,
              methodId,
              valueFromDynamic(*runtime_, arguments));
        },
        std::move(errorProducer));
  } catch (...) {
    std::throw_with_nested(
        std::runtime_error("Error calling " + moduleId + "." + methodId));
  }

  callNativeModules(ret, true);
}

void JSIExecutor::invokeCallback(
    const double callbackId,
    const folly::dynamic& arguments) {
  SystraceSection s("JSIExecutor::invokeCallback", "callbackId", callbackId);
  if (!invokeCallbackAndReturnFlushedQueue_) {
    bindBridge();
  }
  Value ret;
  try {
    ret = invokeCallbackAndReturnFlushedQueue_->call(
        *runtime_, callbackId, valueFromDynamic(*runtime_, arguments));
  } catch (...) {
    std::throw_with_nested(std::runtime_error(
        folly::to<std::string>("Error invoking callback ", callbackId)));
  }

  callNativeModules(ret, true);
}

void JSIExecutor::setGlobalVariable(
    std::string propName,
    std::unique_ptr<const JSBigString> jsonValue) {
  SystraceSection s("JSIExecutor::setGlobalVariable", "propName", propName);
  runtime_->global().setProperty(
      *runtime_,
      propName.c_str(),
      Value::createFromJsonUtf8(
          *runtime_,
          reinterpret_cast<const uint8_t*>(jsonValue->c_str()),
          jsonValue->size()));
}

std::string JSIExecutor::getDescription() {
  return "JSI " + runtime_->description();
}

void* JSIExecutor::getJavaScriptContext() {
  return runtime_.get();
}

bool JSIExecutor::isInspectable() {
  return runtime_->isInspectable();
}

void JSIExecutor::bindBridge() {
  std::call_once(bindFlag_, [this] {
    SystraceSection s("JSIExecutor::bindBridge (once)");
    Value batchedBridgeValue =
        runtime_->global().getProperty(*runtime_, "__fbBatchedBridge");
    if (batchedBridgeValue.isUndefined()) {
      throw JSINativeException(
                               "Could not get BatchedBridge, make sure your bundle is packaged correctly");
    }

    Object batchedBridge = batchedBridgeValue.asObject(*runtime_);
    callFunctionReturnFlushedQueue_ = batchedBridge.getPropertyAsFunction(
        *runtime_, "callFunctionReturnFlushedQueue");
    invokeCallbackAndReturnFlushedQueue_ = batchedBridge.getPropertyAsFunction(
        *runtime_, "invokeCallbackAndReturnFlushedQueue");
    flushedQueue_ =
        batchedBridge.getPropertyAsFunction(*runtime_, "flushedQueue");
    callFunctionReturnResultAndFlushedQueue_ =
        batchedBridge.getPropertyAsFunction(
            *runtime_, "callFunctionReturnResultAndFlushedQueue");
  });
}

void JSIExecutor::callNativeModules(const Value& queue, bool isEndOfBatch) {
  SystraceSection s("JSIExecutor::callNativeModules");
  // If this fails, you need to pass a fully functional delegate with a
  // module registry to the factory/ctor.
  CHECK(delegate_) << "Attempting to use native modules without a delegate";
#if 0 // maybe useful for debugging
  std::string json = runtime_->global().getPropertyAsObject(*runtime_, "JSON")
    .getPropertyAsFunction(*runtime_, "stringify").call(*runtime_, queue)
    .getString(*runtime_).utf8(*runtime_);
#endif
  delegate_->callNativeModules(
      *this, dynamicFromValue(*runtime_, queue), isEndOfBatch);
}

void JSIExecutor::flush() {
  SystraceSection s("JSIExecutor::flush");
  if (flushedQueue_) {
    callNativeModules(flushedQueue_->call(*runtime_), true);
    return;
  }

  // When a native module is called from JS, BatchedBridge.enqueueNativeCall()
  // is invoked.  For that to work, require('BatchedBridge') has to be called,
  // and when that happens, __fbBatchedBridge is set as a side effect.
  Value batchedBridge =
      runtime_->global().getProperty(*runtime_, "__fbBatchedBridge");
  // So here, if __fbBatchedBridge doesn't exist, then we know no native calls
  // have happened, and we were able to determine this without forcing
  // BatchedBridge to be loaded as a side effect.
  if (!batchedBridge.isUndefined()) {
    // If calls were made, we bind to the JS bridge methods, and use them to
    // get the pending queue of native calls.
    bindBridge();
    callNativeModules(flushedQueue_->call(*runtime_), true);
  } else if (delegate_) {
    // If we have a delegate, we need to call it; we pass a null list to
    // callNativeModules, since we know there are no native calls, without
    // calling into JS again.  If no calls were made and there's no delegate,
    // nothing happens, which is correct.
    callNativeModules(nullptr, true);
  }
}

Value JSIExecutor::nativeRequire(const Value* args, size_t count) {
  if (count > 2 || count == 0) {
    throw std::invalid_argument("Got wrong number of args");
  }

  uint32_t moduleId = folly::to<uint32_t>(args[0].getNumber());
  uint32_t bundleId = count == 2 ? folly::to<uint32_t>(args[1].getNumber()) : 0;
  auto module = bundleRegistry_->getModule(bundleId, moduleId);

  runtime_->evaluateJavaScript(
      std::make_unique<StringBuffer>(module.code), module.name);
  return facebook::jsi::Value();
}

Value JSIExecutor::nativeCallSyncHook(const Value* args, size_t count) {
  if (count != 3) {
    throw std::invalid_argument("nativeCallSyncHook arg count must be 3");
  }

  if (!args[2].asObject(*runtime_).isArray(*runtime_)) {
    throw std::invalid_argument(
        folly::to<std::string>("method parameters should be array"));
  }

  MethodCallResult result = delegate_->callSerializableNativeHook(
      *this,
      static_cast<unsigned int>(args[0].getNumber()), // moduleId
      static_cast<unsigned int>(args[1].getNumber()), // methodId
      dynamicFromValue(*runtime_, args[2])); // args

  if (!result.hasValue()) {
    return Value::undefined();
  }
  return valueFromDynamic(*runtime_, result.value());
}

} // namespace react
} // namespace facebook
<|endoftext|>


<commit_before>#ifndef GLM_FORCE_RADIANS
#define GLM_FORCE_RADIANS
#define DEGREES_TO_RADIANS(x) (x * PI / 180.0f)
#endif

#include "bmp_heightmap_loader.hpp"
#include "code/ylikuutio/triangulation/quad_triangulation.hpp"
#include "code/ylikuutio/common/globals.hpp"
#include "code/ylikuutio/common/global_variables.hpp"

// Include GLM
#ifndef __GLM_GLM_HPP_INCLUDED
#define __GLM_GLM_HPP_INCLUDED
#include <glm/glm.hpp> // glm
#endif

// Include standard headers
#include <cmath>    // NAN, std::isnan, std::pow
#include <cstdio>   // std::FILE, std::fclose, std::fopen, std::fread, std::getchar, std::printf etc.
#include <cstring>  // std::memcmp, std::strcmp, std::strlen, std::strncmp
#include <iostream> // std::cout, std::cin, std::cerr
#include <stdint.h> // uint32_t etc.
#include <string>   // std::string
#include <vector>   // std::vector

namespace loaders
{
    bool load_BMP_world(
            std::string image_path,
            std::vector<glm::vec3>& out_vertices,
            std::vector<glm::vec2>& out_UVs,
            std::vector<glm::vec3>& out_normals,
            uint32_t &image_width,
            uint32_t &image_height,
            std::string color_channel,
            uint32_t x_step,
            uint32_t z_step,
            std::string triangulation_type)
    {
        std::cout << "Loading BMP file " << image_path << " ...\n";

        uint8_t header_size = 54;

        // Data read from the header of the BMP file
        uint8_t header[header_size];
        uint32_t image_size;
        // Actual RGB image data.
        uint8_t *image_data;

        // Open the file
        const char* char_image_path = image_path.c_str();
        std::FILE* file = std::fopen(char_image_path, "rb");
        if (!file)
        {
            std::cerr << image_path << " could not be opened.\n";
            return false;
        }

        // Read the header, i.e. the 54 first bytes

        // If less than 54 bytes are read, it's a problem.
        if (std::fread(header, 1, header_size, file) != header_size)
        {
            std::cerr << "not a correct BMP file.\n";
            std::fclose(file);
            return false;
        }

        // The start offset of pixel array in file.
        uint32_t pixel_array_start_offset = header[0x0a];

        // A BMP files always begins with "BM"
        if ((header[0] != 'B') || (header[1] != 'M'))
        {
            std::cerr << "not a correct BMP file.\n";
            std::fclose(file);
            return false;
        }

        // Make sure this is a 24bpp file
        if (*(uint32_t*) &header[0x1e] != 0)
        {
            std::cerr << "not a correct BMP file.\n";
            std::fclose(file);
            return false;
        }

        if (*(uint32_t*) &header[0x1c] != 24)
        {
            std::cerr << "not a correct BMP file.\n";
            std::fclose(file);
            return false;
        }

        // Read the information about the image
        image_size = *(uint32_t*) &header[0x22];
        image_width = *(uint32_t*) &header[0x12];
        image_height = *(uint32_t*) &header[0x16];

        // Define world size.
        uint32_t world_size = image_width * image_height;

        // Some BMP files are misformatted, guess missing information
        if (image_size == 0)
        {
            image_size = image_width * image_height * 3; // 3 : one byte for each Red, Green and Blue component
        }

        // Create a buffer.
        image_data = new uint8_t[image_size];

        if (image_data == nullptr)
        {
            std::cerr << "Reserving memory for image data failed.\n";
            std::fclose(file);
            return false;
        }

        // Move file pointer to the start of the pixel array.
        if (std::fseek(file, pixel_array_start_offset, SEEK_SET) != 0)
        {
            std::cerr << "Moving BMP file position indicator failed.\n";
            std::fclose(file);
            delete image_data;
            return false;
        }

        // Read the actual image data from the file into the buffer.
        if (std::fread(image_data, 1, image_size, file) != image_size)
        {
            std::cerr << "Reading image data from file failed.\n";
            std::fclose(file);
            delete image_data;
            return false;
        }

        // Everything is in memory now, the file can be closed
        std::fclose(file);

        uint8_t *image_pointer;
        image_pointer = image_data;

        float* vertex_data;
        vertex_data = new float[world_size];

        if (vertex_data == nullptr)
        {
            std::cerr << "Reserving memory for vertex data failed.\n";
            delete image_data;
            return false;
        }

        float* vertex_pointer;
        vertex_pointer = vertex_data;

        const char* char_color_channel = color_channel.c_str();

        // start processing image_data.
        for (int32_t z = image_height - 1; z >= 0; z--)
        {
            uint32_t image_width_in_bytes = 3 * image_width;
            image_pointer = image_data + z * image_width_in_bytes;

            for (int32_t x = 0; x < image_width; x++)
            {
                uint32_t y;

                if (std::strcmp(char_color_channel, "blue") == 0)
                {
                    y = static_cast<float>(*image_pointer);       // y-coordinate is the blue (B) value.
                }
                else if (std::strcmp(char_color_channel, "green") == 0)
                {
                    y = static_cast<float>(*(image_pointer + 1)); // y-coordinate is the green (G) value.
                }
                else if (std::strcmp(char_color_channel, "red") == 0)
                {
                    y = static_cast<float>(*(image_pointer + 2)); // y-coordinate is the red (R) value.
                }
                // y-coordinate is the mean of R, G, & B.
                else if ((std::strcmp(char_color_channel, "mean") == 0) || (std::strcmp(char_color_channel, "all") == 0))
                {
                    y = (static_cast<float>(*image_pointer) + static_cast<float>(*(image_pointer + 1)) + static_cast<float>(*(image_pointer + 2))) / 3.0f;
                }
                else
                {
                    std::cerr << "invalid color channel!\n";
                    delete image_data;
                    delete vertex_data;
                    return false;
                }

                *vertex_pointer++ = y;
                image_pointer += 3; // R, G, & B.
            }
        }

        delete image_data;

        std::cout << "color channel in use: " << color_channel << "\n";

        TriangulateQuadsStruct triangulate_quads_struct;
        triangulate_quads_struct.image_width = image_width;
        triangulate_quads_struct.image_height = image_height;
        triangulate_quads_struct.x_step = x_step;
        triangulate_quads_struct.z_step = z_step;
        triangulate_quads_struct.triangulation_type = triangulation_type;
        triangulate_quads_struct.sphere_radius = NAN;
        triangulate_quads_struct.spherical_world_struct = SphericalWorldStruct(); // not used, but is needed in the function call.

        bool result = geometry::triangulate_quads(vertex_data, triangulate_quads_struct, out_vertices, out_UVs, out_normals);
        delete vertex_data;
        return result;
    }
}
<commit_msg>Bugfix: image width and image height are signed values in BMP files.<commit_after>#ifndef GLM_FORCE_RADIANS
#define GLM_FORCE_RADIANS
#define DEGREES_TO_RADIANS(x) (x * PI / 180.0f)
#endif

#include "bmp_heightmap_loader.hpp"
#include "code/ylikuutio/triangulation/quad_triangulation.hpp"
#include "code/ylikuutio/common/globals.hpp"
#include "code/ylikuutio/common/global_variables.hpp"

// Include GLM
#ifndef __GLM_GLM_HPP_INCLUDED
#define __GLM_GLM_HPP_INCLUDED
#include <glm/glm.hpp> // glm
#endif

// Include standard headers
#include <cmath>    // NAN, std::isnan, std::pow
#include <cstdio>   // std::FILE, std::fclose, std::fopen, std::fread, std::getchar, std::printf etc.
#include <cstring>  // std::memcmp, std::strcmp, std::strlen, std::strncmp
#include <iostream> // std::cout, std::cin, std::cerr
#include <stdint.h> // uint32_t etc.
#include <string>   // std::string
#include <vector>   // std::vector

namespace loaders
{
    bool load_BMP_world(
            std::string image_path,
            std::vector<glm::vec3>& out_vertices,
            std::vector<glm::vec2>& out_UVs,
            std::vector<glm::vec3>& out_normals,
            uint32_t &image_width,
            uint32_t &image_height,
            std::string color_channel,
            uint32_t x_step,
            uint32_t z_step,
            std::string triangulation_type)
    {
        std::cout << "Loading BMP file " << image_path << " ...\n";

        uint8_t header_size = 54;

        // Data read from the header of the BMP file
        uint8_t header[header_size];
        uint32_t image_size;
        // Actual RGB image data.
        uint8_t *image_data;

        // Open the file
        const char* char_image_path = image_path.c_str();
        std::FILE* file = std::fopen(char_image_path, "rb");
        if (!file)
        {
            std::cerr << image_path << " could not be opened.\n";
            return false;
        }

        // Read the header, i.e. the 54 first bytes

        // If less than 54 bytes are read, it's a problem.
        if (std::fread(header, 1, header_size, file) != header_size)
        {
            std::cerr << "not a correct BMP file.\n";
            std::fclose(file);
            return false;
        }

        // The start offset of pixel array in file.
        uint32_t pixel_array_start_offset = header[0x0a];

        // A BMP files always begins with "BM"
        if ((header[0] != 'B') || (header[1] != 'M'))
        {
            std::cerr << "not a correct BMP file.\n";
            std::fclose(file);
            return false;
        }

        // Make sure this is a 24bpp file
        if (*(uint32_t*) &header[0x1e] != 0)
        {
            std::cerr << "not a correct BMP file.\n";
            std::fclose(file);
            return false;
        }

        if (*(uint32_t*) &header[0x1c] != 24)
        {
            std::cerr << "not a correct BMP file.\n";
            std::fclose(file);
            return false;
        }

        // Read the information about the image
        image_size = *(uint32_t*) &header[0x22];
        image_width = *(int32_t*) &header[0x12];
        image_height = *(int32_t*) &header[0x16];

        // Define world size.
        uint32_t world_size = image_width * image_height;

        // Some BMP files are misformatted, guess missing information
        if (image_size == 0)
        {
            image_size = image_width * image_height * 3; // 3 : one byte for each Red, Green and Blue component
        }

        // Create a buffer.
        image_data = new uint8_t[image_size];

        if (image_data == nullptr)
        {
            std::cerr << "Reserving memory for image data failed.\n";
            std::fclose(file);
            return false;
        }

        // Move file pointer to the start of the pixel array.
        if (std::fseek(file, pixel_array_start_offset, SEEK_SET) != 0)
        {
            std::cerr << "Moving BMP file position indicator failed.\n";
            std::fclose(file);
            delete image_data;
            return false;
        }

        // Read the actual image data from the file into the buffer.
        if (std::fread(image_data, 1, image_size, file) != image_size)
        {
            std::cerr << "Reading image data from file failed.\n";
            std::fclose(file);
            delete image_data;
            return false;
        }

        // Everything is in memory now, the file can be closed
        std::fclose(file);

        uint8_t *image_pointer;
        image_pointer = image_data;

        float* vertex_data;
        vertex_data = new float[world_size];

        if (vertex_data == nullptr)
        {
            std::cerr << "Reserving memory for vertex data failed.\n";
            delete image_data;
            return false;
        }

        float* vertex_pointer;
        vertex_pointer = vertex_data;

        const char* char_color_channel = color_channel.c_str();

        // start processing image_data.
        for (int32_t z = image_height - 1; z >= 0; z--)
        {
            uint32_t image_width_in_bytes = 3 * image_width;
            image_pointer = image_data + z * image_width_in_bytes;

            for (int32_t x = 0; x < image_width; x++)
            {
                uint32_t y;

                if (std::strcmp(char_color_channel, "blue") == 0)
                {
                    y = static_cast<float>(*image_pointer);       // y-coordinate is the blue (B) value.
                }
                else if (std::strcmp(char_color_channel, "green") == 0)
                {
                    y = static_cast<float>(*(image_pointer + 1)); // y-coordinate is the green (G) value.
                }
                else if (std::strcmp(char_color_channel, "red") == 0)
                {
                    y = static_cast<float>(*(image_pointer + 2)); // y-coordinate is the red (R) value.
                }
                // y-coordinate is the mean of R, G, & B.
                else if ((std::strcmp(char_color_channel, "mean") == 0) || (std::strcmp(char_color_channel, "all") == 0))
                {
                    y = (static_cast<float>(*image_pointer) + static_cast<float>(*(image_pointer + 1)) + static_cast<float>(*(image_pointer + 2))) / 3.0f;
                }
                else
                {
                    std::cerr << "invalid color channel!\n";
                    delete image_data;
                    delete vertex_data;
                    return false;
                }

                *vertex_pointer++ = y;
                image_pointer += 3; // R, G, & B.
            }
        }

        delete image_data;

        std::cout << "color channel in use: " << color_channel << "\n";

        TriangulateQuadsStruct triangulate_quads_struct;
        triangulate_quads_struct.image_width = image_width;
        triangulate_quads_struct.image_height = image_height;
        triangulate_quads_struct.x_step = x_step;
        triangulate_quads_struct.z_step = z_step;
        triangulate_quads_struct.triangulation_type = triangulation_type;
        triangulate_quads_struct.sphere_radius = NAN;
        triangulate_quads_struct.spherical_world_struct = SphericalWorldStruct(); // not used, but is needed in the function call.

        bool result = geometry::triangulate_quads(vertex_data, triangulate_quads_struct, out_vertices, out_UVs, out_normals);
        delete vertex_data;
        return result;
    }
}
<|endoftext|>


<commit_before>// Ylikuutio - A 3D game and simulation engine.
//
// Copyright (C) 2015-2020 Antti Nuortimo.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

#ifndef __COMPUTE_TASK_STRUCT_HPP_INCLUDED
#define __COMPUTE_TASK_STRUCT_HPP_INCLUDED

#include "pre_iterate_callback.hpp"
#include "post_iterate_callback.hpp"
#include "code/ylikuutio/common/any_value.hpp"

// Include GLEW
#include "code/ylikuutio/opengl/ylikuutio_glew.hpp" // GLfloat, GLuint etc.

// Include standard headers
#include <cstddef>  // std::size_t
#include <limits>   // std::numeric_limits
#include <memory>   // std::make_shared, std::shared_ptr
#include <string>   // std::string

namespace yli::callback
{
    class CallbackEngine;
}

namespace yli::ontology
{
    class Shader;

    struct ComputeTaskStruct
    {
        ComputeTaskStruct()
            : parent(nullptr),
            left_filler_vector_any_value(nullptr),
            right_filler_vector_any_value(nullptr),
            end_condition_callback_engine(nullptr),
            n_max_iterations(1),                                     // By default execute GLSL shader exactly once (do not iterate further).
            compute_taskID(std::numeric_limits<std::size_t>::max()), // `std::numeric_limits<std::size_t>::max()` means that `compute_taskID` is not defined.
            texture_width(0),
            texture_height(0),
            texture_depth(0),
            n_index_characters(4),
            format(GL_RGB),
            internal_format(GL_INVALID_ENUM), // If `internal_format` is left to `GL_INVALID_ENUM`, `format` is used as the internal format.
            output_format(GL_INVALID_ENUM),   // If `output_format` is left to `GL_INVALID_ENUM`, `format` is used as the output format.
            type(GL_UNSIGNED_BYTE),
            should_ylikuutio_save_intermediate_results(false),
            should_ylikuutio_flip_texture(true),
            preiterate_callback(nullptr),
            postiterate_callback(nullptr)
        {
            // constructor.
        }

        std::string texture_file_format; // Type of the texture file. supported file formats so far: `"bmp"`/`"BMP"`, `"csv"`/`"CSV"`.
        std::string texture_filename;    // Filename of the model file.
        std::string output_filename;     // Filename of the output file.
        yli::ontology::Shader* parent;   // Pointer to the `Shader`.
        std::shared_ptr<yli::common::AnyValue> left_filler_vector_any_value;
        std::shared_ptr<yli::common::AnyValue> right_filler_vector_any_value;
        std::shared_ptr<yli::callback::CallbackEngine> end_condition_callback_engine;
        std::size_t n_max_iterations;
        std::size_t compute_taskID;
        std::size_t texture_width;
        std::size_t texture_height;
        std::size_t texture_depth;
        std::size_t n_index_characters;  // For intermediate results' filenames.
        GLenum format;
        GLenum internal_format;
        GLenum output_format;
        GLenum type;
        bool should_ylikuutio_save_intermediate_results;
        bool should_ylikuutio_flip_texture;
        PreIterateCallback preiterate_callback;
        PostIterateCallback postiterate_callback;
    };
}

#endif
<commit_msg>`yli::ontology::ComputeTaskStruct`: remove obsolete member variables.<commit_after>// Ylikuutio - A 3D game and simulation engine.
//
// Copyright (C) 2015-2020 Antti Nuortimo.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

#ifndef __COMPUTE_TASK_STRUCT_HPP_INCLUDED
#define __COMPUTE_TASK_STRUCT_HPP_INCLUDED

#include "pre_iterate_callback.hpp"
#include "post_iterate_callback.hpp"
#include "code/ylikuutio/common/any_value.hpp"

// Include GLEW
#include "code/ylikuutio/opengl/ylikuutio_glew.hpp" // GLfloat, GLuint etc.

// Include standard headers
#include <cstddef>  // std::size_t
#include <limits>   // std::numeric_limits
#include <memory>   // std::make_shared, std::shared_ptr
#include <string>   // std::string

namespace yli::callback
{
    class CallbackEngine;
}

namespace yli::ontology
{
    class Shader;

    struct ComputeTaskStruct
    {
        ComputeTaskStruct()
            : parent(nullptr),
            left_filler_vector_any_value(nullptr),
            right_filler_vector_any_value(nullptr),
            end_condition_callback_engine(nullptr),
            n_max_iterations(1),                                     // By default execute GLSL shader exactly once (do not iterate further).
            compute_taskID(std::numeric_limits<std::size_t>::max()), // `std::numeric_limits<std::size_t>::max()` means that `compute_taskID` is not defined.
            texture_width(0),
            texture_height(0),
            n_index_characters(4),
            format(GL_RGB),
            internal_format(GL_INVALID_ENUM), // If `internal_format` is left to `GL_INVALID_ENUM`, `format` is used as the internal format.
            output_format(GL_INVALID_ENUM),   // If `output_format` is left to `GL_INVALID_ENUM`, `format` is used as the output format.
            type(GL_UNSIGNED_BYTE),
            should_ylikuutio_save_intermediate_results(false),
            should_ylikuutio_flip_texture(true),
            preiterate_callback(nullptr),
            postiterate_callback(nullptr)
        {
            // constructor.
        }

        std::string texture_file_format; // Type of the texture file. supported file formats so far: `"bmp"`/`"BMP"`, `"csv"`/`"CSV"`.
        std::string texture_filename;    // Filename of the model file.
        std::string output_filename;     // Filename of the output file.
        yli::ontology::Shader* parent;   // Pointer to the `Shader`.
        std::shared_ptr<yli::common::AnyValue> left_filler_vector_any_value;
        std::shared_ptr<yli::common::AnyValue> right_filler_vector_any_value;
        std::shared_ptr<yli::callback::CallbackEngine> end_condition_callback_engine;
        std::size_t n_max_iterations;
        std::size_t compute_taskID;
        std::size_t texture_width;
        std::size_t texture_height;
        std::size_t n_index_characters;  // For intermediate results' filenames.
        GLenum format;
        GLenum internal_format;
        GLenum output_format;
        GLenum type;
        bool should_ylikuutio_save_intermediate_results;
        bool should_ylikuutio_flip_texture;
        PreIterateCallback preiterate_callback;
        PostIterateCallback postiterate_callback;
    };
}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2014-2020 Real Logic Limited.
 *
 * 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
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <array>
#include <gtest/gtest.h>
#include <util/Exceptions.h>
#include <util/Index.h>
#include <util/BitUtil.h>
#include <concurrent/AtomicBuffer.h>
#include <command/ImageMessageFlyweight.h>
#include <command/ImageBuffersReadyFlyweight.h>
#include <command/RemoveMessageFlyweight.h>
#include <command/SubscriptionMessageFlyweight.h>
#include <command/PublicationMessageFlyweight.h>
#include <command/PublicationBuffersReadyFlyweight.h>
#include <command/CounterMessageFlyweight.h>

using namespace aeron::util;
using namespace aeron::command;
using namespace aeron::concurrent;

static std::array<std::uint8_t, 1024> testBuffer;

static void clearBuffer()
{
    testBuffer.fill(0);
}

TEST (commandTests, testInstantiateFlyweights)
{
    clearBuffer();
    AtomicBuffer ab (&testBuffer[0], testBuffer.size());
    const index_t BASE_OFFSET = 256;

    std::string channelData = "channelData";

    ASSERT_NO_THROW({
        ImageMessageFlyweight cmd(ab, BASE_OFFSET);
    });

    ASSERT_NO_THROW({
        ImageBuffersReadyFlyweight cmd(ab, BASE_OFFSET);
    });

    ASSERT_NO_THROW({
        RemoveMessageFlyweight cmd(ab, BASE_OFFSET);
    });

    ASSERT_NO_THROW({
        SubscriptionMessageFlyweight cmd(ab, BASE_OFFSET);
    });

    ASSERT_NO_THROW({
        PublicationMessageFlyweight cmd(ab, BASE_OFFSET);
    });

    ASSERT_NO_THROW({
        PublicationBuffersReadyFlyweight cmd(ab, BASE_OFFSET);
    });

    ASSERT_NO_THROW({
        CounterMessageFlyweight cmd(ab, BASE_OFFSET);
    });
}

TEST (commandTests, testImageMessageFlyweight)
{
    clearBuffer();
    AtomicBuffer ab (&testBuffer[0], testBuffer.size());
    const index_t BASE_OFFSET = 256;

    std::string channelData = "channelData";

    ASSERT_NO_THROW({
        ImageMessageFlyweight cmd (ab, BASE_OFFSET);
        cmd.correlationId(1).subscriptionRegistrationId(2).streamId(3).channel(channelData);

        ASSERT_EQ(ab.getInt64(BASE_OFFSET + 0), 1);
        ASSERT_EQ(ab.getInt64(BASE_OFFSET + 8), 2);
        ASSERT_EQ(ab.getInt32(BASE_OFFSET + 16), 3);
        ASSERT_EQ(ab.getString(BASE_OFFSET + 20), channelData);

        ASSERT_EQ(cmd.correlationId(), 1);
        ASSERT_EQ(cmd.streamId(), 3);
        ASSERT_EQ(cmd.channel(), channelData);

        ASSERT_EQ(cmd.length(), static_cast<int>(20 + sizeof(std::int32_t) + channelData.length()));
    });
}

TEST (commandTests, testPublicationReadyFlyweight)
{
    clearBuffer();
    AtomicBuffer ab(&testBuffer[0], testBuffer.size());
    const index_t BASE_OFFSET = 256;

    std::string logFileNameData = "logfilenamedata";

    ASSERT_NO_THROW({
        PublicationBuffersReadyFlyweight cmd(ab, BASE_OFFSET);

        cmd.correlationId(-1).registrationId(1).streamId(0x01010101).sessionId(0x02020202).positionLimitCounterId(10);
        cmd.channelStatusIndicatorId(11);
        cmd.logFileName(logFileNameData);

        ASSERT_EQ(ab.getInt64(BASE_OFFSET + 0), -1);
        ASSERT_EQ(ab.getInt64(BASE_OFFSET + 8), 1);
        ASSERT_EQ(ab.getInt32(BASE_OFFSET + 16), 0x02020202);
        ASSERT_EQ(ab.getInt32(BASE_OFFSET + 20), 0x01010101);
        ASSERT_EQ(ab.getInt32(BASE_OFFSET + 24), 10);
        ASSERT_EQ(ab.getInt32(BASE_OFFSET + 28), 11);
        ASSERT_EQ(ab.getInt32(BASE_OFFSET + 32), static_cast<int>(logFileNameData.length()));
        ASSERT_EQ(ab.getString(BASE_OFFSET + 32), logFileNameData);

        ASSERT_EQ(cmd.correlationId(), -1);
        ASSERT_EQ(cmd.registrationId(), 1);
        ASSERT_EQ(cmd.streamId(), 0x01010101);
        ASSERT_EQ(cmd.sessionId(), 0x02020202);
        ASSERT_EQ(cmd.positionLimitCounterId(), 10);
        ASSERT_EQ(cmd.logFileName(), logFileNameData);

        ASSERT_EQ(cmd.length(), static_cast<int>(32 + sizeof(std::int32_t) + logFileNameData.length()));
    });
}

TEST (commandTests, testImageBuffersReadyFlyweight)
{
    clearBuffer();
    AtomicBuffer ab(&testBuffer[0], testBuffer.size());
    const index_t BASE_OFFSET = 0;

    std::string logFileNameData = "logfilenamedata";
    std::string sourceInfoData = "sourceinfodata";

    ASSERT_NO_THROW({
        ImageBuffersReadyFlyweight cmd(ab, BASE_OFFSET);

        cmd.correlationId(-1);

        cmd.sessionId(0x02020202)
            .streamId(0x01010101)
            .subscriberRegistrationId(2)
            .subscriberPositionId(1)
            .logFileName(logFileNameData)
            .sourceIdentity(sourceInfoData);

        ASSERT_EQ(ab.getInt64(BASE_OFFSET + 0), -1);
        ASSERT_EQ(ab.getInt32(BASE_OFFSET + 8), 0x02020202);
        ASSERT_EQ(ab.getInt32(BASE_OFFSET + 12), 0x01010101);

        ASSERT_EQ(ab.getInt64(BASE_OFFSET + 16), 2);
        ASSERT_EQ(ab.getInt32(BASE_OFFSET + 24), 1);

        const index_t startOfLogFileName = BASE_OFFSET + 28;
        ASSERT_EQ(ab.getStringLength(startOfLogFileName), static_cast<int>(logFileNameData.length()));
        ASSERT_EQ(ab.getString(startOfLogFileName), logFileNameData);

        const index_t startOfSourceIdentity = startOfLogFileName + 4 + (index_t)logFileNameData.length();
        const index_t startOfSourceIdentityAligned = BitUtil::align(startOfSourceIdentity, 4);
        ASSERT_EQ(ab.getStringLength(startOfSourceIdentityAligned), static_cast<int>(sourceInfoData.length()));
        ASSERT_EQ(ab.getString(startOfSourceIdentityAligned), sourceInfoData);

        ASSERT_EQ(cmd.correlationId(), -1);
        ASSERT_EQ(cmd.sessionId(), 0x02020202);
        ASSERT_EQ(cmd.streamId(), 0x01010101);
        ASSERT_EQ(cmd.subscriptionRegistrationId(), 2);
        ASSERT_EQ(cmd.subscriberPositionId(), 1);
        ASSERT_EQ(cmd.logFileName(), logFileNameData);
        ASSERT_EQ(cmd.sourceIdentity(), sourceInfoData);

        int expectedLength = static_cast<int>(
            startOfSourceIdentityAligned + sizeof(std::int32_t) + sourceInfoData.length());

        ASSERT_EQ(cmd.length(), expectedLength);
    });
}

TEST (commandTests, testCounterMessageFlyweight)
{
    clearBuffer();
    AtomicBuffer ab(&testBuffer[0], testBuffer.size());

    std::array<std::uint8_t, 29> keyBuffer = {};
    keyBuffer.fill(1);
    std::string label = "this is very cool label";

    ASSERT_NO_THROW({
        CounterMessageFlyweight cmd(ab, 16);

        cmd.correlationId(42).clientId(-9);

        cmd.typeId(36)
            .keyBuffer(keyBuffer.data(), keyBuffer.size())
            .label(label);

        ASSERT_EQ(cmd.correlationId(), 42);
        ASSERT_EQ(cmd.clientId(), -9);
        ASSERT_EQ(cmd.typeId(), 36);
        ASSERT_EQ(cmd.keyLength(), 29);
        const uint8_t* srcBuffer = keyBuffer.data();
        const uint8_t* writtenBuffer = cmd.keyBuffer();
        ASSERT_TRUE( 0 == std::memcmp( srcBuffer, writtenBuffer, sizeof( srcBuffer ) ) );
        ASSERT_EQ(cmd.labelLength(), static_cast<int>(label.size()));
        ASSERT_EQ(cmd.label(), label);

        const int expectedLength = static_cast<int>(
                sizeof(std::int64_t) * 2 + sizeof(std::int32_t) * 2 + BitUtil::align(29, 4) + sizeof(std::int32_t) + label.length());

        ASSERT_EQ(cmd.length(), expectedLength);
    });
}
<commit_msg>[C++] Fix Flyweight#getBytes to add `m_baseOffset`<commit_after>/*
 * Copyright 2014-2020 Real Logic Limited.
 *
 * 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
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <array>
#include <cstring>
#include <gtest/gtest.h>
#include <util/Index.h>
#include <util/BitUtil.h>
#include <concurrent/AtomicBuffer.h>
#include <command/ImageMessageFlyweight.h>
#include <command/ImageBuffersReadyFlyweight.h>
#include <command/RemoveMessageFlyweight.h>
#include <command/SubscriptionMessageFlyweight.h>
#include <command/PublicationMessageFlyweight.h>
#include <command/PublicationBuffersReadyFlyweight.h>
#include <command/CounterMessageFlyweight.h>

using namespace aeron::util;
using namespace aeron::command;
using namespace aeron::concurrent;

static std::array<std::uint8_t, 1024> testBuffer;

static void clearBuffer()
{
    testBuffer.fill(0);
}

TEST (commandTests, testInstantiateFlyweights)
{
    clearBuffer();
    AtomicBuffer ab (&testBuffer[0], testBuffer.size());
    const index_t BASE_OFFSET = 256;

    std::string channelData = "channelData";

    ASSERT_NO_THROW({
        ImageMessageFlyweight cmd(ab, BASE_OFFSET);
    });

    ASSERT_NO_THROW({
        ImageBuffersReadyFlyweight cmd(ab, BASE_OFFSET);
    });

    ASSERT_NO_THROW({
        RemoveMessageFlyweight cmd(ab, BASE_OFFSET);
    });

    ASSERT_NO_THROW({
        SubscriptionMessageFlyweight cmd(ab, BASE_OFFSET);
    });

    ASSERT_NO_THROW({
        PublicationMessageFlyweight cmd(ab, BASE_OFFSET);
    });

    ASSERT_NO_THROW({
        PublicationBuffersReadyFlyweight cmd(ab, BASE_OFFSET);
    });

    ASSERT_NO_THROW({
        CounterMessageFlyweight cmd(ab, BASE_OFFSET);
    });
}

TEST (commandTests, testImageMessageFlyweight)
{
    clearBuffer();
    AtomicBuffer ab (&testBuffer[0], testBuffer.size());
    const index_t BASE_OFFSET = 256;

    std::string channelData = "channelData";

    ASSERT_NO_THROW({
        ImageMessageFlyweight cmd (ab, BASE_OFFSET);
        cmd.correlationId(1).subscriptionRegistrationId(2).streamId(3).channel(channelData);

        ASSERT_EQ(ab.getInt64(BASE_OFFSET + 0), 1);
        ASSERT_EQ(ab.getInt64(BASE_OFFSET + 8), 2);
        ASSERT_EQ(ab.getInt32(BASE_OFFSET + 16), 3);
        ASSERT_EQ(ab.getString(BASE_OFFSET + 20), channelData);

        ASSERT_EQ(cmd.correlationId(), 1);
        ASSERT_EQ(cmd.streamId(), 3);
        ASSERT_EQ(cmd.channel(), channelData);

        ASSERT_EQ(cmd.length(), static_cast<int>(20 + sizeof(std::int32_t) + channelData.length()));
    });
}

TEST (commandTests, testPublicationReadyFlyweight)
{
    clearBuffer();
    AtomicBuffer ab(&testBuffer[0], testBuffer.size());
    const index_t BASE_OFFSET = 256;

    std::string logFileNameData = "logfilenamedata";

    ASSERT_NO_THROW({
        PublicationBuffersReadyFlyweight cmd(ab, BASE_OFFSET);

        cmd.correlationId(-1).registrationId(1).streamId(0x01010101).sessionId(0x02020202).positionLimitCounterId(10);
        cmd.channelStatusIndicatorId(11);
        cmd.logFileName(logFileNameData);

        ASSERT_EQ(ab.getInt64(BASE_OFFSET + 0), -1);
        ASSERT_EQ(ab.getInt64(BASE_OFFSET + 8), 1);
        ASSERT_EQ(ab.getInt32(BASE_OFFSET + 16), 0x02020202);
        ASSERT_EQ(ab.getInt32(BASE_OFFSET + 20), 0x01010101);
        ASSERT_EQ(ab.getInt32(BASE_OFFSET + 24), 10);
        ASSERT_EQ(ab.getInt32(BASE_OFFSET + 28), 11);
        ASSERT_EQ(ab.getInt32(BASE_OFFSET + 32), static_cast<int>(logFileNameData.length()));
        ASSERT_EQ(ab.getString(BASE_OFFSET + 32), logFileNameData);

        ASSERT_EQ(cmd.correlationId(), -1);
        ASSERT_EQ(cmd.registrationId(), 1);
        ASSERT_EQ(cmd.streamId(), 0x01010101);
        ASSERT_EQ(cmd.sessionId(), 0x02020202);
        ASSERT_EQ(cmd.positionLimitCounterId(), 10);
        ASSERT_EQ(cmd.logFileName(), logFileNameData);

        ASSERT_EQ(cmd.length(), static_cast<int>(32 + sizeof(std::int32_t) + logFileNameData.length()));
    });
}

TEST (commandTests, testImageBuffersReadyFlyweight)
{
    clearBuffer();
    AtomicBuffer ab(&testBuffer[0], testBuffer.size());
    const index_t BASE_OFFSET = 0;

    std::string logFileNameData = "logfilenamedata";
    std::string sourceInfoData = "sourceinfodata";

    ASSERT_NO_THROW({
        ImageBuffersReadyFlyweight cmd(ab, BASE_OFFSET);

        cmd.correlationId(-1);

        cmd.sessionId(0x02020202)
            .streamId(0x01010101)
            .subscriberRegistrationId(2)
            .subscriberPositionId(1)
            .logFileName(logFileNameData)
            .sourceIdentity(sourceInfoData);

        ASSERT_EQ(ab.getInt64(BASE_OFFSET + 0), -1);
        ASSERT_EQ(ab.getInt32(BASE_OFFSET + 8), 0x02020202);
        ASSERT_EQ(ab.getInt32(BASE_OFFSET + 12), 0x01010101);

        ASSERT_EQ(ab.getInt64(BASE_OFFSET + 16), 2);
        ASSERT_EQ(ab.getInt32(BASE_OFFSET + 24), 1);

        const index_t startOfLogFileName = BASE_OFFSET + 28;
        ASSERT_EQ(ab.getStringLength(startOfLogFileName), static_cast<int>(logFileNameData.length()));
        ASSERT_EQ(ab.getString(startOfLogFileName), logFileNameData);

        const index_t startOfSourceIdentity = startOfLogFileName + 4 + (index_t)logFileNameData.length();
        const index_t startOfSourceIdentityAligned = BitUtil::align(startOfSourceIdentity, 4);
        ASSERT_EQ(ab.getStringLength(startOfSourceIdentityAligned), static_cast<int>(sourceInfoData.length()));
        ASSERT_EQ(ab.getString(startOfSourceIdentityAligned), sourceInfoData);

        ASSERT_EQ(cmd.correlationId(), -1);
        ASSERT_EQ(cmd.sessionId(), 0x02020202);
        ASSERT_EQ(cmd.streamId(), 0x01010101);
        ASSERT_EQ(cmd.subscriptionRegistrationId(), 2);
        ASSERT_EQ(cmd.subscriberPositionId(), 1);
        ASSERT_EQ(cmd.logFileName(), logFileNameData);
        ASSERT_EQ(cmd.sourceIdentity(), sourceInfoData);

        int expectedLength = static_cast<int>(
            startOfSourceIdentityAligned + sizeof(std::int32_t) + sourceInfoData.length());

        ASSERT_EQ(cmd.length(), expectedLength);
    });
}

TEST (commandTests, testCounterMessageFlyweight)
{
    clearBuffer();
    AtomicBuffer ab(&testBuffer[0], testBuffer.size());

    std::array<std::uint8_t, 29> keyBuffer = {};
    keyBuffer.fill(1);
    std::string label = "this is very cool label";

    ASSERT_NO_THROW({
        CounterMessageFlyweight cmd(ab, 16);

        cmd.correlationId(42).clientId(-9);

        cmd.typeId(36)
            .keyBuffer(keyBuffer.data(), keyBuffer.size())
            .label(label);

        ASSERT_EQ(cmd.correlationId(), 42);
        ASSERT_EQ(cmd.clientId(), -9);
        ASSERT_EQ(cmd.typeId(), 36);
        ASSERT_EQ(cmd.keyLength(), 29);
        const uint8_t* srcBuffer = keyBuffer.data();
        const uint8_t* writtenBuffer = cmd.keyBuffer();
        ASSERT_TRUE( 0 == std::memcmp( srcBuffer, writtenBuffer, 29 ) );
        ASSERT_EQ(cmd.labelLength(), static_cast<int>(label.size()));
        ASSERT_EQ(cmd.label(), label);

        const int expectedLength = static_cast<int>(
                sizeof(std::int64_t) * 2 + sizeof(std::int32_t) * 2 + BitUtil::align(29, 4) + sizeof(std::int32_t) + label.length());

        ASSERT_EQ(cmd.length(), expectedLength);
    });
}
<|endoftext|>


<commit_before>#include "AsfFile.h"
#include <fstream>
#include <iostream>

/*
typedef struct _GUID {
  DWORD Data1;
  WORD  Data2;
  WORD  Data3;
  BYTE  Data4[8];
} GUID;
*/

/* Keeping the definitions in here for now.
 * In future if those are needed in more places they should be moved out to a separate header
 */

struct AsfHeader
{
	_GUID objectId;
	uint64_t objectSize;
	uint32_t numHeaderObjects;
	uint8_t reserved1; // can be ignored
	uint8_t reserved2; // != 0x02 -> "fail to source the content" -> exit
};

struct StreamFlags
{
	unsigned char streamNumber : 7;
	uint8_t reserved;
	unsigned char encrypted : 1;
};

struct StreamPropertiesObject
{
	_GUID objectId;
	uint64_t objectSize;
	_GUID streamType;
	_GUID errorCorrectionType;
	uint64_t timeOffset;
	uint32_t timeSpecificDataLength;
	uint32_t errorCorrectionDataLenght;
	StreamFlags flags;
	uint32_t reserved;
	// uint8_t* typeSpecificData;
	// uint8_t* errorCorrectionData;
};

void getHeader(std::ifstream& file, AsfHeader& header)
{
	file.read(reinterpret_cast<char*>(&header), sizeof(AsfHeader));
}

AsfFile::~AsfFile(void)
{
	close();
}

void AsfFile::open(std::string filename)
{
	// Non-mmapped file for now. Get it working first, then optimize
	_input.open(filename, std::ios::in);
	if (!_input.good()) {
		throw(std::exception("error opening file"));
	}
}

void AsfFile::process()
{
	// get header
	AsfHeader header;
	getHeader(_input, header);

	std::cout << "Header object size: " /*<< std::cout.hex*/ << header.objectSize << std::endl;

	// count streams
	// loop over streams
	//	output Type Specific Data to #.dat
	//	if Encrypted Content Flag
	//		print "stream encrypted
	//	if Stream Type == video
	//		print Compression ID
}

void AsfFile::close()
{
	// Assume any errors in the file stream have been detected earlier already
	// so that closing would always succeed. If there were an error we couldn't
	// throw an exception anyway as this would be called from a destructor and
	// throwing an exception from it would mess things up really bad
	_input.close();
}
<commit_msg>Added GUID conversion functions.<commit_after>#include "AsfFile.h"
#include <fstream>
#include <iostream>
#include <array>

/*
typedef struct _GUID {
  DWORD Data1;
  WORD  Data2;
  WORD  Data3;
  BYTE  Data4[8];
} GUID;
*/

namespace {

// Taken from http://blog.tomaka17.com/2012/09/c-converting-guid-to-string-and-vice-versa/ with slight modifications
///
std::string guidToString(GUID guid) {
	std::array<char,40> output;
	_snprintf_s(output.data(), output.size(), 40, "{%08X-%04hX-%04hX-%02X%02X-%02X%02X%02X%02X%02X%02X}", guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
	return std::string(output.data());
}

GUID stringToGUID(const std::string& guid) {
	GUID output;
	const auto ret = sscanf_s(guid.c_str(), "{%8X-%4hX-%4hX-%2hX%2hX-%2hX%2hX%2hX%2hX%2hX%2hX}", &output.Data1, &output.Data2, &output.Data3, &output.Data4[0], &output.Data4[1], &output.Data4[2], &output.Data4[3], &output.Data4[4], &output.Data4[5], &output.Data4[6], &output.Data4[7]);
	if (ret != 11)
		throw std::logic_error("Unvalid GUID, format should be {00000000-0000-0000-0000-000000000000}");
	return output;
}
///

//ASF_Index_Object	D6E229D3-35DA-11D1-9034-00A0C90349BE
//ASF_Media_Object_Index_Object	FEB103F8-12AD-4C64-840F-2A1D2F7AD48C
//ASF_Timecode_Index_Object	3CB73FD0-0C4A-4803-953D-EDF7B6228F0C

};

static const _GUID ASF_Header_Object = stringToGUID("{75B22630-668E-11CF-A6D9-00AA0062CE6C}");
static const _GUID ASF_Simple_Index_Object = stringToGUID("{33000890-E5B1-11CF-89F4-00A0C90349CB}");

/* Keeping the definitions in here for now.
 * In future if those are needed in more places they should be moved out to a separate header
 */

struct AsfHeader
{
	_GUID objectId;
	uint64_t objectSize;
	uint32_t numHeaderObjects;
	uint8_t reserved1; // can be ignored
	uint8_t reserved2; // != 0x02 -> "fail to source the content" -> exit
};

struct StreamFlags
{
	unsigned char streamNumber : 7;
	uint8_t reserved;
	unsigned char encrypted : 1;
};

struct StreamPropertiesObject
{
	_GUID objectId;
	uint64_t objectSize;
	_GUID streamType;
	_GUID errorCorrectionType;
	uint64_t timeOffset;
	uint32_t timeSpecificDataLength;
	uint32_t errorCorrectionDataLenght;
	StreamFlags flags;
	uint32_t reserved;
	// uint8_t* typeSpecificData;
	// uint8_t* errorCorrectionData;
};

void getHeader(std::ifstream& file, AsfHeader& header)
{
	file.read(reinterpret_cast<char*>(&header), sizeof(AsfHeader));
}

AsfFile::~AsfFile(void)
{
	close();
}

void AsfFile::open(std::string filename)
{
	// Non-mmapped file for now. Get it working first, then optimize
	_input.open(filename, std::ios::in);
	if (!_input.good()) {
		throw(std::exception("error opening file"));
	}
}

void AsfFile::process()
{
	// get header
	AsfHeader header;
	getHeader(_input, header);

	std::cout << "Num header objects: " /*<< std::cout.hex*/ << header.numHeaderObjects << std::endl;
	if (header.objectId != ASF_Header_Object)
		throw std::exception("File not in ASF format");
	// count streams
	// loop over streams
	//	output Type Specific Data to #.dat
	//	if Encrypted Content Flag
	//		print "stream encrypted
	//	if Stream Type == video
	//		print Compression ID
}

void AsfFile::close()
{
	// Assume any errors in the file stream have been detected earlier already
	// so that closing would always succeed. If there were an error we couldn't
	// throw an exception anyway as this would be called from a destructor and
	// throwing an exception from it would mess things up really bad
	_input.close();
}
<|endoftext|>


<commit_before>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "AssetModule.h"
#include "LocalAssetProvider.h"
#include "HttpAssetProvider.h"
#include "Framework.h"
#include "Profiler.h"
#include "EventManager.h"
#include "ServiceManager.h"
#include "CoreException.h"
#include "AssetAPI.h"

#include <QDir>

namespace Asset
{
    std::string AssetModule::type_name_static_ = "Asset";

    AssetModule::AssetModule() : IModule(type_name_static_)
    {
    }

    AssetModule::~AssetModule()
    {
    }

    void AssetModule::Initialize()
    {
        boost::shared_ptr<HttpAssetProvider> http = boost::shared_ptr<HttpAssetProvider>(new HttpAssetProvider(framework_));
        framework_->Asset()->RegisterAssetProvider(boost::dynamic_pointer_cast<IAssetProvider>(http));

        boost::shared_ptr<LocalAssetProvider> local = boost::shared_ptr<LocalAssetProvider>(new LocalAssetProvider(framework_));
        framework_->Asset()->RegisterAssetProvider(boost::dynamic_pointer_cast<IAssetProvider>(local));

        QDir dir((GuaranteeTrailingSlash(GetFramework()->GetPlatform()->GetInstallDirectory().c_str()) + "data/assets").toStdString().c_str());
        local->AddStorageDirectory(dir.absolutePath().toStdString(), "System", true);

        dir = QDir((GuaranteeTrailingSlash(GetFramework()->GetPlatform()->GetInstallDirectory().c_str()) + "jsmodules").toStdString().c_str());
        local->AddStorageDirectory(dir.absolutePath().toStdString(), "Javascript", true);

        dir = QDir((GuaranteeTrailingSlash(GetFramework()->GetPlatform()->GetInstallDirectory().c_str()) + "media").toStdString().c_str());
        local->AddStorageDirectory(dir.absolutePath().toStdString(), "Ogre Media", true);
    }

    void AssetModule::PostInitialize()
    {
        RegisterConsoleCommand(Console::CreateCommand(
            "RequestAsset", "Request asset from server. Usage: RequestAsset(uuid,assettype)",
            Console::Bind(this, &AssetModule::ConsoleRequestAsset)));

        RegisterConsoleCommand(Console::CreateCommand(
            "AddHttpStorage", "Adds a new Http asset storage to the known storages. Usage: AddHttpStorage(url, name)",
            Console::Bind(this, &AssetModule::AddHttpStorage)));

        ProcessCommandLineOptions();
    }

    void AssetModule::ProcessCommandLineOptions()
    {
        assert(framework_);

        const boost::program_options::variables_map &options = framework_->ProgramOptions();

        if (options.count("file") > 0)
        {
            std::string startup_scene_ = QString(options["file"].as<std::string>().c_str()).trimmed().toStdString();
            if (!startup_scene_.empty())
            {
                // If scene name is expressed as a full path, add it as a recursive asset source for localassetprovider
                boost::filesystem::path scenepath(startup_scene_);
                std::string dirname = scenepath.branch_path().string();
                if (!dirname.empty())
                    framework_->Asset()->GetAssetProvider<LocalAssetProvider>()->AddStorageDirectory(dirname, "Scene Local", true);
            }
        }

        if (options.count("storage") > 0)
        {
            std::string startup_scene_ = QString(options["storage"].as<std::string>().c_str()).trimmed().toStdString();
            if (!startup_scene_.empty())
            {
                // If scene name is expressed as a full path, add it as a recursive asset source for localassetprovider
                boost::filesystem::path scenepath(startup_scene_);
                std::string dirname = scenepath.branch_path().string();
                if (!dirname.empty())
                    framework_->Asset()->GetAssetProvider<LocalAssetProvider>()->AddStorageDirectory(dirname, "Scene Local", true);
            }
        }
    }

    Console::CommandResult AssetModule::ConsoleRequestAsset(const StringVector &params)
    {
        if (params.size() != 2)
            return Console::ResultFailure("Usage: RequestAsset(uuid,assettype)");

        AssetTransferPtr transfer = framework_->Asset()->RequestAsset(params[0].c_str(), params[1].c_str());
        if (transfer)
            return Console::ResultSuccess();
        else
            return Console::ResultFailure();
    }

    Console::CommandResult AssetModule::AddHttpStorage(const StringVector &params)
    {
        if (params.size() != 2)
            return Console::ResultFailure("Usage: AddHttpStorage(url, name). For example: AddHttpStorage(http://www.google.com/, google)");

        if (!framework_->Asset()->GetAssetProvider<HttpAssetProvider>())
            return Console::ResultFailure();

        framework_->Asset()->GetAssetProvider<HttpAssetProvider>()->AddStorageAddress(params[0].c_str(), params[1].c_str());
        return Console::ResultSuccess();
    }
}

extern "C" void POCO_LIBRARY_API SetProfiler(Foundation::Profiler *profiler);
void SetProfiler(Foundation::Profiler *profiler)
{
    Foundation::ProfilerSection::SetProfiler(profiler);
}

using namespace Asset;

POCO_BEGIN_MANIFEST(IModule)
    POCO_EXPORT_CLASS(AssetModule)
POCO_END_MANIFEST

<commit_msg>Make Scene Local storage the default storage.<commit_after>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "AssetModule.h"
#include "LocalAssetProvider.h"
#include "HttpAssetProvider.h"
#include "Framework.h"
#include "Profiler.h"
#include "EventManager.h"
#include "ServiceManager.h"
#include "CoreException.h"
#include "AssetAPI.h"

#include <QDir>

namespace Asset
{
    std::string AssetModule::type_name_static_ = "Asset";

    AssetModule::AssetModule() : IModule(type_name_static_)
    {
    }

    AssetModule::~AssetModule()
    {
    }

    void AssetModule::Initialize()
    {
        boost::shared_ptr<HttpAssetProvider> http = boost::shared_ptr<HttpAssetProvider>(new HttpAssetProvider(framework_));
        framework_->Asset()->RegisterAssetProvider(boost::dynamic_pointer_cast<IAssetProvider>(http));

        boost::shared_ptr<LocalAssetProvider> local = boost::shared_ptr<LocalAssetProvider>(new LocalAssetProvider(framework_));
        framework_->Asset()->RegisterAssetProvider(boost::dynamic_pointer_cast<IAssetProvider>(local));

        QDir dir((GuaranteeTrailingSlash(GetFramework()->GetPlatform()->GetInstallDirectory().c_str()) + "data/assets").toStdString().c_str());
        local->AddStorageDirectory(dir.absolutePath().toStdString(), "System", true);

        dir = QDir((GuaranteeTrailingSlash(GetFramework()->GetPlatform()->GetInstallDirectory().c_str()) + "jsmodules").toStdString().c_str());
        local->AddStorageDirectory(dir.absolutePath().toStdString(), "Javascript", true);

        dir = QDir((GuaranteeTrailingSlash(GetFramework()->GetPlatform()->GetInstallDirectory().c_str()) + "media").toStdString().c_str());
        local->AddStorageDirectory(dir.absolutePath().toStdString(), "Ogre Media", true);
    }

    void AssetModule::PostInitialize()
    {
        RegisterConsoleCommand(Console::CreateCommand(
            "RequestAsset", "Request asset from server. Usage: RequestAsset(uuid,assettype)",
            Console::Bind(this, &AssetModule::ConsoleRequestAsset)));

        RegisterConsoleCommand(Console::CreateCommand(
            "AddHttpStorage", "Adds a new Http asset storage to the known storages. Usage: AddHttpStorage(url, name)",
            Console::Bind(this, &AssetModule::AddHttpStorage)));

        ProcessCommandLineOptions();
    }

    void AssetModule::ProcessCommandLineOptions()
    {
        assert(framework_);

        const boost::program_options::variables_map &options = framework_->ProgramOptions();

        if (options.count("file") > 0)
        {
            std::string startup_scene_ = QString(options["file"].as<std::string>().c_str()).trimmed().toStdString();
            if (!startup_scene_.empty())
            {
                // If scene name is expressed as a full path, add it as a recursive asset source for localassetprovider
                boost::filesystem::path scenepath(startup_scene_);
                std::string dirname = scenepath.branch_path().string();
                if (!dirname.empty())
                {
                    framework_->Asset()->GetAssetProvider<LocalAssetProvider>()->AddStorageDirectory(dirname, "Scene", true);
                    framework_->Asset()->SetDefaultAssetStorage(framework_->Asset()->GetAssetStorage("Scene"));
                }
            }
        }

        if (options.count("storage") > 0)
        {
            std::string startup_scene_ = QString(options["storage"].as<std::string>().c_str()).trimmed().toStdString();
            if (!startup_scene_.empty())
            {
                // If scene name is expressed as a full path, add it as a recursive asset source for localassetprovider
                boost::filesystem::path scenepath(startup_scene_);
                std::string dirname = scenepath.branch_path().string();
                if (!dirname.empty())
                {
                    framework_->Asset()->GetAssetProvider<LocalAssetProvider>()->AddStorageDirectory(dirname, "Scene", true);
                    framework_->Asset()->SetDefaultAssetStorage(framework_->Asset()->GetAssetStorage("Scene"));
                }
            }
        }
    }

    Console::CommandResult AssetModule::ConsoleRequestAsset(const StringVector &params)
    {
        if (params.size() != 2)
            return Console::ResultFailure("Usage: RequestAsset(uuid,assettype)");

        AssetTransferPtr transfer = framework_->Asset()->RequestAsset(params[0].c_str(), params[1].c_str());
        if (transfer)
            return Console::ResultSuccess();
        else
            return Console::ResultFailure();
    }

    Console::CommandResult AssetModule::AddHttpStorage(const StringVector &params)
    {
        if (params.size() != 2)
            return Console::ResultFailure("Usage: AddHttpStorage(url, name). For example: AddHttpStorage(http://www.google.com/, google)");

        if (!framework_->Asset()->GetAssetProvider<HttpAssetProvider>())
            return Console::ResultFailure();

        framework_->Asset()->GetAssetProvider<HttpAssetProvider>()->AddStorageAddress(params[0].c_str(), params[1].c_str());
        framework_->Asset()->SetDefaultAssetStorage(framework_->Asset()->GetAssetStorage(params[1].c_str()));

        return Console::ResultSuccess();
    }
}

extern "C" void POCO_LIBRARY_API SetProfiler(Foundation::Profiler *profiler);
void SetProfiler(Foundation::Profiler *profiler)
{
    Foundation::ProfilerSection::SetProfiler(profiler);
}

using namespace Asset;

POCO_BEGIN_MANIFEST(IModule)
    POCO_EXPORT_CLASS(AssetModule)
POCO_END_MANIFEST

<|endoftext|>


<commit_before>#include "Vajra/Engine/Core/Engine.h"
#include "Vajra/Framework/Logging/Logger.h"
#include "Vajra/Utilities/MathUtilities.h"
#include "Vajra/Utilities/Utilities.h"

#include "Libraries/glm/gtx/orthonormalize.hpp"
#include "Libraries/glm/gtx/vector_angle.hpp"

const float PI = 3.14159265358979323846264f;

const glm::mat4 IDENTITY_MATRIX = glm::mat4(1.0f);
const glm::quat IDENTITY_QUATERNION = glm::quat(glm::vec3(0.0f, 0.0f, 0.0f));

const glm::vec3 XAXIS = glm::vec3(1.0f, 0.0f, 0.0f);
const glm::vec3 YAXIS = glm::vec3(0.0f, 1.0f, 0.0f);
const glm::vec3 ZAXIS = glm::vec3(0.0f, 0.0f, 1.0f);
//
const glm::vec3 ZERO_VEC3 = glm::vec3(0.0f, 0.0f, 0.0f);
const glm::vec4 ZERO_VEC4_POSITION  = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);
const glm::vec4 ZERO_VEC4_DIRECTION = glm::vec4(0.0f, 0.0f, 0.0f, 0.0f);

glm::quat QuaternionFromLookVectors(glm::vec3 requiredForward, glm::vec3 up /* = YAXIS */) {
	ASSERT(requiredForward != ZERO_VEC3, "QuaternionFromLookVectors: Forward vector can't be zero");
	ASSERT(up != ZERO_VEC3, "QuaternionFromLookVectors: Up vector can't be zero");

	glm::quat quaternion1 = IDENTITY_QUATERNION;
	glm::quat quaternion2 = IDENTITY_QUATERNION;

	{
		// Determine the rotation to align the forward vector
		glm::vec3 axis = glm::cross(ZAXIS, requiredForward);
		float angle;
		if (axis != ZERO_VEC3) {
			axis = glm::normalize(axis);
			angle = glm::angle(ZAXIS, requiredForward);
		}
		else {
			axis = YAXIS;
			angle = PI;
		}
		quaternion1 = glm::angleAxis(angle, axis);
	}
	if (up != YAXIS) {
		// Determine the rotation to align the up vector
		glm::vec3 axis = glm::cross(YAXIS, requiredForward);
		float angle;
		if (axis != ZERO_VEC3) {
			axis = glm::normalize(axis);
			angle = glm::angle(YAXIS, requiredForward);
		}
		else {
			axis = ZAXIS;
			angle = PI;
		}
		quaternion2 = glm::angleAxis(angle, axis);
	}

	return quaternion1 * quaternion2;
}

glm::vec3 QuaternionRightVector(glm::quat q) {
	glm::vec3 v;
	v.x = 1.0f - 2.0f * (q.y * q.y + q.z * q.z);
	v.y = 2.0f * (q.x * q.y + q.w * q.z);
	v.z = 2.0f * (q.x * q.z - q.w * q.y);
	return glm::normalize(v);
}

glm::vec3 QuaternionUpVector(glm::quat q) {
	glm::vec3 v;
	v.x = 2.0f * (q.x * q.y - q.w * q.z);
	v.y = 1.0f - 2.0f * (q.x * q.x + q.z * q.z);
	v.z = 2.0f * (q.y * q.z + q.w * q.x);
	return glm::normalize(v);
}

glm::vec3 QuaternionForwardVector(glm::quat q) {
	glm::vec3 v;
	v.x = 2.0f * (q.x * q.z + q.w * q.y);
	v.y = 2.0f * (q.y * q.x - q.w * q.x);
	v.z = 1.0f - 2.0f * (q.x * q.x + q.y * q.y);
	return glm::normalize(v);
}

// Interpolation Functions:
void lerp(float& destination, const float a, const float b, const float interp) {
	destination = a * (1 - interp) + b * interp;
}

void slerp(glm::quat& destination, const glm::quat a, const glm::quat b, float interp) {
	destination = glm::slerp(a, b, interp);
}

void catmullromerp(float& destination, const float p0, const float p1, const float p2, const float p3, const float interp) {
	destination = 0.5f * (
		(2*p1) +
		(-p0 + p2) * interp +
		(2*p0 - 5*p1 + 4*p2 - p3) * interp * interp +
		(-p0 + 3*p1 - 3*p2 +p3) * interp * interp * interp
		);
}

void parabolaerp(glm::vec3& destination, const glm::vec3 a, const glm::vec3 b, const float parabola_a, const float interp) {
	float parabolaBaseLength = glm::distance(a, b);
	float maxHeightOfParabola = 4.0f * parabola_a * square(parabolaBaseLength / 2.0f);

	lerp(destination.x, a.x, b.x, interp);
	lerp(destination.z, a.z, b.z, interp);
	float parabola_y = (parabolaBaseLength * interp) - (parabolaBaseLength / 2.0f);
	destination.y = a.y + maxHeightOfParabola -
						  (4.0f * parabola_a *
						  square(parabola_y));

	// Adjust for when the parabolic path connects points that are at different heights -- like when jumping onto a ledge:
	destination.y += (b.y - a.y) * interp;
}

bool rayPlaneIntersection(Ray& ray, Plane& plane, float& dist) {
	if(glm::dot(plane.normal, ray.dir) == 0) {
		return false;
	}
	glm::vec3 rayToPlane = plane.origin - ray.origin;
	dist = (glm::dot(plane.normal, rayToPlane) / glm::dot(plane.normal, ray.dir));
	return (dist >= 0);
}

void lerp(glm::vec3& destination, const glm::vec3 a, const glm::vec3 b, const float interp) {
	lerp(destination.x, a.x, b.x, interp);
	lerp(destination.y, a.y, b.y, interp);
	lerp(destination.z, a.z, b.z, interp);
}
<commit_msg>More quaternion math fixes<commit_after>#include "Vajra/Engine/Core/Engine.h"
#include "Vajra/Framework/Logging/Logger.h"
#include "Vajra/Utilities/MathUtilities.h"
#include "Vajra/Utilities/Utilities.h"

#include "Libraries/glm/gtx/orthonormalize.hpp"
#include "Libraries/glm/gtx/vector_angle.hpp"

const float PI = 3.14159265358979323846264f;

const glm::mat4 IDENTITY_MATRIX = glm::mat4(1.0f);
const glm::quat IDENTITY_QUATERNION = glm::quat(glm::vec3(0.0f, 0.0f, 0.0f));

const glm::vec3 XAXIS = glm::vec3(1.0f, 0.0f, 0.0f);
const glm::vec3 YAXIS = glm::vec3(0.0f, 1.0f, 0.0f);
const glm::vec3 ZAXIS = glm::vec3(0.0f, 0.0f, 1.0f);
//
const glm::vec3 ZERO_VEC3 = glm::vec3(0.0f, 0.0f, 0.0f);
const glm::vec4 ZERO_VEC4_POSITION  = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);
const glm::vec4 ZERO_VEC4_DIRECTION = glm::vec4(0.0f, 0.0f, 0.0f, 0.0f);

glm::quat QuaternionFromLookVectors(glm::vec3 requiredForward, glm::vec3 up /* = YAXIS */) {
	VERIFY(requiredForward != ZERO_VEC3, "QuaternionFromLookVectors: Forward vector can't be zero");
	VERIFY(up != ZERO_VEC3, "QuaternionFromLookVectors: Up vector can't be zero");

	glm::vec3 quatForward = glm::normalize(requiredForward);
	glm::vec3 quatUp = glm::orthonormalize(up, quatForward);
	glm::vec3 quatRight = glm::normalize(glm::cross(quatUp, quatForward));

	float m00 = quatRight.x;
	float m01 = quatRight.y;
	float m02 = quatRight.z;
	float m10 = quatUp.x;
	float m11 = quatUp.y;
	float m12 = quatUp.z;
	float m20 = quatForward.x;
	float m21 = quatForward.y;
	float m22 = quatForward.z;

	glm::quat finalQuat;
	float num8 = (m00 + m11) + m22;
	if (num8 > 0.0f) {
		float num = sqrt(num8 + 1.0f);
		finalQuat.w = num * 0.5f;
		num = 0.5f / num;
		finalQuat.x = (m12 - m21) * num;
		finalQuat.y = (m20 - m02) * num;
		finalQuat.z = (m01 - m10) * num;
		return finalQuat;
	}
	if ((m00 >= m11) && (m00 >= m22)) {
		float num7 = sqrt(((1.0f + m00) - m11) - m22);
		float num4 = 0.5f / num7;
		finalQuat.x = 0.5f * num7;
		finalQuat.y = (m01 + m10) * num4;
		finalQuat.z = (m02 + m20) * num4;
		finalQuat.w = (m12 - m21) * num4;
		return finalQuat;
	}
	if (m11 > m22) {
		float num6 = sqrt(((1.0f + m11) - m00) - m22);
		float num3 = 0.5f / num6;
		finalQuat.x = (m10 + m01) * num3;
		finalQuat.y = 0.5f * num6;
		finalQuat.z = (m21 + m12) * num3;
		finalQuat.w = (m20 - m02) * num3;
		return finalQuat;
	}
	float num5 = sqrt(((1.0f + m22) - m00) - m11);
	float num2 = 0.5f / num5;
	finalQuat.x = (m20 + m02) * num2;
	finalQuat.y = (m21 + m12) * num2;
	finalQuat.z = 0.5f * num5;
	finalQuat.w = (m01 - m10) * num2;
	return finalQuat;
}

glm::vec3 QuaternionRightVector(glm::quat q) {
	glm::vec3 v;
	v.x = 1.0f - 2.0f * (q.y * q.y + q.z * q.z);
	v.y = 2.0f * (q.x * q.y + q.w * q.z);
	v.z = 2.0f * (q.x * q.z - q.w * q.y);
	return glm::normalize(v);
}

glm::vec3 QuaternionUpVector(glm::quat q) {
	glm::vec3 v;
	v.x = 2.0f * (q.x * q.y - q.w * q.z);
	v.y = 1.0f - 2.0f * (q.x * q.x + q.z * q.z);
	v.z = 2.0f * (q.y * q.z + q.w * q.x);
	return glm::normalize(v);
}

glm::vec3 QuaternionForwardVector(glm::quat q) {
	glm::vec3 v;
	v.x = 2.0f * (q.x * q.z + q.w * q.y);
	v.y = 2.0f * (q.y * q.z - q.w * q.x);
	v.z = 1.0f - 2.0f * (q.x * q.x + q.y * q.y);
	return glm::normalize(v);
}

// Interpolation Functions:
void lerp(float& destination, const float a, const float b, const float interp) {
	destination = a * (1 - interp) + b * interp;
}

void slerp(glm::quat& destination, const glm::quat a, const glm::quat b, float interp) {
	destination = glm::slerp(a, b, interp);
}

void catmullromerp(float& destination, const float p0, const float p1, const float p2, const float p3, const float interp) {
	destination = 0.5f * (
		(2*p1) +
		(-p0 + p2) * interp +
		(2*p0 - 5*p1 + 4*p2 - p3) * interp * interp +
		(-p0 + 3*p1 - 3*p2 +p3) * interp * interp * interp
		);
}

void parabolaerp(glm::vec3& destination, const glm::vec3 a, const glm::vec3 b, const float parabola_a, const float interp) {
	float parabolaBaseLength = glm::distance(a, b);
	float maxHeightOfParabola = 4.0f * parabola_a * square(parabolaBaseLength / 2.0f);

	lerp(destination.x, a.x, b.x, interp);
	lerp(destination.z, a.z, b.z, interp);
	float parabola_y = (parabolaBaseLength * interp) - (parabolaBaseLength / 2.0f);
	destination.y = a.y + maxHeightOfParabola -
						  (4.0f * parabola_a *
						  square(parabola_y));

	// Adjust for when the parabolic path connects points that are at different heights -- like when jumping onto a ledge:
	destination.y += (b.y - a.y) * interp;
}

bool rayPlaneIntersection(Ray& ray, Plane& plane, float& dist) {
	if(glm::dot(plane.normal, ray.dir) == 0) {
		return false;
	}
	glm::vec3 rayToPlane = plane.origin - ray.origin;
	dist = (glm::dot(plane.normal, rayToPlane) / glm::dot(plane.normal, ray.dir));
	return (dist >= 0);
}

void lerp(glm::vec3& destination, const glm::vec3 a, const glm::vec3 b, const float interp) {
	lerp(destination.x, a.x, b.x, interp);
	lerp(destination.y, a.y, b.y, interp);
	lerp(destination.z, a.z, b.z, interp);
}
<|endoftext|>