<commit_before>//
// Created by michael on 06.10.15.
//

#include <World/Space/SpaceWorldModel.h>
#include <World/Space/Planet.h>
#include <cmath>

using namespace std;
using namespace weave;

WorldModelAction SpaceWorldModel::CreateLocation() const {
    int x = rs->GetIntInRange(param.minLocation, param.maxLocation);
    int y = rs->GetIntInRange(param.minLocation, param.maxLocation);
    int z = rs->GetIntInRange(param.minLocation, param.maxLocation);
    return WorldModelAction(WorldActionType::CREATE, make_shared<SpaceLocation>(x, y, z));
}

SpaceWorldModel::SpaceWorldModel(std::shared_ptr<RandomStream> randomStream) : WorldModel() {
    rs = randomStream;
}

ModelParameters SpaceWorldModel::GetParameters() {
    return param;
}

void SpaceWorldModel::SetParameters(ModelParameters parameters) {
    this->param = parameters;
}

const NameGenerator &SpaceWorldModel::GetNameGenerator() const {
    return nameGenerator;
}

WorldModelAction SpaceWorldModel::CreateAgent(NameType nameType) const {
    return WorldModelAction(WorldActionType::CREATE, make_shared<SpaceAgent>(nameGenerator.CreateName(nameType, rs)));
}

WorldModelAction SpaceWorldModel::CreatePlanet(NameType nameType, int distanceToSun) const {
    float angle = rs->GetULongInRange(0, 3600) / 10.0f;
    float radians = angle * M_PI / 180.0f;
    float x = distanceToSun * cos(radians);
    float y = distanceToSun * sin(radians);
    int seed = rs->GetInt();
    string name = nameGenerator.CreateName(nameType, rs);
    return WorldModelAction(WorldActionType::CREATE, make_shared<Planet>(x, y, seed, name));
}

vector<WorldModelAction> SpaceWorldModel::CreateSolarSystem(NameType nameType, int planetCount) const {
    if (planetCount < 0) {
        planetCount = rs->GetNormalIntInRange(1, 8);
    }

    vector<WorldModelAction> actions;
    vector<NameType> planetNames = {NameType::DARK_THING, NameType::ALIEN, NameType::LIGHT_THING};
    vector<shared_ptr<Planet>> planets;
    for (int i = 1; i <= planetCount; i++) {
        int distance = 50 + rs->GetNormalIntInRange(-10, 10);
        auto nameType = planetNames[rs->GetRandomIndex(planetNames.size())];
        auto planetAction = CreatePlanet(nameType, distance);
        actions.push_back(planetAction);
        planets.push_back(dynamic_pointer_cast<Planet>(planetAction.GetEntity()));
    }

    auto locationAction = CreateLocation();
    actions.push_back(locationAction);
    shared_ptr<SpaceLocation> location = dynamic_pointer_cast<SpaceLocation>(locationAction.GetEntity());
    auto solarSystem = make_shared<SolarSystem>(nameGenerator.CreateName(nameType, rs), location, planets);
    actions.push_back(WorldModelAction(WorldActionType::CREATE, solarSystem));

    return actions;
}
<commit_msg>removed compiler warning<commit_after>//
// Created by michael on 06.10.15.
//

#include <World/Space/SpaceWorldModel.h>
#include <World/Space/Planet.h>
#include <cmath>

using namespace std;
using namespace weave;

WorldModelAction SpaceWorldModel::CreateLocation() const {
    int x = rs->GetIntInRange(param.minLocation, param.maxLocation);
    int y = rs->GetIntInRange(param.minLocation, param.maxLocation);
    int z = rs->GetIntInRange(param.minLocation, param.maxLocation);
    return WorldModelAction(WorldActionType::CREATE, make_shared<SpaceLocation>(x, y, z));
}

SpaceWorldModel::SpaceWorldModel(std::shared_ptr<RandomStream> randomStream) : WorldModel() {
    rs = randomStream;
}

ModelParameters SpaceWorldModel::GetParameters() {
    return param;
}

void SpaceWorldModel::SetParameters(ModelParameters parameters) {
    this->param = parameters;
}

const NameGenerator &SpaceWorldModel::GetNameGenerator() const {
    return nameGenerator;
}

WorldModelAction SpaceWorldModel::CreateAgent(NameType nameType) const {
    return WorldModelAction(WorldActionType::CREATE, make_shared<SpaceAgent>(nameGenerator.CreateName(nameType, rs)));
}

WorldModelAction SpaceWorldModel::CreatePlanet(NameType nameType, int distanceToSun) const {
    float angle = rs->GetULongInRange(0, 3600) / 10.0f;
    float radians = static_cast<float>(angle * M_PI / 180);
    float x = distanceToSun * cos(radians);
    float y = distanceToSun * sin(radians);
    int seed = rs->GetInt();
    string name = nameGenerator.CreateName(nameType, rs);
    return WorldModelAction(WorldActionType::CREATE, make_shared<Planet>(x, y, seed, name));
}

vector<WorldModelAction> SpaceWorldModel::CreateSolarSystem(NameType nameType, int planetCount) const {
    if (planetCount < 0) {
        planetCount = rs->GetNormalIntInRange(1, 8);
    }

    vector<WorldModelAction> actions;
    vector<NameType> planetNames = {NameType::DARK_THING, NameType::ALIEN, NameType::LIGHT_THING};
    vector<shared_ptr<Planet>> planets;
    for (int i = 1; i <= planetCount; i++) {
        int distance = 50 + rs->GetNormalIntInRange(-10, 10);
        auto nameType = planetNames[rs->GetRandomIndex(planetNames.size())];
        auto planetAction = CreatePlanet(nameType, distance);
        actions.push_back(planetAction);
        planets.push_back(dynamic_pointer_cast<Planet>(planetAction.GetEntity()));
    }

    auto locationAction = CreateLocation();
    actions.push_back(locationAction);
    shared_ptr<SpaceLocation> location = dynamic_pointer_cast<SpaceLocation>(locationAction.GetEntity());
    auto solarSystem = make_shared<SolarSystem>(nameGenerator.CreateName(nameType, rs), location, planets);
    actions.push_back(WorldModelAction(WorldActionType::CREATE, solarSystem));

    return actions;
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2014-present, The osquery authors
 *
 * This source code is licensed as defined by the LICENSE file found in the
 * root directory of this source tree.
 *
 * SPDX-License-Identifier: (Apache-2.0 OR GPL-2.0-only)
 */

#include <set>
#include <string>

#include <osquery/carver/carver.h>
#include <osquery/core/flags.h>
#include <osquery/logger/logger.h>
#include <osquery/utils/conversions/split.h>
#include <osquery/utils/mutex.h>

#include <sqlite3.h>

namespace osquery {

/// Global set of requested carve paths.
static std::set<std::string> kFunctionCarvePaths;

/// Mutex to protect access to carve paths.
Mutex kFunctionCarveMutex;

DECLARE_bool(carver_disable_function);

static void addCarveFile(sqlite3_context* ctx, int argc, sqlite3_value** argv) {
  if (argc == 0) {
    return;
  }

  if (SQLITE_NULL == sqlite3_value_type(argv[0])) {
    sqlite3_result_null(ctx);
    return;
  }

  WriteLock lock(kFunctionCarveMutex);
  std::string path((const char*)sqlite3_value_text(argv[0]));
  kFunctionCarvePaths.insert(path);

  sqlite3_result_text(
      ctx, path.c_str(), static_cast<int>(path.size()), SQLITE_TRANSIENT);
}

static void executeCarve(sqlite3_context* ctx) {
  WriteLock lock(kFunctionCarveMutex);
  if (!FLAGS_carver_disable_function) {
    carvePaths(kFunctionCarvePaths);
  } else {
    LOG(WARNING) << "Carver as a function is disabled";
  }
  kFunctionCarvePaths.clear();
  sqlite3_result_text(ctx, "Carve Started", 13, SQLITE_TRANSIENT);
}

void registerOperationExtensions(sqlite3* db) {
  sqlite3_create_function(db,
                          "carve",
                          1,
                          SQLITE_UTF8,
                          nullptr,
                          nullptr,
                          addCarveFile,
                          executeCarve);
}
} // namespace osquery
<commit_msg>carver: Emit an error if the carve function is disabled (#6658)<commit_after>/**
 * Copyright (c) 2014-present, The osquery authors
 *
 * This source code is licensed as defined by the LICENSE file found in the
 * root directory of this source tree.
 *
 * SPDX-License-Identifier: (Apache-2.0 OR GPL-2.0-only)
 */

#include <set>
#include <string>

#include <osquery/carver/carver.h>
#include <osquery/core/flags.h>
#include <osquery/logger/logger.h>
#include <osquery/utils/conversions/split.h>
#include <osquery/utils/mutex.h>

#include <sqlite3.h>

namespace osquery {

/// Global set of requested carve paths.
static std::set<std::string> kFunctionCarvePaths;

/// Mutex to protect access to carve paths.
Mutex kFunctionCarveMutex;

DECLARE_bool(carver_disable_function);

static void addCarveFile(sqlite3_context* ctx, int argc, sqlite3_value** argv) {
  if (argc == 0) {
    return;
  }

  if (SQLITE_NULL == sqlite3_value_type(argv[0])) {
    sqlite3_result_null(ctx);
    return;
  }

  WriteLock lock(kFunctionCarveMutex);
  std::string path((const char*)sqlite3_value_text(argv[0]));
  kFunctionCarvePaths.insert(path);

  sqlite3_result_text(
      ctx, path.c_str(), static_cast<int>(path.size()), SQLITE_TRANSIENT);
}

static void executeCarve(sqlite3_context* ctx) {
  WriteLock lock(kFunctionCarveMutex);
  if (!FLAGS_carver_disable_function) {
    carvePaths(kFunctionCarvePaths);
    sqlite3_result_text(ctx, "Carve Started", 13, SQLITE_TRANSIENT);
  } else {
    LOG(WARNING) << "Carver as a function is disabled";
    sqlite3_result_text(ctx, "Carve Failed", 13, SQLITE_TRANSIENT);
  }
  kFunctionCarvePaths.clear();
}

void registerOperationExtensions(sqlite3* db) {
  sqlite3_create_function(db,
                          "carve",
                          1,
                          SQLITE_UTF8,
                          nullptr,
                          nullptr,
                          addCarveFile,
                          executeCarve);
}
} // namespace osquery
<|endoftext|>


<commit_before>#include <babylon/misc/file_tools.h>
#include <babylon/asio/asio.h>

#define STB_IMAGE_IMPLEMENTATION
#if defined(__GNUC__) || defined(__MINGW32__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#pragma GCC diagnostic ignored "-Wconversion"
#if __GNUC__ > 5
#pragma GCC diagnostic ignored "-Wmisleading-indentation"
#pragma GCC diagnostic ignored "-Wshift-negative-value"
#endif
#if __GNUC__ > 6
// Use of GNU statement expression extension
#endif
#pragma GCC diagnostic ignored "-Wswitch-default"
#endif
#if _MSC_VER && !__INTEL_COMPILER
#ifndef NOMINMAX
#define NOMINMAX
#endif
#pragma warning(push)
#pragma warning(disable : 4244)
#endif
#include <stb_image/stb_image.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#if defined(__GNUC__) || defined(__MINGW32__)
#pragma GCC diagnostic pop
#endif

#include <babylon/core/array_buffer_view.h>
#include <babylon/core/filesystem.h>
#include <babylon/core/logging.h>
#include <babylon/core/string.h>
#include <babylon/interfaces/igl_rendering_context.h>
#include <babylon/loading/progress_event.h>
#include <babylon/utils/base64.h>

#include <stdexcept>

namespace BABYLON {

std::string tryFindFile(const std::string filename)
{
  // Check if the file is locally available
  // - Check in local folder
  auto absolutePath = Filesystem::absolutePath(filename);
  if (Filesystem::exists(absolutePath)) {
    return absolutePath;
  }
  // - Check in assets folder
  absolutePath = Filesystem::absolutePath(BABYLON::assets_folder() + filename);
  if (Filesystem::exists(absolutePath)) {
    return absolutePath;
  }
  return filename;
};

std::string FileTools::PreprocessUrl(const std::string& url_)
{
  std::string url = url_;
  if (String::startsWith(url, "http"))
    throw std::runtime_error("PreprocessUrl only supports file urls for the moment");

  if ( ! String::startsWith(url, "file:/"))
    url = std::string("file:/") + url;

  std::string filename = url.substr(6);
  filename = tryFindFile(filename);
  return std::string("file:/") + filename;
}

std::string FileTools::_CleanUrl(std::string url)
{
  String::replaceInPlace(url, "#", "%23");
  return url;
}

std::optional<Image> LoadImage_Stbi_Impl(
  const char *filename,
  int nb_desired_channels,
  bool flipVertically)
{

  // Basic usage (see HDR discussion below for HDR usage):
  int w, h, nb_channels_real;
  stbi_set_flip_vertically_on_load(flipVertically);
  unsigned char *data = stbi_load(filename, &w, &h, &nb_channels_real, nb_desired_channels);
  stbi_set_flip_vertically_on_load(false);
  if (data)
  {
    unsigned int glColorMode = (nb_desired_channels == 3) ? GL::RGB : GL::RGBA;
    Image image(data, w * h * nb_desired_channels, w, h, nb_desired_channels, glColorMode);
    stbi_image_free(data);
    return image;
  }
  return std::nullopt;
}

void FileTools::LoadImageFromUrl(
  std::string url, const std::function<void(const Image& img)>& onLoad,
  const std::function<void(const std::string& message, const std::string& exception)>& onError,
  bool flipVertically)
{
  url = FileTools::_CleanUrl(url);
  url = FileTools::PreprocessUrl(url);

  if (!String::startsWith(url, "file:"))
    throw std::runtime_error("FileTools::LoadImageFromUrl only supports file urls");

  std::string filename = url.substr(5).c_str();

  auto load_image_file_proc = [filename, flipVertically, onLoad, onError]() {
    std::optional<Image> image;
    // Try to load RGBA, then load RGB on fail (is this really required? we could instead trust stbi)
    image = LoadImage_Stbi_Impl(filename.c_str(), STBI_rgb_alpha, flipVertically);
    if (!image)
      image = LoadImage_Stbi_Impl(filename.c_str(), STBI_rgb, flipVertically);

    if (image)
      onLoad(*image);
    else if (onError)
      onError("Error loading image from file " + filename, "");
  };

  load_image_file_proc();
}

void FileTools::LoadImageFromBuffer(
  const std::variant<std::string, ArrayBuffer, ArrayBufferView, Image>& input, bool invertY,
  const std::function<void(const Image& img)>& onLoad,
  const std::function<void(const std::string& message, const std::string& exception)>& onError)
{
  if (!onLoad) {
    return;
  }

  if (std::holds_alternative<std::string>(input)) {
    onLoad(FileTools::StringToImage(std::get<std::string>(input), invertY));
  }
  else if (std::holds_alternative<ArrayBuffer>(input)) {
    onLoad(FileTools::ArrayBufferToImage(std::get<ArrayBuffer>(input), invertY));
  }
  else if (std::holds_alternative<ArrayBufferView>(input)) {
    onLoad(FileTools::ArrayBufferToImage(std::get<ArrayBufferView>(input).uint8Array, invertY));
  }
  else if (std::holds_alternative<Image>(input)) {
    onLoad(std::get<Image>(input));
  }
  else {
    auto errorMessage = "Loading image from url not supported";
    if (onError) {
      onError(errorMessage, "");
    }
    else {
      throw std::runtime_error(errorMessage);
    }
  }
}

Image FileTools::ArrayBufferToImage(const ArrayBuffer& buffer, bool flipVertically)
{
  if (buffer.empty()) {
    return Image();
  }
  auto bufferSize = static_cast<int>(buffer.size());
  int w = -1, h = -1, n = -1;
  int req_comp = STBI_rgb_alpha;

  stbi_set_flip_vertically_on_load(flipVertically);
  unsigned char * ucharBuffer = stbi_load_from_memory(buffer.data(), bufferSize, &w, &h, &n, req_comp);
  stbi_set_flip_vertically_on_load(false);

  if (!ucharBuffer)
    return Image();

  n = STBI_rgb_alpha;
  Image image (ucharBuffer, w * h * n, w, h, n, (n == 3) ? GL::RGB : GL::RGBA);
  stbi_image_free(ucharBuffer);
  return image;
}

Image FileTools::StringToImage(const std::string& uri, bool flipVertically)
{
  const auto IsDataURI = [](const std::string& in) -> bool {
    std::string header = "data:application/octet-stream;base64,";
    if (in.find(header) == 0) {
      return true;
    }

    header = "data:image/jpeg;base64,";
    if (in.find(header) == 0) {
      return true;
    }

    header = "data:image/png;base64,";
    if (in.find(header) == 0) {
      return true;
    }

    header = "data:image/bmp;base64,";
    if (in.find(header) == 0) {
      return true;
    }

    header = "data:image/gif;base64,";
    if (in.find(header) == 0) {
      return true;
    }

    header = "data:text/plain;base64,";
    if (in.find(header) == 0) {
      return true;
    }

    header = "data:application/gltf-buffer;base64,";
    return in.find(header) == 0;
  };

  const auto DecodeDataURI = [](std::vector<unsigned char>* out, std::string& mime_type,
                                const std::string& in, size_t reqBytes, bool checkSize) -> bool {
    std::string header = "data:application/octet-stream;base64,";
    std::string data;
    if (in.find(header) == 0) {
      data = Base64::decode(in.substr(header.size())); // cut mime string.
    }

    if (data.empty()) {
      header = "data:image/jpeg;base64,";
      if (in.find(header) == 0) {
        mime_type = "image/jpeg";
        data      = Base64::decode(in.substr(header.size())); // cut mime string.
      }
    }

    if (data.empty()) {
      header = "data:image/png;base64,";
      if (in.find(header) == 0) {
        mime_type = "image/png";
        data      = Base64::decode(in.substr(header.size())); // cut mime string.
      }
    }

    if (data.empty()) {
      header = "data:image/bmp;base64,";
      if (in.find(header) == 0) {
        mime_type = "image/bmp";
        data      = Base64::decode(in.substr(header.size())); // cut mime string.
      }
    }

    if (data.empty()) {
      header = "data:image/gif;base64,";
      if (in.find(header) == 0) {
        mime_type = "image/gif";
        data      = Base64::decode(in.substr(header.size())); // cut mime string.
      }
    }

    if (data.empty()) {
      header = "data:text/plain;base64,";
      if (in.find(header) == 0) {
        mime_type = "text/plain";
        data      = Base64::decode(in.substr(header.size()));
      }
    }

    if (data.empty()) {
      header = "data:application/gltf-buffer;base64,";
      if (in.find(header) == 0) {
        data = Base64::decode(in.substr(header.size()));
      }
    }

    if (data.empty()) {
      return false;
    }

    if (checkSize) {
      if (data.size() != reqBytes) {
        return false;
      }
      out->resize(reqBytes);
    }
    else {
      out->resize(data.size());
    }
    std::copy(data.begin(), data.end(), out->begin());
    return true;
  };

  const auto LoadImageData = [](Image& image, int req_width, int req_height,
                                const unsigned char* bytes, int size, bool flipVertically) -> bool {
    int w = 0, h = 0, comp = 0, req_comp = 0;

    unsigned char* data = nullptr;

    // force 32-bit textures for common Vulkan compatibility. It appears that
    // some GPU drivers do not support 24-bit images for Vulkan
    req_comp = 4;
    int bits = 8;

    stbi_set_flip_vertically_on_load(flipVertically);

    // It is possible that the image we want to load is a 16bit per channel
    // image We are going to attempt to load it as 16bit per channel, and if it
    // worked, set the image data accodingly. We are casting the returned
    // pointer into unsigned char, because we are representing "bytes". But we
    // are updating the Image metadata to signal that this image uses 2 bytes
    // (16bits) per channel:
    if (stbi_is_16_bit_from_memory(bytes, size)) {
      data = reinterpret_cast<unsigned char*>(
        stbi_load_16_from_memory(bytes, size, &w, &h, &comp, req_comp));
      if (data) {
        bits = 16;
      }
    }

    // at this point, if data is still NULL, it means that the image wasn't
    // 16bit per channel, we are going to load it as a normal 8bit per channel
    // mage as we used to do:
    // if image cannot be decoded, ignore parsing and keep it by its path
    // don't break in this case
    // FIXME we should only enter this function if the image is embedded. If
    // image->uri references
    // an image file, it should be left as it is. Image loading should not be
    // mandatory (to support other formats)
    if (!data)
      data = stbi_load_from_memory(bytes, size, &w, &h, &comp, req_comp);
    if (!data) {
      BABYLON_LOG_WARN("StringToImage",
                       "Unknown image format. STB cannot decode image data for image")
      return false;
    }

    stbi_set_flip_vertically_on_load(false);

    if ((w < 1) || (h < 1)) {
      stbi_image_free(data);
      BABYLON_LOG_ERROR("StringToImage", "Invalid image data for image")
      return false;
    }

    if (req_width > 0) {
      if (req_width != w) {
        stbi_image_free(data);
        BABYLON_LOG_ERROR("StringToImage", "Image width mismatch for image")
        return false;
      }
    }

    if (req_height > 0) {
      if (req_height != h) {
        stbi_image_free(data);
        BABYLON_LOG_ERROR("StringToImage", "Image height mismatch. for image")
        return false;
      }
    }

    image.width  = w;
    image.height = h;
    image.depth  = req_comp;
    image.mode   = (req_comp == 3) ? GL::RGB : GL::RGBA;
    image.data.resize(static_cast<size_t>(w * h * req_comp) * size_t(bits / 8));
    std::copy(data, data + w * h * req_comp * (bits / 8), image.data.begin());
    stbi_image_free(data);

    return true;
  };

  Image image;
  std::vector<unsigned char> img;
  std::string mimeType;
  if (IsDataURI(uri)) {
    if (!DecodeDataURI(&img, mimeType, uri, 0, false)) {
      BABYLON_LOG_ERROR("Failed to decode image from uri: %s", uri.c_str())
      return Image();
    }
  }

  if (LoadImageData(image, 0, 0, &img.at(0), static_cast<int>(img.size()), flipVertically)) {
    return image;
  }

  return Image();
}

void FileTools::LoadFile(
  const std::string& url,
  const std::function<void(const std::variant<std::string, ArrayBuffer>& data,
                           const std::string& responseURL)>& onSuccess,
  const std::function<void(const ProgressEvent& event)>& onProgress,
  bool useArrayBuffer,
  const std::function<void(const std::string& message, const std::string& exception)>& onError)
{
  // LoadFile's signature is extremely complicated for no good reason
  // Let's write some wrappers from the simple callbacks of BABYLON::asio
  // We will need to refactor this later

  // Superfluous params?
  constexpr const char * dummyResponseUrl = "";
  constexpr const char * dummyExceptionString = "";
  constexpr const char * dummyProgressType = "";

  std::string url_clean = FileTools::_CleanUrl(url);
  url_clean = FileTools::PreprocessUrl(url);

  auto onErrorWrapper = [onError](const std::string& errorMessage) {
    if (onError)
      onError(errorMessage, dummyExceptionString);
  };
  auto onProgressWrapper = [onProgress](bool lengthComputable, size_t loaded, size_t total) {
    if (onProgress)
      onProgress({dummyProgressType, lengthComputable, loaded, total});
  };

  if (useArrayBuffer)
  {
    auto onSuccessWrapper = [onSuccess](const ArrayBuffer& data) {
      if (onSuccess)
        onSuccess(data, dummyResponseUrl);
    };
    asio::LoadUrlAsync_Binary(url_clean, onSuccessWrapper, onErrorWrapper, onProgressWrapper);
  }
  else
  {
    auto onSuccessWrapper = [onSuccess](const std::string& data) {
      if (onSuccess) {
        onSuccess(data, dummyResponseUrl);
      }
    };
    asio::LoadUrlAsync_Text(url_clean, onSuccessWrapper, onErrorWrapper, onProgressWrapper);
  }

  asio::Service_WaitAll_Sync();
  std::cout << "WaitAll finished\n";
}

} // end of namespace BABYLON
<commit_msg>file_tools.cpp: do not asio::Service_WaitAll<commit_after>#include <babylon/misc/file_tools.h>
#include <babylon/asio/asio.h>

#define STB_IMAGE_IMPLEMENTATION
#if defined(__GNUC__) || defined(__MINGW32__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#pragma GCC diagnostic ignored "-Wconversion"
#if __GNUC__ > 5
#pragma GCC diagnostic ignored "-Wmisleading-indentation"
#pragma GCC diagnostic ignored "-Wshift-negative-value"
#endif
#if __GNUC__ > 6
// Use of GNU statement expression extension
#endif
#pragma GCC diagnostic ignored "-Wswitch-default"
#endif
#if _MSC_VER && !__INTEL_COMPILER
#ifndef NOMINMAX
#define NOMINMAX
#endif
#pragma warning(push)
#pragma warning(disable : 4244)
#endif
#include <stb_image/stb_image.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#if defined(__GNUC__) || defined(__MINGW32__)
#pragma GCC diagnostic pop
#endif

#include <babylon/core/array_buffer_view.h>
#include <babylon/core/filesystem.h>
#include <babylon/core/logging.h>
#include <babylon/core/string.h>
#include <babylon/interfaces/igl_rendering_context.h>
#include <babylon/loading/progress_event.h>
#include <babylon/utils/base64.h>

#include <stdexcept>

namespace BABYLON {

std::string tryFindFile(const std::string filename)
{
  // Check if the file is locally available
  // - Check in local folder
  auto absolutePath = Filesystem::absolutePath(filename);
  if (Filesystem::exists(absolutePath)) {
    return absolutePath;
  }
  // - Check in assets folder
  absolutePath = Filesystem::absolutePath(BABYLON::assets_folder() + filename);
  if (Filesystem::exists(absolutePath)) {
    return absolutePath;
  }
  return filename;
};

std::string FileTools::PreprocessUrl(const std::string& url_)
{
  std::string url = url_;
  if (String::startsWith(url, "http"))
    throw std::runtime_error("PreprocessUrl only supports file urls for the moment");

  if ( ! String::startsWith(url, "file:/"))
    url = std::string("file:/") + url;

  std::string filename = url.substr(6);
  filename = tryFindFile(filename);
  return std::string("file:/") + filename;
}

std::string FileTools::_CleanUrl(std::string url)
{
  String::replaceInPlace(url, "#", "%23");
  return url;
}

std::optional<Image> LoadImage_Stbi_Impl(
  const char *filename,
  int nb_desired_channels,
  bool flipVertically)
{

  // Basic usage (see HDR discussion below for HDR usage):
  int w, h, nb_channels_real;
  stbi_set_flip_vertically_on_load(flipVertically);
  unsigned char *data = stbi_load(filename, &w, &h, &nb_channels_real, nb_desired_channels);
  stbi_set_flip_vertically_on_load(false);
  if (data)
  {
    unsigned int glColorMode = (nb_desired_channels == 3) ? GL::RGB : GL::RGBA;
    Image image(data, w * h * nb_desired_channels, w, h, nb_desired_channels, glColorMode);
    stbi_image_free(data);
    return image;
  }
  return std::nullopt;
}

void FileTools::LoadImageFromUrl(
  std::string url, const std::function<void(const Image& img)>& onLoad,
  const std::function<void(const std::string& message, const std::string& exception)>& onError,
  bool flipVertically)
{
  url = FileTools::_CleanUrl(url);
  url = FileTools::PreprocessUrl(url);

  if (!String::startsWith(url, "file:"))
    throw std::runtime_error("FileTools::LoadImageFromUrl only supports file urls");

  std::string filename = url.substr(5).c_str();

  auto load_image_file_proc = [filename, flipVertically, onLoad, onError]() {
    std::optional<Image> image;
    // Try to load RGBA, then load RGB on fail (is this really required? we could instead trust stbi)
    image = LoadImage_Stbi_Impl(filename.c_str(), STBI_rgb_alpha, flipVertically);
    if (!image)
      image = LoadImage_Stbi_Impl(filename.c_str(), STBI_rgb, flipVertically);

    if (image)
      onLoad(*image);
    else if (onError)
      onError("Error loading image from file " + filename, "");
  };

  load_image_file_proc();
}

void FileTools::LoadImageFromBuffer(
  const std::variant<std::string, ArrayBuffer, ArrayBufferView, Image>& input, bool invertY,
  const std::function<void(const Image& img)>& onLoad,
  const std::function<void(const std::string& message, const std::string& exception)>& onError)
{
  if (!onLoad) {
    return;
  }

  if (std::holds_alternative<std::string>(input)) {
    onLoad(FileTools::StringToImage(std::get<std::string>(input), invertY));
  }
  else if (std::holds_alternative<ArrayBuffer>(input)) {
    onLoad(FileTools::ArrayBufferToImage(std::get<ArrayBuffer>(input), invertY));
  }
  else if (std::holds_alternative<ArrayBufferView>(input)) {
    onLoad(FileTools::ArrayBufferToImage(std::get<ArrayBufferView>(input).uint8Array, invertY));
  }
  else if (std::holds_alternative<Image>(input)) {
    onLoad(std::get<Image>(input));
  }
  else {
    auto errorMessage = "Loading image from url not supported";
    if (onError) {
      onError(errorMessage, "");
    }
    else {
      throw std::runtime_error(errorMessage);
    }
  }
}

Image FileTools::ArrayBufferToImage(const ArrayBuffer& buffer, bool flipVertically)
{
  if (buffer.empty()) {
    return Image();
  }
  auto bufferSize = static_cast<int>(buffer.size());
  int w = -1, h = -1, n = -1;
  int req_comp = STBI_rgb_alpha;

  stbi_set_flip_vertically_on_load(flipVertically);
  unsigned char * ucharBuffer = stbi_load_from_memory(buffer.data(), bufferSize, &w, &h, &n, req_comp);
  stbi_set_flip_vertically_on_load(false);

  if (!ucharBuffer)
    return Image();

  n = STBI_rgb_alpha;
  Image image (ucharBuffer, w * h * n, w, h, n, (n == 3) ? GL::RGB : GL::RGBA);
  stbi_image_free(ucharBuffer);
  return image;
}

Image FileTools::StringToImage(const std::string& uri, bool flipVertically)
{
  const auto IsDataURI = [](const std::string& in) -> bool {
    std::string header = "data:application/octet-stream;base64,";
    if (in.find(header) == 0) {
      return true;
    }

    header = "data:image/jpeg;base64,";
    if (in.find(header) == 0) {
      return true;
    }

    header = "data:image/png;base64,";
    if (in.find(header) == 0) {
      return true;
    }

    header = "data:image/bmp;base64,";
    if (in.find(header) == 0) {
      return true;
    }

    header = "data:image/gif;base64,";
    if (in.find(header) == 0) {
      return true;
    }

    header = "data:text/plain;base64,";
    if (in.find(header) == 0) {
      return true;
    }

    header = "data:application/gltf-buffer;base64,";
    return in.find(header) == 0;
  };

  const auto DecodeDataURI = [](std::vector<unsigned char>* out, std::string& mime_type,
                                const std::string& in, size_t reqBytes, bool checkSize) -> bool {
    std::string header = "data:application/octet-stream;base64,";
    std::string data;
    if (in.find(header) == 0) {
      data = Base64::decode(in.substr(header.size())); // cut mime string.
    }

    if (data.empty()) {
      header = "data:image/jpeg;base64,";
      if (in.find(header) == 0) {
        mime_type = "image/jpeg";
        data      = Base64::decode(in.substr(header.size())); // cut mime string.
      }
    }

    if (data.empty()) {
      header = "data:image/png;base64,";
      if (in.find(header) == 0) {
        mime_type = "image/png";
        data      = Base64::decode(in.substr(header.size())); // cut mime string.
      }
    }

    if (data.empty()) {
      header = "data:image/bmp;base64,";
      if (in.find(header) == 0) {
        mime_type = "image/bmp";
        data      = Base64::decode(in.substr(header.size())); // cut mime string.
      }
    }

    if (data.empty()) {
      header = "data:image/gif;base64,";
      if (in.find(header) == 0) {
        mime_type = "image/gif";
        data      = Base64::decode(in.substr(header.size())); // cut mime string.
      }
    }

    if (data.empty()) {
      header = "data:text/plain;base64,";
      if (in.find(header) == 0) {
        mime_type = "text/plain";
        data      = Base64::decode(in.substr(header.size()));
      }
    }

    if (data.empty()) {
      header = "data:application/gltf-buffer;base64,";
      if (in.find(header) == 0) {
        data = Base64::decode(in.substr(header.size()));
      }
    }

    if (data.empty()) {
      return false;
    }

    if (checkSize) {
      if (data.size() != reqBytes) {
        return false;
      }
      out->resize(reqBytes);
    }
    else {
      out->resize(data.size());
    }
    std::copy(data.begin(), data.end(), out->begin());
    return true;
  };

  const auto LoadImageData = [](Image& image, int req_width, int req_height,
                                const unsigned char* bytes, int size, bool flipVertically) -> bool {
    int w = 0, h = 0, comp = 0, req_comp = 0;

    unsigned char* data = nullptr;

    // force 32-bit textures for common Vulkan compatibility. It appears that
    // some GPU drivers do not support 24-bit images for Vulkan
    req_comp = 4;
    int bits = 8;

    stbi_set_flip_vertically_on_load(flipVertically);

    // It is possible that the image we want to load is a 16bit per channel
    // image We are going to attempt to load it as 16bit per channel, and if it
    // worked, set the image data accodingly. We are casting the returned
    // pointer into unsigned char, because we are representing "bytes". But we
    // are updating the Image metadata to signal that this image uses 2 bytes
    // (16bits) per channel:
    if (stbi_is_16_bit_from_memory(bytes, size)) {
      data = reinterpret_cast<unsigned char*>(
        stbi_load_16_from_memory(bytes, size, &w, &h, &comp, req_comp));
      if (data) {
        bits = 16;
      }
    }

    // at this point, if data is still NULL, it means that the image wasn't
    // 16bit per channel, we are going to load it as a normal 8bit per channel
    // mage as we used to do:
    // if image cannot be decoded, ignore parsing and keep it by its path
    // don't break in this case
    // FIXME we should only enter this function if the image is embedded. If
    // image->uri references
    // an image file, it should be left as it is. Image loading should not be
    // mandatory (to support other formats)
    if (!data)
      data = stbi_load_from_memory(bytes, size, &w, &h, &comp, req_comp);
    if (!data) {
      BABYLON_LOG_WARN("StringToImage",
                       "Unknown image format. STB cannot decode image data for image")
      return false;
    }

    stbi_set_flip_vertically_on_load(false);

    if ((w < 1) || (h < 1)) {
      stbi_image_free(data);
      BABYLON_LOG_ERROR("StringToImage", "Invalid image data for image")
      return false;
    }

    if (req_width > 0) {
      if (req_width != w) {
        stbi_image_free(data);
        BABYLON_LOG_ERROR("StringToImage", "Image width mismatch for image")
        return false;
      }
    }

    if (req_height > 0) {
      if (req_height != h) {
        stbi_image_free(data);
        BABYLON_LOG_ERROR("StringToImage", "Image height mismatch. for image")
        return false;
      }
    }

    image.width  = w;
    image.height = h;
    image.depth  = req_comp;
    image.mode   = (req_comp == 3) ? GL::RGB : GL::RGBA;
    image.data.resize(static_cast<size_t>(w * h * req_comp) * size_t(bits / 8));
    std::copy(data, data + w * h * req_comp * (bits / 8), image.data.begin());
    stbi_image_free(data);

    return true;
  };

  Image image;
  std::vector<unsigned char> img;
  std::string mimeType;
  if (IsDataURI(uri)) {
    if (!DecodeDataURI(&img, mimeType, uri, 0, false)) {
      BABYLON_LOG_ERROR("Failed to decode image from uri: %s", uri.c_str())
      return Image();
    }
  }

  if (LoadImageData(image, 0, 0, &img.at(0), static_cast<int>(img.size()), flipVertically)) {
    return image;
  }

  return Image();
}

void FileTools::LoadFile(
  const std::string& url,
  const std::function<void(const std::variant<std::string, ArrayBuffer>& data,
                           const std::string& responseURL)>& onSuccess,
  const std::function<void(const ProgressEvent& event)>& onProgress,
  bool useArrayBuffer,
  const std::function<void(const std::string& message, const std::string& exception)>& onError)
{
  // LoadFile's signature is extremely complicated for no good reason
  // Let's write some wrappers from the simple callbacks of BABYLON::asio
  // We will need to refactor this later

  // Superfluous params?
  constexpr const char * dummyResponseUrl = "";
  constexpr const char * dummyExceptionString = "";
  constexpr const char * dummyProgressType = "";

  std::string url_clean = FileTools::_CleanUrl(url);
  url_clean = FileTools::PreprocessUrl(url);

  auto onErrorWrapper = [onError](const std::string& errorMessage) {
    if (onError)
      onError(errorMessage, dummyExceptionString);
  };
  auto onProgressWrapper = [onProgress](bool lengthComputable, size_t loaded, size_t total) {
    if (onProgress)
      onProgress({dummyProgressType, lengthComputable, loaded, total});
  };

  if (useArrayBuffer)
  {
    auto onSuccessWrapper = [onSuccess](const ArrayBuffer& data) {
      if (onSuccess)
        onSuccess(data, dummyResponseUrl);
    };
    asio::LoadUrlAsync_Binary(url_clean, onSuccessWrapper, onErrorWrapper, onProgressWrapper);
  }
  else
  {
    auto onSuccessWrapper = [onSuccess](const std::string& data) {
      if (onSuccess) {
        onSuccess(data, dummyResponseUrl);
      }
    };
    asio::LoadUrlAsync_Text(url_clean, onSuccessWrapper, onErrorWrapper, onProgressWrapper);
  }

  //asio::Service_WaitAll_Sync();
  //std::cout << "WaitAll finished\n";
}

} // end of namespace BABYLON
<|endoftext|>


<commit_before>#include "pch.h"
#include "axl_enc_EscapeEncoding.h"
#include "axl_enc_HexEncoding.h"

namespace axl {
namespace enc {

//.............................................................................

char
EscapeEncoding::findEscapeChar (char x)
{
	switch (x)
	{
	case '\0':
		return '0';

	case '\a':
		return 'a';

	case '\b':
		return 'b';

	case '\t':
		return 't';

	case '\n':
		return 'n';

	case '\f':
		return 'f';

	case '\r':
		return 'r';

	case '\x1b':
		return 'e';

	default:
		return x;
	};
}

char
EscapeEncoding::findEscapeReplaceChar (char x)
{
	switch (x)
	{
	case '0':
		return '\0';

	case 'a':
		return '\a';

	case 'b':
		return '\b';

	case 't':
		return '\t';

	case 'n':
		return '\n';

	case 'f':
		return '\f';

	case 'r':
		return '\r';

	case 'e':
		return '\x1b';

	default:
		return x;
	};
}

size_t
EscapeEncoding::encode (
	sl::String* string,
	const char* p,
	size_t length
	)
{
	if (length == -1)
		length = axl_strlen (p);

	string->clear ();
	string->reserve (length);

	char escapeSequence [4] = { '\\' };

	const char* base = p;
	const char* end = p + length;
	for (; p < end; p++)
	{
		if (*p == '\\')
		{
			string->append (base, p - base);

			escapeSequence [1] = '\\';
			string->append (escapeSequence, 2);

			base = p + 1;
		}
		else
		{
			if (isprint (*p))
				continue;

			string->append (base, p - base);

			char escape = findEscapeChar (*p);
			if (escape != *p)
			{
				escapeSequence [1] = escape;
				string->append (escapeSequence, 2);
			}
			else
			{
				escapeSequence [1] = 'x';
				escapeSequence [2] = HexEncoding::getHexChar_l (*p >> 4);
				escapeSequence [3] = HexEncoding::getHexChar_l (*p);
				string->append (escapeSequence, 4);
			}

			base = p + 1;
		}
	}

	string->append (base, p - base);

	return string->getLength ();
}

static
inline
bool
isHexChar (char c)
{
	return
		c >= '0' && c <= '9' ||
		c >= 'a' && c <= 'f' ||
		c >= 'A' && c <= 'F';
}

size_t
EscapeEncoding::decode (
	sl::String* string,
	const char* p,
	size_t length
	)
{
	enum State
	{
		State_Normal = 0,
		State_Escape,
		State_Hex,
	};

	State state = State_Normal;

	if (length == -1)
		length = axl_strlen (p);

	string->clear ();
	string->reserve (length / 2);

	char hexCodeString [16];
	size_t hexCodeLen;
	size_t hexCodeMaxLen;
	ulong_t hexCode;

	char replace;

	const char* end = p + length;
	const char* base = p;
	for (; p < end; p++)
	{
		switch (state)
		{
		case State_Normal:
			if (*p == '\\')
			{
				string->append (base, p - base);
				state = State_Escape;
			}

			break;

		case State_Escape:
			switch (*p)
			{
			case 'x':
				state = State_Hex;
				hexCodeLen = 0;
				hexCodeMaxLen = 2;
				break;

			case 'u':
				state = State_Hex;
				hexCodeLen = 0;
				hexCodeMaxLen = 4;
				break;

			case 'U':
				state = State_Hex;
				hexCodeLen = 0;
				hexCodeMaxLen = 8;
				break;

			default:
				replace = findEscapeReplaceChar (*p);
				if (replace != *p)
				{
					string->append (replace);
					base = p + 1;
				}
				else
				{
					base = p;
				}

				state = State_Normal;
			}

			break;

		case State_Hex:
			if (isHexChar (*p))
			{
				hexCodeString [hexCodeLen++] = *p;
				if (hexCodeLen < hexCodeMaxLen)
					break;

				base = p + 1;
			}
			else
			{
				base = p;
			}

			if (!hexCodeLen)
			{
				hexCode = '?';
				string->append ((char const*) &hexCode, 1);
			}
			else
			{
				hexCodeString [hexCodeLen] = 0;
				hexCode = strtoul (hexCodeString, NULL, 16);

				if (hexCodeMaxLen == 2) // \x
				{
					string->append ((char const*) &hexCode, 1);
				}
				else // \u
				{
					utf8_t buffer [8];
					size_t length = enc::Utf8::getEncodeCodePointLength (hexCode);
					enc::Utf8::encodeCodePoint (buffer, hexCode);
					string->append (buffer, length);
				}
			}

			state = State_Normal;
			break;
		}
	}

	string->append (base, p - base);
	return string->getLength ();
}

//.............................................................................

} // namespace enc
} // namespace axl
<commit_msg>[axl] bugfix: after adding special handling of zero-utf32_t methods in sl::String enc::EscapeEncoding ::decode started to incorrectly parse \0 escape sequence. should use append (c, 1) instead<commit_after>#include "pch.h"
#include "axl_enc_EscapeEncoding.h"
#include "axl_enc_HexEncoding.h"

namespace axl {
namespace enc {

//.............................................................................

char
EscapeEncoding::findEscapeChar (char x)
{
	switch (x)
	{
	case '\0':
		return '0';

	case '\a':
		return 'a';

	case '\b':
		return 'b';

	case '\t':
		return 't';

	case '\n':
		return 'n';

	case '\f':
		return 'f';

	case '\r':
		return 'r';

	case '\x1b':
		return 'e';

	default:
		return x;
	};
}

char
EscapeEncoding::findEscapeReplaceChar (char x)
{
	switch (x)
	{
	case '0':
		return '\0';

	case 'a':
		return '\a';

	case 'b':
		return '\b';

	case 't':
		return '\t';

	case 'n':
		return '\n';

	case 'f':
		return '\f';

	case 'r':
		return '\r';

	case 'e':
		return '\x1b';

	default:
		return x;
	};
}

size_t
EscapeEncoding::encode (
	sl::String* string,
	const char* p,
	size_t length
	)
{
	if (length == -1)
		length = axl_strlen (p);

	string->clear ();
	string->reserve (length);

	char escapeSequence [4] = { '\\' };

	const char* base = p;
	const char* end = p + length;
	for (; p < end; p++)
	{
		if (*p == '\\')
		{
			string->append (base, p - base);

			escapeSequence [1] = '\\';
			string->append (escapeSequence, 2);

			base = p + 1;
		}
		else
		{
			if (isprint (*p))
				continue;

			string->append (base, p - base);

			char escape = findEscapeChar (*p);
			if (escape != *p)
			{
				escapeSequence [1] = escape;
				string->append (escapeSequence, 2);
			}
			else
			{
				escapeSequence [1] = 'x';
				escapeSequence [2] = HexEncoding::getHexChar_l (*p >> 4);
				escapeSequence [3] = HexEncoding::getHexChar_l (*p);
				string->append (escapeSequence, 4);
			}

			base = p + 1;
		}
	}

	string->append (base, p - base);

	return string->getLength ();
}

static
inline
bool
isHexChar (char c)
{
	return
		c >= '0' && c <= '9' ||
		c >= 'a' && c <= 'f' ||
		c >= 'A' && c <= 'F';
}

size_t
EscapeEncoding::decode (
	sl::String* string,
	const char* p,
	size_t length
	)
{
	enum State
	{
		State_Normal = 0,
		State_Escape,
		State_Hex,
	};

	State state = State_Normal;

	if (length == -1)
		length = axl_strlen (p);

	string->clear ();
	string->reserve (length / 2);

	char hexCodeString [16];
	size_t hexCodeLen;
	size_t hexCodeMaxLen;
	ulong_t hexCode;

	char replace;

	const char* end = p + length;
	const char* base = p;
	for (; p < end; p++)
	{
		switch (state)
		{
		case State_Normal:
			if (*p == '\\')
			{
				string->append (base, p - base);
				state = State_Escape;
			}

			break;

		case State_Escape:
			switch (*p)
			{
			case 'x':
				state = State_Hex;
				hexCodeLen = 0;
				hexCodeMaxLen = 2;
				break;

			case 'u':
				state = State_Hex;
				hexCodeLen = 0;
				hexCodeMaxLen = 4;
				break;

			case 'U':
				state = State_Hex;
				hexCodeLen = 0;
				hexCodeMaxLen = 8;
				break;

			default:
				replace = findEscapeReplaceChar (*p);
				if (replace != *p)
				{
					string->append (replace, 1);
					base = p + 1;
				}
				else
				{
					base = p;
				}

				state = State_Normal;
			}

			break;

		case State_Hex:
			if (isHexChar (*p))
			{
				hexCodeString [hexCodeLen++] = *p;
				if (hexCodeLen < hexCodeMaxLen)
					break;

				base = p + 1;
			}
			else
			{
				base = p;
			}

			if (!hexCodeLen)
			{
				hexCode = '?';
				string->append ((char const*) &hexCode, 1);
			}
			else
			{
				hexCodeString [hexCodeLen] = 0;
				hexCode = strtoul (hexCodeString, NULL, 16);

				if (hexCodeMaxLen == 2) // \x
				{
					string->append ((char const*) &hexCode, 1);
				}
				else // \u
				{
					utf8_t buffer [8];
					size_t length = enc::Utf8::getEncodeCodePointLength (hexCode);
					enc::Utf8::encodeCodePoint (buffer, hexCode);
					string->append (buffer, length);
				}
			}

			state = State_Normal;
			break;
		}
	}

	string->append (base, p - base);
	return string->getLength ();
}

//.............................................................................

} // namespace enc
} // namespace axl
<|endoftext|>


<commit_before>#include <iostream>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <EGL/eglplatform.h>
#include "libGLESv2/main.h"
#include "libGLESv2/Context.h"
#include "common/winrtangle.h"

#include <stdio.h>
#include <assert.h>
#include <vector>
#include <string>
#include <iostream>

static void usage();
static GLuint createShader(GLenum shaderType, const char **source, unsigned sourceCount);

#using <Windows.winmd>
#using <Platform.winmd>
using namespace Platform;
using namespace std;

namespace egl
{
struct Current
{
    EGLint error;
    EGLenum API;
    EGLDisplay display;
    EGLSurface drawSurface;
    EGLSurface readSurface;
};

static Current glContext;

void setCurrentError(EGLint error)
{
    glContext.error = error;
}

EGLint getCurrentError()
{
    return  glContext.error;
}

void setCurrentAPI(EGLenum API)
{
     glContext.API = API;
}

EGLenum getCurrentAPI()
{
    return glContext.API;
}

void setCurrentDisplay(EGLDisplay dpy)
{
    glContext.display = dpy;
}

EGLDisplay getCurrentDisplay()
{
    return glContext.display;
}

void setCurrentDrawSurface(EGLSurface surface)
{
    glContext.drawSurface = surface;
}

EGLSurface getCurrentDrawSurface()
{
    return glContext.drawSurface;
}

void setCurrentReadSurface(EGLSurface surface)
{
    glContext.readSurface = surface;
}

EGLSurface getCurrentReadSurface()
{
    return glContext.readSurface;
}

void error(EGLint errorCode)
{
    egl::setCurrentError(errorCode);
}

}

namespace gl
{

static gl::Current glContext;

void makeCurrent(Context *context, egl::Display *display, egl::Surface *surface)
{
    Current *current = (Current*)&glContext;

    current->context = context;
    current->display = display;

    if (context && display && surface)
    {
        context->makeCurrent(surface);
    }
}

Context *getContext()
{
    Current *current = (Current*)&glContext;

    return current->context;
}

Context *getNonLostContext()
{
    Context *context = getContext();

    if (context)
    {
        if (context->isContextLost())
        {
            gl::error(GL_OUT_OF_MEMORY);
            return NULL;
        }
        else
        {
            return context;
        }
    }
    return NULL;
}

egl::Display *getDisplay()
{
    Current *current = (Current*)&glContext;

    return current->display;
}

// Records an error code
void error(GLenum errorCode)
{
    gl::Context *context = glGetCurrentContext();

    if (context)
    {
        switch (errorCode)
        {
          case GL_INVALID_ENUM:
            context->recordInvalidEnum();
            TRACE("\t! Error generated: invalid enum\n");
            break;
          case GL_INVALID_VALUE:
            context->recordInvalidValue();
            TRACE("\t! Error generated: invalid value\n");
            break;
          case GL_INVALID_OPERATION:
            context->recordInvalidOperation();
            TRACE("\t! Error generated: invalid operation\n");
            break;
          case GL_OUT_OF_MEMORY:
            context->recordOutOfMemory();
            TRACE("\t! Error generated: out of memory\n");
            break;
          case GL_INVALID_FRAMEBUFFER_OPERATION:
            context->recordInvalidFramebufferOperation();
            TRACE("\t! Error generated: invalid framebuffer operation\n");
            break;
          default: UNREACHABLE();
        }
    }
}
}

bool InitializeAngle(EGLDisplay& display, EGLContext& context, ANGLE_D3D_FEATURE_LEVEL featureLevel)
{
	// setup EGL
	EGLint configAttribList[] = {
		EGL_RED_SIZE,       8,
		EGL_GREEN_SIZE,     8,
		EGL_BLUE_SIZE,      8,
		EGL_ALPHA_SIZE,     8,
		EGL_DEPTH_SIZE,     8,
		EGL_STENCIL_SIZE,   8,
		EGL_SAMPLE_BUFFERS, 0,
		EGL_NONE
	};

	EGLint surfaceAttribList[] = {
		EGL_NONE, EGL_NONE
	};

	EGLint numConfigs;
	EGLint majorVersion;
	EGLint minorVersion;
	EGLConfig config;
	EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE };

    IUnknown* dummy = nullptr;
    Microsoft::WRL::ComPtr<IWinrtEglWindow> eglWindow;
    HRESULT result = CreateWinrtEglWindow(WINRT_EGL_IUNKNOWN(dummy), featureLevel, eglWindow.GetAddressOf());
    if(!SUCCEEDED(result))
    {
        cout << "InitializeAngle: unable to create IWinrtEglWindow. HRESULT: " << result << endl;
        return false;
    }

	display = eglGetDisplay(eglWindow);
	if(display == EGL_NO_DISPLAY){
        cout << "InitializeAngle: couldn't get EGL display" << endl;
		return false;
	}

	if(!eglInitialize(display, &majorVersion, &minorVersion)){
        cout << "InitializeAngle: failed to initialize EGL" << endl;
		return false;
	}

	// Get configs
	if ( !eglGetConfigs(display, NULL, 0, &numConfigs) ){
        cout << "InitializeAngle: failed to get display configurations" << endl;
		return false;
	}

	// Choose config
	if(!eglChooseConfig(display, configAttribList, &config, 1, &numConfigs)){
        cout << "InitializeAngle: failed to choose display configurations" << endl;
		return false;
	}

	// Create a GL context
	context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
	if(context == EGL_NO_CONTEXT){
        cout << "InitializeAngle: failed to create EGL context" << endl;
		return false;
	}

	// Make the context current
    // Note: we are not using a surface
	if (!eglMakeCurrent(display, NULL, NULL, context)){
        cout << "InitializeAngle: failed to make EGL context current" << endl;
		return false;
	}

    return true;
}

GLuint createShader(GLenum shaderType, const char **source, unsigned sourceCount)
{
    GLuint shader = glCreateShader(shaderType);
    glShaderSource(shader, sourceCount, source, NULL);
    glCompileShader(shader);
    int compileStatus;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);

    if(compileStatus != GL_TRUE)
    {
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &compileStatus);
        char *sourceBuffer = new char[compileStatus];
        char *shaderTypeName = (shaderType == GL_VERTEX_SHADER) ? "vertex shader(s)" : "fragment shader(s)";
        glGetShaderInfoLog(shader, compileStatus, NULL, sourceBuffer);
        printf("Failed to compile %s due to:\n%s\n", shaderTypeName, sourceBuffer);
        delete [] sourceBuffer;
        glDeleteShader(shader);
        return 0;
    }
    return shader;
}

//
//   print usage to stdout
//
void usage()
{
    printf("Usage: glslPrecompiler [-o=[file]  -p=[platform] -a=[variable]] -v=[vertex_shader_1] ... -v=[vertex_shader_1] -f=[fragment_shader_1] ... -f=[fragment_shader_n]\n"
        "Where: filename : filename ending in .frag or .vert\n"
        "       -o=[file] : output file\n"
        "       -p=[platform] : wp8 or winrt\n"
        "       -v=[variable] : output to char array named [variable] in header file, omit for binary file\n");
}

// -p=wp8 -o=shader.h -a=gProgram -v=shader.vert -f=shader.frag

[Platform::MTAThread]
int __cdecl main(int argc, char* argv[])
{
    EGLDisplay display = nullptr;
    EGLContext context = nullptr;

    GLuint vertexShader = 0;
    GLuint fragmentShader = 0;
    bool usageFail = false;
    bool outputToHeaderFile = false;
    std::string outputFile = "shader.file";
    char variableName[1024];
    std::vector<std::string> vertexShaders;
    std::vector<std::string> fragmentShaders;
    std::string platform = "";

    if (argc < 3)
        usageFail = TRUE;

    argc--;
    argv++;
    for (; (argc >= 1) && !usageFail; argc--, argv++) {
        if (argv[0][0] == '-') {
            switch (argv[0][1]) {
            case 'p':
                if (argv[0][2] == '=' && strlen(argv[0] + 3)) {
                    platform = argv[0] + 3;
                }
                break;
            case 'o':
                if (argv[0][2] == '=' && strlen(argv[0] + 3)) {
                    outputFile = argv[0] + 3;
                }
                break;
            case 'a':
                if (argv[0][2] == '=') {
                    strcpy(variableName, argv[0] + 3);
                    outputToHeaderFile = true;
                }
                break;
            case 'v':
            case 'f':
                {
                    if(argv[0][2] != '=')
                        break;

                    FILE *fp = fopen(argv[0] + 3, "r");
                    if(!fp)
                    {
                        printf("Can't open %s, aborting\n", argv[0]);
                        return 0;
                    }
                    fseek(fp, 0, SEEK_END);
                    int fileSize = ftell(fp);
                    rewind(fp);
                    char *sourceBuffer = new char[fileSize + 1];
                    fileSize = fread(sourceBuffer, 1, fileSize, fp);
                    fclose(fp);
                    sourceBuffer[fileSize] = 0;
                    if(argv[0][1] == 'v')
                        vertexShaders.push_back(sourceBuffer);
                    else
                        fragmentShaders.push_back(sourceBuffer);
                    delete [] sourceBuffer;
                }
                break;
            default: usageFail = true;
            }
        }
    }

    if (usageFail)
    {
        usage();
        return -1;
    }

    // we need to select the correct DirectX feature level depending on the platform
    // default is D3D_FEATURE_LEVEL_9_3 Windows Phone 8.0
    ANGLE_D3D_FEATURE_LEVEL featureLevel = ANGLE_D3D_FEATURE_LEVEL::ANGLE_D3D_FEATURE_LEVEL_9_1;

    if(platform == "winrt")
    {
#if (_MSC_VER >= 1800)
    // WinRT on Windows 8.1 can compile shaders at run time so we don't care about the DirectX feature level
        featureLevel = ANGLE_D3D_FEATURE_LEVEL::ANGLE_D3D_FEATURE_LEVEL_ANY;
        cout << "Compiling for WinRT at ANGLE_D3D_FEATURE_LEVEL_ANY" << endl;
#else
        featureLevel = ANGLE_D3D_FEATURE_LEVEL::ANGLE_D3D_FEATURE_LEVEL_9_1;
        cout << "Compiling for WinRT at ANGLE_D3D_FEATURE_LEVEL_9_1" << endl;
#endif
    }
    else if(platform == "wp8")
    {
        featureLevel = ANGLE_D3D_FEATURE_LEVEL::ANGLE_D3D_FEATURE_LEVEL_9_3;
        cout << "Compiling for Windows Phone 8 at ANGLE_D3D_FEATURE_LEVEL_9_3" << endl;
    }
    else
    {
#if (_MSC_VER >= 1800)
        cout << "Unknown target platform. Default to ANGLE_D3D_FEATURE_LEVEL_ANY" << endl;
        cout << "Compiling for WinRT at ANGLE_D3D_FEATURE_LEVEL_ANY" << endl;
#else
        cout << "Unknown target platform. Default to ANGLE_D3D_FEATURE_LEVEL_9_1" << endl;
#endif
    }

    if(!InitializeAngle(display, context, featureLevel))
    {
        return -1;
    }

    std::vector<const char*> vertexSources;
    std::vector<const char*> fragmentSources;
    for(unsigned i = 0; i < vertexShaders.size(); ++i)
        vertexSources.push_back(vertexShaders[i].c_str());
    for(unsigned i = 0; i < fragmentShaders.size(); ++i)
        fragmentSources.push_back(fragmentShaders[i].c_str());

    GLuint program = glCreateProgram();
    vertexShader = createShader(GL_VERTEX_SHADER, &vertexSources[0], vertexSources.size());
    if(!vertexShader)
        return 0;
    fragmentShader = createShader(GL_FRAGMENT_SHADER, &fragmentSources[0], vertexSources.size());
    if(!fragmentShader)
        return 0;
    glAttachShader(program, vertexShader);
    glAttachShader(program, fragmentShader);

    glLinkProgram(program);
    int linkStatus;
    glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);

    if(linkStatus != GL_TRUE)
    {
        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &linkStatus);
        char *infoLog = new char[linkStatus];
        glGetProgramInfoLog(program, linkStatus, NULL, infoLog);
        printf("Failed to link the shaders into a program due to:\n%s\n", infoLog);
        delete [] infoLog;
        glDeleteShader(vertexShader);
        glDeleteShader(fragmentShader);
        return 0;
    }
    glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &linkStatus);

    unsigned char *binary = new unsigned char[linkStatus];
    GLenum binaryFormat;
    glGetProgramBinaryOES(program, linkStatus, NULL, &binaryFormat, binary);
    if(outputToHeaderFile)
    {
        FILE *fp = fopen(outputFile.c_str(), "w");
        fprintf(fp, "unsigned char %s[] = {\n", variableName);
        fprintf(fp, "%3i, ", binary[0]);
        for(int i = 1; i < linkStatus - 1; ++i)
        {
            if(i % 8 == 0)
                fprintf(fp, "\n");
            fprintf(fp, "%3i, ", binary[i]);
        }
        if((linkStatus - 1) % 8 == 0)
            fprintf(fp, "\n");
        fprintf(fp, "%3i\n};", binary[linkStatus - 1]);
        fclose(fp);
    }
    else
    {
        FILE *fp = fopen(outputFile.c_str(), "wb");
        fwrite(binary, linkStatus, 1, fp);
        fclose(fp);
    }
    delete [] binary;
    printf("Compilation successful\n");
    eglMakeCurrent(NULL, NULL, NULL, NULL);

    if(display && context)
    {
        eglDestroyContext(display, context);
    }
    if(display)
    {
        eglTerminate(display);
   }

    return 0;
}

<commit_msg>removed check for msc_ver >= 1800 for winrt option<commit_after>#include <iostream>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <EGL/eglplatform.h>
#include "libGLESv2/main.h"
#include "libGLESv2/Context.h"
#include "common/winrtangle.h"

#include <stdio.h>
#include <assert.h>
#include <vector>
#include <string>
#include <iostream>

static void usage();
static GLuint createShader(GLenum shaderType, const char **source, unsigned sourceCount);

#using <Windows.winmd>
#using <Platform.winmd>
using namespace Platform;
using namespace std;

namespace egl
{
struct Current
{
    EGLint error;
    EGLenum API;
    EGLDisplay display;
    EGLSurface drawSurface;
    EGLSurface readSurface;
};

static Current glContext;

void setCurrentError(EGLint error)
{
    glContext.error = error;
}

EGLint getCurrentError()
{
    return  glContext.error;
}

void setCurrentAPI(EGLenum API)
{
     glContext.API = API;
}

EGLenum getCurrentAPI()
{
    return glContext.API;
}

void setCurrentDisplay(EGLDisplay dpy)
{
    glContext.display = dpy;
}

EGLDisplay getCurrentDisplay()
{
    return glContext.display;
}

void setCurrentDrawSurface(EGLSurface surface)
{
    glContext.drawSurface = surface;
}

EGLSurface getCurrentDrawSurface()
{
    return glContext.drawSurface;
}

void setCurrentReadSurface(EGLSurface surface)
{
    glContext.readSurface = surface;
}

EGLSurface getCurrentReadSurface()
{
    return glContext.readSurface;
}

void error(EGLint errorCode)
{
    egl::setCurrentError(errorCode);
}

}

namespace gl
{

static gl::Current glContext;

void makeCurrent(Context *context, egl::Display *display, egl::Surface *surface)
{
    Current *current = (Current*)&glContext;

    current->context = context;
    current->display = display;

    if (context && display && surface)
    {
        context->makeCurrent(surface);
    }
}

Context *getContext()
{
    Current *current = (Current*)&glContext;

    return current->context;
}

Context *getNonLostContext()
{
    Context *context = getContext();

    if (context)
    {
        if (context->isContextLost())
        {
            gl::error(GL_OUT_OF_MEMORY);
            return NULL;
        }
        else
        {
            return context;
        }
    }
    return NULL;
}

egl::Display *getDisplay()
{
    Current *current = (Current*)&glContext;

    return current->display;
}

// Records an error code
void error(GLenum errorCode)
{
    gl::Context *context = glGetCurrentContext();

    if (context)
    {
        switch (errorCode)
        {
          case GL_INVALID_ENUM:
            context->recordInvalidEnum();
            TRACE("\t! Error generated: invalid enum\n");
            break;
          case GL_INVALID_VALUE:
            context->recordInvalidValue();
            TRACE("\t! Error generated: invalid value\n");
            break;
          case GL_INVALID_OPERATION:
            context->recordInvalidOperation();
            TRACE("\t! Error generated: invalid operation\n");
            break;
          case GL_OUT_OF_MEMORY:
            context->recordOutOfMemory();
            TRACE("\t! Error generated: out of memory\n");
            break;
          case GL_INVALID_FRAMEBUFFER_OPERATION:
            context->recordInvalidFramebufferOperation();
            TRACE("\t! Error generated: invalid framebuffer operation\n");
            break;
          default: UNREACHABLE();
        }
    }
}
}

bool InitializeAngle(EGLDisplay& display, EGLContext& context, ANGLE_D3D_FEATURE_LEVEL featureLevel)
{
	// setup EGL
	EGLint configAttribList[] = {
		EGL_RED_SIZE,       8,
		EGL_GREEN_SIZE,     8,
		EGL_BLUE_SIZE,      8,
		EGL_ALPHA_SIZE,     8,
		EGL_DEPTH_SIZE,     8,
		EGL_STENCIL_SIZE,   8,
		EGL_SAMPLE_BUFFERS, 0,
		EGL_NONE
	};

	EGLint surfaceAttribList[] = {
		EGL_NONE, EGL_NONE
	};

	EGLint numConfigs;
	EGLint majorVersion;
	EGLint minorVersion;
	EGLConfig config;
	EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE };

    IUnknown* dummy = nullptr;
    Microsoft::WRL::ComPtr<IWinrtEglWindow> eglWindow;
    HRESULT result = CreateWinrtEglWindow(WINRT_EGL_IUNKNOWN(dummy), featureLevel, eglWindow.GetAddressOf());
    if(!SUCCEEDED(result))
    {
        cout << "InitializeAngle: unable to create IWinrtEglWindow. HRESULT: " << result << endl;
        return false;
    }

	display = eglGetDisplay(eglWindow);
	if(display == EGL_NO_DISPLAY){
        cout << "InitializeAngle: couldn't get EGL display" << endl;
		return false;
	}

	if(!eglInitialize(display, &majorVersion, &minorVersion)){
        cout << "InitializeAngle: failed to initialize EGL" << endl;
		return false;
	}

	// Get configs
	if ( !eglGetConfigs(display, NULL, 0, &numConfigs) ){
        cout << "InitializeAngle: failed to get display configurations" << endl;
		return false;
	}

	// Choose config
	if(!eglChooseConfig(display, configAttribList, &config, 1, &numConfigs)){
        cout << "InitializeAngle: failed to choose display configurations" << endl;
		return false;
	}

	// Create a GL context
	context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
	if(context == EGL_NO_CONTEXT){
        cout << "InitializeAngle: failed to create EGL context" << endl;
		return false;
	}

	// Make the context current
    // Note: we are not using a surface
	if (!eglMakeCurrent(display, NULL, NULL, context)){
        cout << "InitializeAngle: failed to make EGL context current" << endl;
		return false;
	}

    return true;
}

GLuint createShader(GLenum shaderType, const char **source, unsigned sourceCount)
{
    GLuint shader = glCreateShader(shaderType);
    glShaderSource(shader, sourceCount, source, NULL);
    glCompileShader(shader);
    int compileStatus;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);

    if(compileStatus != GL_TRUE)
    {
        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &compileStatus);
        char *sourceBuffer = new char[compileStatus];
        char *shaderTypeName = (shaderType == GL_VERTEX_SHADER) ? "vertex shader(s)" : "fragment shader(s)";
        glGetShaderInfoLog(shader, compileStatus, NULL, sourceBuffer);
        printf("Failed to compile %s due to:\n%s\n", shaderTypeName, sourceBuffer);
        delete [] sourceBuffer;
        glDeleteShader(shader);
        return 0;
    }
    return shader;
}

//
//   print usage to stdout
//
void usage()
{
    printf("Usage: glslPrecompiler [-o=[file]  -p=[platform] -a=[variable]] -v=[vertex_shader_1] ... -v=[vertex_shader_1] -f=[fragment_shader_1] ... -f=[fragment_shader_n]\n"
        "Where: filename : filename ending in .frag or .vert\n"
        "       -o=[file] : output file\n"
        "       -p=[platform] : wp8 or winrt\n"
        "       -v=[variable] : output to char array named [variable] in header file, omit for binary file\n");
}

// -p=wp8 -o=shader.h -a=gProgram -v=shader.vert -f=shader.frag

[Platform::MTAThread]
int __cdecl main(int argc, char* argv[])
{
    EGLDisplay display = nullptr;
    EGLContext context = nullptr;

    GLuint vertexShader = 0;
    GLuint fragmentShader = 0;
    bool usageFail = false;
    bool outputToHeaderFile = false;
    std::string outputFile = "shader.file";
    char variableName[1024];
    std::vector<std::string> vertexShaders;
    std::vector<std::string> fragmentShaders;
    std::string platform = "";

    if (argc < 3)
        usageFail = TRUE;

    argc--;
    argv++;
    for (; (argc >= 1) && !usageFail; argc--, argv++) {
        if (argv[0][0] == '-') {
            switch (argv[0][1]) {
            case 'p':
                if (argv[0][2] == '=' && strlen(argv[0] + 3)) {
                    platform = argv[0] + 3;
                }
                break;
            case 'o':
                if (argv[0][2] == '=' && strlen(argv[0] + 3)) {
                    outputFile = argv[0] + 3;
                }
                break;
            case 'a':
                if (argv[0][2] == '=') {
                    strcpy(variableName, argv[0] + 3);
                    outputToHeaderFile = true;
                }
                break;
            case 'v':
            case 'f':
                {
                    if(argv[0][2] != '=')
                        break;

                    FILE *fp = fopen(argv[0] + 3, "r");
                    if(!fp)
                    {
                        printf("Can't open %s, aborting\n", argv[0]);
                        return 0;
                    }
                    fseek(fp, 0, SEEK_END);
                    int fileSize = ftell(fp);
                    rewind(fp);
                    char *sourceBuffer = new char[fileSize + 1];
                    fileSize = fread(sourceBuffer, 1, fileSize, fp);
                    fclose(fp);
                    sourceBuffer[fileSize] = 0;
                    if(argv[0][1] == 'v')
                        vertexShaders.push_back(sourceBuffer);
                    else
                        fragmentShaders.push_back(sourceBuffer);
                    delete [] sourceBuffer;
                }
                break;
            default: usageFail = true;
            }
        }
    }

    if (usageFail)
    {
        usage();
        return -1;
    }

    // we need to select the correct DirectX feature level depending on the platform
    // default is D3D_FEATURE_LEVEL_9_3 Windows Phone 8.0
    ANGLE_D3D_FEATURE_LEVEL featureLevel = ANGLE_D3D_FEATURE_LEVEL::ANGLE_D3D_FEATURE_LEVEL_9_1;

    if(platform == "winrt")
    {
        featureLevel = ANGLE_D3D_FEATURE_LEVEL::ANGLE_D3D_FEATURE_LEVEL_9_1;
        cout << "Compiling for WinRT at ANGLE_D3D_FEATURE_LEVEL_9_1" << endl;
    }
    else if(platform == "wp8")
    {
        featureLevel = ANGLE_D3D_FEATURE_LEVEL::ANGLE_D3D_FEATURE_LEVEL_9_3;
        cout << "Compiling for Windows Phone 8 at ANGLE_D3D_FEATURE_LEVEL_9_3" << endl;
    }
    else
    {
#if (_MSC_VER >= 1800)
        cout << "Unknown target platform. Default to ANGLE_D3D_FEATURE_LEVEL_ANY" << endl;
        cout << "Compiling for WinRT at ANGLE_D3D_FEATURE_LEVEL_ANY" << endl;
#else
        cout << "Unknown target platform. Default to ANGLE_D3D_FEATURE_LEVEL_9_1" << endl;
#endif
    }

    if(!InitializeAngle(display, context, featureLevel))
    {
        return -1;
    }

    std::vector<const char*> vertexSources;
    std::vector<const char*> fragmentSources;
    for(unsigned i = 0; i < vertexShaders.size(); ++i)
        vertexSources.push_back(vertexShaders[i].c_str());
    for(unsigned i = 0; i < fragmentShaders.size(); ++i)
        fragmentSources.push_back(fragmentShaders[i].c_str());

    GLuint program = glCreateProgram();
    vertexShader = createShader(GL_VERTEX_SHADER, &vertexSources[0], vertexSources.size());
    if(!vertexShader)
        return 0;
    fragmentShader = createShader(GL_FRAGMENT_SHADER, &fragmentSources[0], vertexSources.size());
    if(!fragmentShader)
        return 0;
    glAttachShader(program, vertexShader);
    glAttachShader(program, fragmentShader);

    glLinkProgram(program);
    int linkStatus;
    glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);

    if(linkStatus != GL_TRUE)
    {
        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &linkStatus);
        char *infoLog = new char[linkStatus];
        glGetProgramInfoLog(program, linkStatus, NULL, infoLog);
        printf("Failed to link the shaders into a program due to:\n%s\n", infoLog);
        delete [] infoLog;
        glDeleteShader(vertexShader);
        glDeleteShader(fragmentShader);
        return 0;
    }
    glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &linkStatus);

    unsigned char *binary = new unsigned char[linkStatus];
    GLenum binaryFormat;
    glGetProgramBinaryOES(program, linkStatus, NULL, &binaryFormat, binary);
    if(outputToHeaderFile)
    {
        FILE *fp = fopen(outputFile.c_str(), "w");
        fprintf(fp, "unsigned char %s[] = {\n", variableName);
        fprintf(fp, "%3i, ", binary[0]);
        for(int i = 1; i < linkStatus - 1; ++i)
        {
            if(i % 8 == 0)
                fprintf(fp, "\n");
            fprintf(fp, "%3i, ", binary[i]);
        }
        if((linkStatus - 1) % 8 == 0)
            fprintf(fp, "\n");
        fprintf(fp, "%3i\n};", binary[linkStatus - 1]);
        fclose(fp);
    }
    else
    {
        FILE *fp = fopen(outputFile.c_str(), "wb");
        fwrite(binary, linkStatus, 1, fp);
        fclose(fp);
    }
    delete [] binary;
    printf("Compilation successful\n");
    eglMakeCurrent(NULL, NULL, NULL, NULL);

    if(display && context)
    {
        eglDestroyContext(display, context);
    }
    if(display)
    {
        eglTerminate(display);
   }

    return 0;
}

<|endoftext|>


<commit_before>/*****************************************************************************
 *                                                                           *
 *  Copyright (c) 2016 Boris Pek <tehnick-8@yandex.ru>                       *
 *                                                                           *
 *  Permission is hereby granted, free of charge, to any person obtaining    *
 *  a copy of this software and associated documentation files (the          *
 *  "Software"), to deal in the Software without restriction, including      *
 *  without limitation the rights to use, copy, modify, merge, publish,      *
 *  distribute, sublicense, and/or sell copies of the Software, and to       *
 *  permit persons to whom the Software is furnished to do so, subject to    *
 *  the following conditions:                                                *
 *                                                                           *
 *  The above copyright notice and this permission notice shall be included  *
 *  in all copies or substantial portions of the Software.                   *
 *                                                                           *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,          *
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF       *
 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
 *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY     *
 *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,     *
 *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE        *
 *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                   *
 *                                                                           *
 *****************************************************************************/

#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QProcess>
#include <QByteArray>
#include <QJsonObject>
#include <QJsonDocument>

#include "logmanager.h"
#include "applicationsettings.h"
#include "resourcemanager.h"
#include "datafilewithlimitedaccess.h"

DataFileWithLimitedAccess::DataFileWithLimitedAccess(const Request &request,
                                                     const QString &projectName,
                                                     const QString &fileName) :
    HtmlPage(request)
{
    if (request.get("ajax").isEmpty()) {
        generateHtmlTemplate(projectName, fileName);
    }
    else {
        generateAjaxResponse(request, projectName, fileName);
    }
    show();
}

bool DataFileWithLimitedAccess::isAllowedAccess(const QString &projectName,
                                                const QString &fileName) const
{
    if (isAdmin())
        return true;

    const UserSettings &us = userSettings();
    const QJsonObject &&obj = us.getObject("projects");

    if (!obj.contains(projectName))
        return false;

    const QString &&role = obj[projectName].toString();

    if (role == "tester") {
        static const QStringList logFiles = {
            "build.log",
            "cppcheck.log",
            "cppcheck.html"
        };
        for (const auto &f : logFiles) {
            if (fileName.contains(f)) {
                return false;
            }
        }
        return true;
    }

    return (role == "developer" || role == "owner");
}

void DataFileWithLimitedAccess::generateHtmlTemplate(const QString &projectName,
                                                     const QString &fileName)
{
    if (isAutorizedUser()) {
        if (isAllowedAccess(projectName, fileName)) {
            ResourceManager res(APP_S().cacheDirectory() + "/projects");
            res.addPath(APP_S().buildServerBinDir());
            if (!res.contains(fileName) && fileName.endsWith(".zip")) {
                makeArchive(projectName, fileName);
            }
            if (res.contains(fileName)) {
                setData(res.read(fileName));
                autodetectContentType(fileName);
            }
            else {
                update();
            }
        }
        else {
            forbidAccess();
            update();
        }
    }
    else {
        forbidAccess();
        forceAuthorization();
        update();
    }
}

void DataFileWithLimitedAccess::generateAjaxResponse(const Request &request,
                                                     const QString &projectName,
                                                     const QString &fileName)
{
    if (!isAutorizedUser())
        return;

    if (!isAllowedAccess(projectName, fileName))
        return;

    if (!request.isPost())
        return;

    if (request.post("id").isEmpty())
        return;

    const QString &&cacheDirPath = APP_S().cacheDirectory() + "/projects";
    const QString &&binDirPath   = APP_S().buildServerBinDir();

    ResourceManager res(cacheDirPath);
    res.addPath(binDirPath);
    if (!res.contains(fileName) && fileName.endsWith(".zip")) {
        makeArchive(projectName, fileName);
    }

    if (!res.contains(fileName))
        return;

    const QByteArray &&data = res.read(fileName);

    const auto sha256sum = [&data]() {
        const QByteArray &&out =
                QCryptographicHash::hash(data, QCryptographicHash::Sha256)
                .toHex();
        return QString::fromLatin1(out);
    };

    const QJsonObject out = {
        {"id",          request.post("id")},
        {"file_name",   QFileInfo(fileName).fileName()},
        {"size",        data.size()},
        {"sha256sum",   sha256sum()}
    };
    setData(QJsonDocument(out).toJson());
}

bool DataFileWithLimitedAccess::makeArchive(const QString &projectName,
                                            const QString &fileName) const
{
    if (projectName.isEmpty() || fileName.isEmpty())
        return false;

    const int idx = fileName.lastIndexOf("/");
    if (idx < 0)
        return false;

    // Directory with files for archiving:
    const QString in = APP_S().buildServerBinDir() + "/" + fileName.mid(0, idx);

    if (!QDir(in).exists())
        return false;

    // Archive file:
    const QString out = APP_S().cacheDirectory() + "/projects/" + fileName;

    QFile f(out + ".lock");
    if (f.exists()) {
        return false;
    }
    else {
        QDir().mkpath(QFileInfo(f).absolutePath());
        if (f.open(QIODevice::OpenModeFlag::WriteOnly)) {
            f.close();
        }
        else {
            return false;
        }
    }

    const QString program = "zip";
    const QStringList arguments = {
        "-rq9",
        QFileInfo(out).absoluteFilePath(),
        QFileInfo(in).fileName(),
        "-x '*.log'"
    };
    QProcess process;
    process.setWorkingDirectory(QFileInfo(in).absolutePath());
    process.start(program, arguments);
    process.waitForFinished(300000); // limit by 5 minutes

    f.remove();
    return (process.exitStatus() == QProcess::NormalExit);
}

<commit_msg>BuildResultsPage: reply to ajax request from any authorized user.<commit_after>/*****************************************************************************
 *                                                                           *
 *  Copyright (c) 2016 Boris Pek <tehnick-8@yandex.ru>                       *
 *                                                                           *
 *  Permission is hereby granted, free of charge, to any person obtaining    *
 *  a copy of this software and associated documentation files (the          *
 *  "Software"), to deal in the Software without restriction, including      *
 *  without limitation the rights to use, copy, modify, merge, publish,      *
 *  distribute, sublicense, and/or sell copies of the Software, and to       *
 *  permit persons to whom the Software is furnished to do so, subject to    *
 *  the following conditions:                                                *
 *                                                                           *
 *  The above copyright notice and this permission notice shall be included  *
 *  in all copies or substantial portions of the Software.                   *
 *                                                                           *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,          *
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF       *
 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
 *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY     *
 *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,     *
 *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE        *
 *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                   *
 *                                                                           *
 *****************************************************************************/

#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QProcess>
#include <QByteArray>
#include <QJsonObject>
#include <QJsonDocument>

#include "logmanager.h"
#include "applicationsettings.h"
#include "resourcemanager.h"
#include "datafilewithlimitedaccess.h"

DataFileWithLimitedAccess::DataFileWithLimitedAccess(const Request &request,
                                                     const QString &projectName,
                                                     const QString &fileName) :
    HtmlPage(request)
{
    if (request.get("ajax").isEmpty()) {
        generateHtmlTemplate(projectName, fileName);
    }
    else {
        generateAjaxResponse(request, projectName, fileName);
    }
    show();
}

bool DataFileWithLimitedAccess::isAllowedAccess(const QString &projectName,
                                                const QString &fileName) const
{
    if (isAdmin())
        return true;

    const UserSettings &us = userSettings();
    const QJsonObject &&obj = us.getObject("projects");

    if (!obj.contains(projectName))
        return false;

    const QString &&role = obj[projectName].toString();

    if (role == "tester") {
        static const QStringList logFiles = {
            "build.log",
            "cppcheck.log",
            "cppcheck.html"
        };
        for (const auto &f : logFiles) {
            if (fileName.contains(f)) {
                return false;
            }
        }
        return true;
    }

    return (role == "developer" || role == "owner");
}

void DataFileWithLimitedAccess::generateHtmlTemplate(const QString &projectName,
                                                     const QString &fileName)
{
    if (isAutorizedUser()) {
        if (isAllowedAccess(projectName, fileName)) {
            ResourceManager res(APP_S().cacheDirectory() + "/projects");
            res.addPath(APP_S().buildServerBinDir());
            if (!res.contains(fileName) && fileName.endsWith(".zip")) {
                makeArchive(projectName, fileName);
            }
            if (res.contains(fileName)) {
                setData(res.read(fileName));
                autodetectContentType(fileName);
            }
            else {
                update();
            }
        }
        else {
            forbidAccess();
            update();
        }
    }
    else {
        forbidAccess();
        forceAuthorization();
        update();
    }
}

void DataFileWithLimitedAccess::generateAjaxResponse(const Request &request,
                                                     const QString &projectName,
                                                     const QString &fileName)
{
    if (!isAutorizedUser())
        return;

    if (!request.isPost())
        return;

    if (request.post("id").isEmpty())
        return;

    if (!isAllowedAccess(projectName, fileName)) {
        const QJsonObject out = {
            {"id",          request.post("id")},
            {"file_name",   QFileInfo(fileName).fileName()},
            {"size",        0},
            {"sha256sum",   "?"}
        };
        setData(QJsonDocument(out).toJson());
        return;
    }

    const QString &&cacheDirPath = APP_S().cacheDirectory() + "/projects";
    const QString &&binDirPath   = APP_S().buildServerBinDir();

    ResourceManager res(cacheDirPath);
    res.addPath(binDirPath);
    if (!res.contains(fileName) && fileName.endsWith(".zip")) {
        makeArchive(projectName, fileName);
    }

    if (!res.contains(fileName))
        return;

    const QByteArray &&data = res.read(fileName);

    const auto sha256sum = [&data]() {
        const QByteArray &&out =
                QCryptographicHash::hash(data, QCryptographicHash::Sha256)
                .toHex();
        return QString::fromLatin1(out);
    };

    const QJsonObject out = {
        {"id",          request.post("id")},
        {"file_name",   QFileInfo(fileName).fileName()},
        {"size",        data.size()},
        {"sha256sum",   sha256sum()}
    };
    setData(QJsonDocument(out).toJson());
}

bool DataFileWithLimitedAccess::makeArchive(const QString &projectName,
                                            const QString &fileName) const
{
    if (projectName.isEmpty() || fileName.isEmpty())
        return false;

    const int idx = fileName.lastIndexOf("/");
    if (idx < 0)
        return false;

    // Directory with files for archiving:
    const QString in = APP_S().buildServerBinDir() + "/" + fileName.mid(0, idx);

    if (!QDir(in).exists())
        return false;

    // Archive file:
    const QString out = APP_S().cacheDirectory() + "/projects/" + fileName;

    QFile f(out + ".lock");
    if (f.exists()) {
        return false;
    }
    else {
        QDir().mkpath(QFileInfo(f).absolutePath());
        if (f.open(QIODevice::OpenModeFlag::WriteOnly)) {
            f.close();
        }
        else {
            return false;
        }
    }

    const QString program = "zip";
    const QStringList arguments = {
        "-rq9",
        QFileInfo(out).absoluteFilePath(),
        QFileInfo(in).fileName(),
        "-x '*.log'"
    };
    QProcess process;
    process.setWorkingDirectory(QFileInfo(in).absolutePath());
    process.start(program, arguments);
    process.waitForFinished(300000); // limit by 5 minutes

    f.remove();
    return (process.exitStatus() == QProcess::NormalExit);
}

<|endoftext|>