<commit_before>// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <algorithm>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>

#include "flutter/fml/native_library.h"
#include "flutter/fml/paths.h"
#include "flutter/fml/size.h"
#include "flutter/shell/version/version.h"

// Include once for the default enum definition.
#include "flutter/shell/common/switches.h"

#undef SHELL_COMMON_SWITCHES_H_

struct SwitchDesc {
  flutter::Switch sw;
  const std::string_view flag;
  const char* help;
};

#undef DEF_SWITCHES_START
#undef DEF_SWITCH
#undef DEF_SWITCHES_END

// clang-format off
#define DEF_SWITCHES_START static const struct SwitchDesc gSwitchDescs[] = {
#define DEF_SWITCH(p_swtch, p_flag, p_help) \
  { flutter::Switch:: p_swtch, p_flag, p_help },
#define DEF_SWITCHES_END };
// clang-format on

// List of common and safe VM flags to allow to be passed directly to the VM.
#if FLUTTER_RELEASE

// clang-format off
static const std::string gDartFlagsWhitelist[] = {
    "--no-causal_async_stacks",
    "--lazy_async_stacks",
};
// clang-format on

#else

// clang-format off
static const std::string gDartFlagsWhitelist[] = {
    "--max_profile_depth",
    "--profile_period",
    "--random_seed",
    "--enable_mirrors",
    "--write-service-info",
    "--sample-buffer-duration",
    "--no-causal_async_stacks",
    "--lazy_async_stacks",
    "--trace-reload",
    "--trace-reload-verbose",
};
// clang-format on

#endif  // FLUTTER_RELEASE

// Include again for struct definition.
#include "flutter/shell/common/switches.h"

// Define symbols for the ICU data that is linked into the Flutter library on
// Android.  This is a workaround for crashes seen when doing dynamic lookups
// of the engine's own symbols on some older versions of Android.
#if OS_ANDROID
extern uint8_t _binary_icudtl_dat_start[];
extern uint8_t _binary_icudtl_dat_end[];

static std::unique_ptr<fml::Mapping> GetICUStaticMapping() {
  return std::make_unique<fml::NonOwnedMapping>(
      _binary_icudtl_dat_start,
      _binary_icudtl_dat_end - _binary_icudtl_dat_start);
}
#endif

namespace flutter {

void PrintUsage(const std::string& executable_name) {
  std::cerr << std::endl << "  " << executable_name << std::endl << std::endl;

  std::cerr << "Versions: " << std::endl << std::endl;

  std::cerr << "Flutter Engine Version: " << GetFlutterEngineVersion()
            << std::endl;
  std::cerr << "Skia Version: " << GetSkiaVersion() << std::endl;

  std::cerr << "Dart Version: " << GetDartVersion() << std::endl << std::endl;

  std::cerr << "Available Flags:" << std::endl;

  const uint32_t column_width = 80;

  const uint32_t flags_count = static_cast<uint32_t>(Switch::Sentinel);

  uint32_t max_width = 2;
  for (uint32_t i = 0; i < flags_count; i++) {
    auto desc = gSwitchDescs[i];
    max_width = std::max<uint32_t>(desc.flag.size() + 2, max_width);
  }

  const uint32_t help_width = column_width - max_width - 3;

  std::cerr << std::string(column_width, '-') << std::endl;
  for (uint32_t i = 0; i < flags_count; i++) {
    auto desc = gSwitchDescs[i];

    std::cerr << std::setw(max_width)
              << std::string("--") +
                     std::string{desc.flag.data(), desc.flag.size()}
              << " : ";

    std::istringstream stream(desc.help);
    int32_t remaining = help_width;

    std::string word;
    while (stream >> word && remaining > 0) {
      remaining -= (word.size() + 1);
      if (remaining <= 0) {
        std::cerr << std::endl
                  << std::string(max_width, ' ') << "   " << word << " ";
        remaining = help_width;
      } else {
        std::cerr << word << " ";
      }
    }

    std::cerr << std::endl;
  }
  std::cerr << std::string(column_width, '-') << std::endl;
}

const std::string_view FlagForSwitch(Switch swtch) {
  for (uint32_t i = 0; i < static_cast<uint32_t>(Switch::Sentinel); i++) {
    if (gSwitchDescs[i].sw == swtch) {
      return gSwitchDescs[i].flag;
    }
  }
  return std::string_view();
}

static bool IsWhitelistedDartVMFlag(const std::string& flag) {
  for (uint32_t i = 0; i < fml::size(gDartFlagsWhitelist); ++i) {
    const std::string& allowed = gDartFlagsWhitelist[i];
    // Check that the prefix of the flag matches one of the whitelisted flags.
    // We don't need to worry about cases like "--safe --sneaky_dangerous" as
    // the VM will discard these as a single unrecognized flag.
    if (std::equal(allowed.begin(), allowed.end(), flag.begin())) {
      return true;
    }
  }
  return false;
}

template <typename T>
static bool GetSwitchValue(const fml::CommandLine& command_line,
                           Switch sw,
                           T* result) {
  std::string switch_string;

  if (!command_line.GetOptionValue(FlagForSwitch(sw), &switch_string)) {
    return false;
  }

  std::stringstream stream(switch_string);
  T value = 0;
  if (stream >> value) {
    *result = value;
    return true;
  }

  return false;
}

std::unique_ptr<fml::Mapping> GetSymbolMapping(std::string symbol_prefix,
                                               std::string native_lib_path) {
  const uint8_t* mapping;
  intptr_t size;

  auto lookup_symbol = [&mapping, &size, symbol_prefix](
                           const fml::RefPtr<fml::NativeLibrary>& library) {
    mapping = library->ResolveSymbol((symbol_prefix + "_start").c_str());
    size = reinterpret_cast<intptr_t>(
        library->ResolveSymbol((symbol_prefix + "_size").c_str()));
  };

  fml::RefPtr<fml::NativeLibrary> library =
      fml::NativeLibrary::CreateForCurrentProcess();
  lookup_symbol(library);

  if (!(mapping && size)) {
    // Symbol lookup for the current process fails on some devices.  As a
    // fallback, try doing the lookup based on the path to the Flutter library.
    library = fml::NativeLibrary::Create(native_lib_path.c_str());
    lookup_symbol(library);
  }

  FML_CHECK(mapping && size) << "Unable to resolve symbols: " << symbol_prefix;
  return std::make_unique<fml::NonOwnedMapping>(mapping, size);
}

Settings SettingsFromCommandLine(const fml::CommandLine& command_line) {
  Settings settings = {};

  // Enable Observatory
  settings.enable_observatory =
      !command_line.HasOption(FlagForSwitch(Switch::DisableObservatory));

  // Set Observatory Host
  if (command_line.HasOption(FlagForSwitch(Switch::DeviceObservatoryHost))) {
    command_line.GetOptionValue(FlagForSwitch(Switch::DeviceObservatoryHost),
                                &settings.observatory_host);
  }
  // Default the observatory port based on --ipv6 if not set.
  if (settings.observatory_host.empty()) {
    settings.observatory_host =
        command_line.HasOption(FlagForSwitch(Switch::IPv6)) ? "::1"
                                                            : "127.0.0.1";
  }

  // Set Observatory Port
  if (command_line.HasOption(FlagForSwitch(Switch::DeviceObservatoryPort))) {
    if (!GetSwitchValue(command_line, Switch::DeviceObservatoryPort,
                        &settings.observatory_port)) {
      FML_LOG(INFO)
          << "Observatory port specified was malformed. Will default to "
          << settings.observatory_port;
    }
  }

  // Disable need for authentication codes for VM service communication, if
  // specified.
  settings.disable_service_auth_codes =
      command_line.HasOption(FlagForSwitch(Switch::DisableServiceAuthCodes));

  // Checked mode overrides.
  settings.disable_dart_asserts =
      command_line.HasOption(FlagForSwitch(Switch::DisableDartAsserts));

  settings.start_paused =
      command_line.HasOption(FlagForSwitch(Switch::StartPaused));

  settings.enable_checked_mode =
      command_line.HasOption(FlagForSwitch(Switch::EnableCheckedMode));

  settings.enable_dart_profiling =
      command_line.HasOption(FlagForSwitch(Switch::EnableDartProfiling));

  settings.enable_software_rendering =
      command_line.HasOption(FlagForSwitch(Switch::EnableSoftwareRendering));

  settings.endless_trace_buffer =
      command_line.HasOption(FlagForSwitch(Switch::EndlessTraceBuffer));

  settings.trace_startup =
      command_line.HasOption(FlagForSwitch(Switch::TraceStartup));

  settings.trace_skia =
      command_line.HasOption(FlagForSwitch(Switch::TraceSkia));

  settings.trace_systrace =
      command_line.HasOption(FlagForSwitch(Switch::TraceSystrace));

  settings.skia_deterministic_rendering_on_cpu =
      command_line.HasOption(FlagForSwitch(Switch::SkiaDeterministicRendering));

  settings.verbose_logging =
      command_line.HasOption(FlagForSwitch(Switch::VerboseLogging));

  command_line.GetOptionValue(FlagForSwitch(Switch::FlutterAssetsDir),
                              &settings.assets_path);

  std::vector<std::string_view> aot_shared_library_name =
      command_line.GetOptionValues(FlagForSwitch(Switch::AotSharedLibraryName));

  std::string snapshot_asset_path;
  command_line.GetOptionValue(FlagForSwitch(Switch::SnapshotAssetPath),
                              &snapshot_asset_path);

  std::string vm_snapshot_data_filename;
  command_line.GetOptionValue(FlagForSwitch(Switch::VmSnapshotData),
                              &vm_snapshot_data_filename);

  std::string vm_snapshot_instr_filename;
  command_line.GetOptionValue(FlagForSwitch(Switch::VmSnapshotInstructions),
                              &vm_snapshot_instr_filename);

  std::string isolate_snapshot_data_filename;
  command_line.GetOptionValue(FlagForSwitch(Switch::IsolateSnapshotData),
                              &isolate_snapshot_data_filename);

  std::string isolate_snapshot_instr_filename;
  command_line.GetOptionValue(
      FlagForSwitch(Switch::IsolateSnapshotInstructions),
      &isolate_snapshot_instr_filename);

  if (aot_shared_library_name.size() > 0) {
    for (std::string_view name : aot_shared_library_name) {
      settings.application_library_path.emplace_back(name);
    }
  } else if (snapshot_asset_path.size() > 0) {
    settings.vm_snapshot_data_path =
        fml::paths::JoinPaths({snapshot_asset_path, vm_snapshot_data_filename});
    settings.vm_snapshot_instr_path = fml::paths::JoinPaths(
        {snapshot_asset_path, vm_snapshot_instr_filename});
    settings.isolate_snapshot_data_path = fml::paths::JoinPaths(
        {snapshot_asset_path, isolate_snapshot_data_filename});
    settings.isolate_snapshot_instr_path = fml::paths::JoinPaths(
        {snapshot_asset_path, isolate_snapshot_instr_filename});
  }

  command_line.GetOptionValue(FlagForSwitch(Switch::CacheDirPath),
                              &settings.temp_directory_path);

  if (settings.icu_initialization_required) {
    command_line.GetOptionValue(FlagForSwitch(Switch::ICUDataFilePath),
                                &settings.icu_data_path);
    if (command_line.HasOption(FlagForSwitch(Switch::ICUSymbolPrefix))) {
      std::string icu_symbol_prefix, native_lib_path;
      command_line.GetOptionValue(FlagForSwitch(Switch::ICUSymbolPrefix),
                                  &icu_symbol_prefix);
      command_line.GetOptionValue(FlagForSwitch(Switch::ICUNativeLibPath),
                                  &native_lib_path);

#if OS_ANDROID
      settings.icu_mapper = GetICUStaticMapping;
#else
      settings.icu_mapper = [icu_symbol_prefix, native_lib_path] {
        return GetSymbolMapping(icu_symbol_prefix, native_lib_path);
      };
#endif
    }
  }

  settings.use_test_fonts =
      command_line.HasOption(FlagForSwitch(Switch::UseTestFonts));

  std::string all_dart_flags;
  if (command_line.GetOptionValue(FlagForSwitch(Switch::DartFlags),
                                  &all_dart_flags)) {
    std::stringstream stream(all_dart_flags);
    std::string flag;

    // Assume that individual flags are comma separated.
    while (std::getline(stream, flag, ',')) {
      if (!IsWhitelistedDartVMFlag(flag)) {
        FML_LOG(FATAL) << "Encountered blacklisted Dart VM flag: " << flag;
      }
      settings.dart_flags.push_back(flag);
    }
  }

#if !FLUTTER_RELEASE
  command_line.GetOptionValue(FlagForSwitch(Switch::LogTag), &settings.log_tag);
#endif

  settings.dump_skp_on_shader_compilation =
      command_line.HasOption(FlagForSwitch(Switch::DumpSkpOnShaderCompilation));

  settings.cache_sksl =
      command_line.HasOption(FlagForSwitch(Switch::CacheSkSL));

  return settings;
}

}  // namespace flutter
<commit_msg>Allow --enable-service-port-fallback as a whitelisted arg (#16167)<commit_after>// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <algorithm>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>

#include "flutter/fml/native_library.h"
#include "flutter/fml/paths.h"
#include "flutter/fml/size.h"
#include "flutter/shell/version/version.h"

// Include once for the default enum definition.
#include "flutter/shell/common/switches.h"

#undef SHELL_COMMON_SWITCHES_H_

struct SwitchDesc {
  flutter::Switch sw;
  const std::string_view flag;
  const char* help;
};

#undef DEF_SWITCHES_START
#undef DEF_SWITCH
#undef DEF_SWITCHES_END

// clang-format off
#define DEF_SWITCHES_START static const struct SwitchDesc gSwitchDescs[] = {
#define DEF_SWITCH(p_swtch, p_flag, p_help) \
  { flutter::Switch:: p_swtch, p_flag, p_help },
#define DEF_SWITCHES_END };
// clang-format on

// List of common and safe VM flags to allow to be passed directly to the VM.
#if FLUTTER_RELEASE

// clang-format off
static const std::string gDartFlagsWhitelist[] = {
    "--no-causal_async_stacks",
    "--lazy_async_stacks",
};
// clang-format on

#else

// clang-format off
static const std::string gDartFlagsWhitelist[] = {
    "--enable_mirrors",
    "--enable-service-port-fallback",
    "--lazy_async_stacks",
    "--max_profile_depth",
    "--no-causal_async_stacks",
    "--profile_period",
    "--random_seed",
    "--sample-buffer-duration",
    "--trace-reload",
    "--trace-reload-verbose",
    "--write-service-info",
};
// clang-format on

#endif  // FLUTTER_RELEASE

// Include again for struct definition.
#include "flutter/shell/common/switches.h"

// Define symbols for the ICU data that is linked into the Flutter library on
// Android.  This is a workaround for crashes seen when doing dynamic lookups
// of the engine's own symbols on some older versions of Android.
#if OS_ANDROID
extern uint8_t _binary_icudtl_dat_start[];
extern uint8_t _binary_icudtl_dat_end[];

static std::unique_ptr<fml::Mapping> GetICUStaticMapping() {
  return std::make_unique<fml::NonOwnedMapping>(
      _binary_icudtl_dat_start,
      _binary_icudtl_dat_end - _binary_icudtl_dat_start);
}
#endif

namespace flutter {

void PrintUsage(const std::string& executable_name) {
  std::cerr << std::endl << "  " << executable_name << std::endl << std::endl;

  std::cerr << "Versions: " << std::endl << std::endl;

  std::cerr << "Flutter Engine Version: " << GetFlutterEngineVersion()
            << std::endl;
  std::cerr << "Skia Version: " << GetSkiaVersion() << std::endl;

  std::cerr << "Dart Version: " << GetDartVersion() << std::endl << std::endl;

  std::cerr << "Available Flags:" << std::endl;

  const uint32_t column_width = 80;

  const uint32_t flags_count = static_cast<uint32_t>(Switch::Sentinel);

  uint32_t max_width = 2;
  for (uint32_t i = 0; i < flags_count; i++) {
    auto desc = gSwitchDescs[i];
    max_width = std::max<uint32_t>(desc.flag.size() + 2, max_width);
  }

  const uint32_t help_width = column_width - max_width - 3;

  std::cerr << std::string(column_width, '-') << std::endl;
  for (uint32_t i = 0; i < flags_count; i++) {
    auto desc = gSwitchDescs[i];

    std::cerr << std::setw(max_width)
              << std::string("--") +
                     std::string{desc.flag.data(), desc.flag.size()}
              << " : ";

    std::istringstream stream(desc.help);
    int32_t remaining = help_width;

    std::string word;
    while (stream >> word && remaining > 0) {
      remaining -= (word.size() + 1);
      if (remaining <= 0) {
        std::cerr << std::endl
                  << std::string(max_width, ' ') << "   " << word << " ";
        remaining = help_width;
      } else {
        std::cerr << word << " ";
      }
    }

    std::cerr << std::endl;
  }
  std::cerr << std::string(column_width, '-') << std::endl;
}

const std::string_view FlagForSwitch(Switch swtch) {
  for (uint32_t i = 0; i < static_cast<uint32_t>(Switch::Sentinel); i++) {
    if (gSwitchDescs[i].sw == swtch) {
      return gSwitchDescs[i].flag;
    }
  }
  return std::string_view();
}

static bool IsWhitelistedDartVMFlag(const std::string& flag) {
  for (uint32_t i = 0; i < fml::size(gDartFlagsWhitelist); ++i) {
    const std::string& allowed = gDartFlagsWhitelist[i];
    // Check that the prefix of the flag matches one of the whitelisted flags.
    // We don't need to worry about cases like "--safe --sneaky_dangerous" as
    // the VM will discard these as a single unrecognized flag.
    if (std::equal(allowed.begin(), allowed.end(), flag.begin())) {
      return true;
    }
  }
  return false;
}

template <typename T>
static bool GetSwitchValue(const fml::CommandLine& command_line,
                           Switch sw,
                           T* result) {
  std::string switch_string;

  if (!command_line.GetOptionValue(FlagForSwitch(sw), &switch_string)) {
    return false;
  }

  std::stringstream stream(switch_string);
  T value = 0;
  if (stream >> value) {
    *result = value;
    return true;
  }

  return false;
}

std::unique_ptr<fml::Mapping> GetSymbolMapping(std::string symbol_prefix,
                                               std::string native_lib_path) {
  const uint8_t* mapping;
  intptr_t size;

  auto lookup_symbol = [&mapping, &size, symbol_prefix](
                           const fml::RefPtr<fml::NativeLibrary>& library) {
    mapping = library->ResolveSymbol((symbol_prefix + "_start").c_str());
    size = reinterpret_cast<intptr_t>(
        library->ResolveSymbol((symbol_prefix + "_size").c_str()));
  };

  fml::RefPtr<fml::NativeLibrary> library =
      fml::NativeLibrary::CreateForCurrentProcess();
  lookup_symbol(library);

  if (!(mapping && size)) {
    // Symbol lookup for the current process fails on some devices.  As a
    // fallback, try doing the lookup based on the path to the Flutter library.
    library = fml::NativeLibrary::Create(native_lib_path.c_str());
    lookup_symbol(library);
  }

  FML_CHECK(mapping && size) << "Unable to resolve symbols: " << symbol_prefix;
  return std::make_unique<fml::NonOwnedMapping>(mapping, size);
}

Settings SettingsFromCommandLine(const fml::CommandLine& command_line) {
  Settings settings = {};

  // Enable Observatory
  settings.enable_observatory =
      !command_line.HasOption(FlagForSwitch(Switch::DisableObservatory));

  // Set Observatory Host
  if (command_line.HasOption(FlagForSwitch(Switch::DeviceObservatoryHost))) {
    command_line.GetOptionValue(FlagForSwitch(Switch::DeviceObservatoryHost),
                                &settings.observatory_host);
  }
  // Default the observatory port based on --ipv6 if not set.
  if (settings.observatory_host.empty()) {
    settings.observatory_host =
        command_line.HasOption(FlagForSwitch(Switch::IPv6)) ? "::1"
                                                            : "127.0.0.1";
  }

  // Set Observatory Port
  if (command_line.HasOption(FlagForSwitch(Switch::DeviceObservatoryPort))) {
    if (!GetSwitchValue(command_line, Switch::DeviceObservatoryPort,
                        &settings.observatory_port)) {
      FML_LOG(INFO)
          << "Observatory port specified was malformed. Will default to "
          << settings.observatory_port;
    }
  }

  // Disable need for authentication codes for VM service communication, if
  // specified.
  settings.disable_service_auth_codes =
      command_line.HasOption(FlagForSwitch(Switch::DisableServiceAuthCodes));

  // Checked mode overrides.
  settings.disable_dart_asserts =
      command_line.HasOption(FlagForSwitch(Switch::DisableDartAsserts));

  settings.start_paused =
      command_line.HasOption(FlagForSwitch(Switch::StartPaused));

  settings.enable_checked_mode =
      command_line.HasOption(FlagForSwitch(Switch::EnableCheckedMode));

  settings.enable_dart_profiling =
      command_line.HasOption(FlagForSwitch(Switch::EnableDartProfiling));

  settings.enable_software_rendering =
      command_line.HasOption(FlagForSwitch(Switch::EnableSoftwareRendering));

  settings.endless_trace_buffer =
      command_line.HasOption(FlagForSwitch(Switch::EndlessTraceBuffer));

  settings.trace_startup =
      command_line.HasOption(FlagForSwitch(Switch::TraceStartup));

  settings.trace_skia =
      command_line.HasOption(FlagForSwitch(Switch::TraceSkia));

  settings.trace_systrace =
      command_line.HasOption(FlagForSwitch(Switch::TraceSystrace));

  settings.skia_deterministic_rendering_on_cpu =
      command_line.HasOption(FlagForSwitch(Switch::SkiaDeterministicRendering));

  settings.verbose_logging =
      command_line.HasOption(FlagForSwitch(Switch::VerboseLogging));

  command_line.GetOptionValue(FlagForSwitch(Switch::FlutterAssetsDir),
                              &settings.assets_path);

  std::vector<std::string_view> aot_shared_library_name =
      command_line.GetOptionValues(FlagForSwitch(Switch::AotSharedLibraryName));

  std::string snapshot_asset_path;
  command_line.GetOptionValue(FlagForSwitch(Switch::SnapshotAssetPath),
                              &snapshot_asset_path);

  std::string vm_snapshot_data_filename;
  command_line.GetOptionValue(FlagForSwitch(Switch::VmSnapshotData),
                              &vm_snapshot_data_filename);

  std::string vm_snapshot_instr_filename;
  command_line.GetOptionValue(FlagForSwitch(Switch::VmSnapshotInstructions),
                              &vm_snapshot_instr_filename);

  std::string isolate_snapshot_data_filename;
  command_line.GetOptionValue(FlagForSwitch(Switch::IsolateSnapshotData),
                              &isolate_snapshot_data_filename);

  std::string isolate_snapshot_instr_filename;
  command_line.GetOptionValue(
      FlagForSwitch(Switch::IsolateSnapshotInstructions),
      &isolate_snapshot_instr_filename);

  if (aot_shared_library_name.size() > 0) {
    for (std::string_view name : aot_shared_library_name) {
      settings.application_library_path.emplace_back(name);
    }
  } else if (snapshot_asset_path.size() > 0) {
    settings.vm_snapshot_data_path =
        fml::paths::JoinPaths({snapshot_asset_path, vm_snapshot_data_filename});
    settings.vm_snapshot_instr_path = fml::paths::JoinPaths(
        {snapshot_asset_path, vm_snapshot_instr_filename});
    settings.isolate_snapshot_data_path = fml::paths::JoinPaths(
        {snapshot_asset_path, isolate_snapshot_data_filename});
    settings.isolate_snapshot_instr_path = fml::paths::JoinPaths(
        {snapshot_asset_path, isolate_snapshot_instr_filename});
  }

  command_line.GetOptionValue(FlagForSwitch(Switch::CacheDirPath),
                              &settings.temp_directory_path);

  if (settings.icu_initialization_required) {
    command_line.GetOptionValue(FlagForSwitch(Switch::ICUDataFilePath),
                                &settings.icu_data_path);
    if (command_line.HasOption(FlagForSwitch(Switch::ICUSymbolPrefix))) {
      std::string icu_symbol_prefix, native_lib_path;
      command_line.GetOptionValue(FlagForSwitch(Switch::ICUSymbolPrefix),
                                  &icu_symbol_prefix);
      command_line.GetOptionValue(FlagForSwitch(Switch::ICUNativeLibPath),
                                  &native_lib_path);

#if OS_ANDROID
      settings.icu_mapper = GetICUStaticMapping;
#else
      settings.icu_mapper = [icu_symbol_prefix, native_lib_path] {
        return GetSymbolMapping(icu_symbol_prefix, native_lib_path);
      };
#endif
    }
  }

  settings.use_test_fonts =
      command_line.HasOption(FlagForSwitch(Switch::UseTestFonts));

  std::string all_dart_flags;
  if (command_line.GetOptionValue(FlagForSwitch(Switch::DartFlags),
                                  &all_dart_flags)) {
    std::stringstream stream(all_dart_flags);
    std::string flag;

    // Assume that individual flags are comma separated.
    while (std::getline(stream, flag, ',')) {
      if (!IsWhitelistedDartVMFlag(flag)) {
        FML_LOG(FATAL) << "Encountered blacklisted Dart VM flag: " << flag;
      }
      settings.dart_flags.push_back(flag);
    }
  }

#if !FLUTTER_RELEASE
  command_line.GetOptionValue(FlagForSwitch(Switch::LogTag), &settings.log_tag);
#endif

  settings.dump_skp_on_shader_compilation =
      command_line.HasOption(FlagForSwitch(Switch::DumpSkpOnShaderCompilation));

  settings.cache_sksl =
      command_line.HasOption(FlagForSwitch(Switch::CacheSkSL));

  return settings;
}

}  // namespace flutter
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2014, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */
#include "proxygen/lib/http/codec/compress/GzipHeaderCodec.h"

#include "proxygen/lib/http/codec/SPDYCodec.h"
#include "proxygen/lib/http/codec/SPDYConstants.h"

#include <folly/Memory.h>
#include <folly/String.h>
#include <folly/ThreadLocal.h>
#include <folly/io/IOBuf.h>
#include <string>

using folly::IOBuf;
using folly::ThreadLocalPtr;
using folly::io::Cursor;
using proxygen::compress::Header;
using proxygen::compress::HeaderPiece;
using proxygen::compress::HeaderPieceList;
using proxygen::spdy::kMaxFrameLength;
using std::string;
using std::unique_ptr;
using std::vector;

namespace {

// Maximum size of header names+values after expanding multi-value headers
const size_t kMaxExpandedHeaderLineBytes = 80 * 1024;

folly::IOBuf& getStaticHeaderBufSpace(size_t size) {
  static ThreadLocalPtr<IOBuf> buf;
  if (!buf) {
    buf.reset(new IOBuf(IOBuf::CREATE, size));
  } else {
    if (size > buf->capacity()) {
      buf.reset(new IOBuf(IOBuf::CREATE, size));
    } else {
      buf->clear();
    }
  }
  DCHECK(!buf->isShared());
  return *buf;
}

void appendString(uint8_t*& dst, const string& str) {
  size_t len = str.length();
  memcpy(dst, str.data(), len);
  dst += len;
}

} // anonymous namespace

namespace proxygen {

GzipHeaderCodec::GzipHeaderCodec(int compressionLevel,
                                 const SPDYVersionSettings& versionSettings)
    : versionSettings_(versionSettings) {
  // Create compression and decompression contexts by cloning thread-local
  // copies of the initial SPDY compression state
  auto context = getZlibContext(versionSettings, compressionLevel);
  deflateCopy(&deflater_, const_cast<z_stream*>(&(context->deflater)));
  inflateCopy(&inflater_, const_cast<z_stream*>(&(context->inflater)));
}

GzipHeaderCodec::GzipHeaderCodec(int compressionLevel,
                                 SPDYVersion version)
    : GzipHeaderCodec(
        compressionLevel,
        SPDYCodec::getVersionSettings(version)) {}

GzipHeaderCodec::~GzipHeaderCodec() {
  deflateEnd(&deflater_);
  inflateEnd(&inflater_);
}

folly::IOBuf& GzipHeaderCodec::getHeaderBuf() {
  return getStaticHeaderBufSpace(maxUncompressed_);
}

const GzipHeaderCodec::ZlibContext* GzipHeaderCodec::getZlibContext(
    SPDYVersionSettings versionSettings, int compressionLevel) {
  static folly::ThreadLocal<ZlibContextMap> zlibContexts_;
  ZlibConfig zlibConfig(versionSettings.version, compressionLevel);
  auto match = zlibContexts_->find(zlibConfig);
  if (match != zlibContexts_->end()) {
    return match->second.get();
  } else {
    // This is the first request for the specified SPDY version and compression
    // level in this thread, so we need to construct the initial compressor and
    // decompressor contexts.
    auto newContext = folly::make_unique<ZlibContext>();
    newContext->deflater.zalloc = Z_NULL;
    newContext->deflater.zfree = Z_NULL;
    newContext->deflater.opaque = Z_NULL;
    newContext->deflater.avail_in = 0;
    newContext->deflater.next_in = Z_NULL;
    int windowBits  = (compressionLevel == Z_NO_COMPRESSION) ? 8 : 11;
    int r = deflateInit2(
        &(newContext->deflater),
        compressionLevel,
        Z_DEFLATED, // compression method
        windowBits, // log2 of the compression window size, negative value
                    // means raw deflate output format w/o libz header
        1,          // memory size for internal compression state, 1-9
        Z_DEFAULT_STRATEGY);
    CHECK(r == Z_OK);
    if (compressionLevel != Z_NO_COMPRESSION) {
      r = deflateSetDictionary(&(newContext->deflater), versionSettings.dict,
                               versionSettings.dictSize);
      CHECK(r == Z_OK);
    }

    newContext->inflater.zalloc = Z_NULL;
    newContext->inflater.zfree = Z_NULL;
    newContext->inflater.opaque = Z_NULL;
    newContext->inflater.avail_in = 0;
    newContext->inflater.next_in = Z_NULL;
    r = inflateInit(&(newContext->inflater));
    CHECK(r == Z_OK);

    auto result = newContext.get();
    zlibContexts_->emplace(zlibConfig, std::move(newContext));
    return result;
  }
}

unique_ptr<IOBuf> GzipHeaderCodec::encode(vector<Header>& headers) noexcept {
  // Build a sequence of the header names and values, sorted by name.
  // The purpose of the sort is to make it easier to combine the
  // values of multiple headers with the same name.  The SPDY spec
  // prohibits any header name from appearing more than once in the
  // Name/Value list, so we must combine values when serializing.
  std::sort(headers.begin(), headers.end());

  auto& uncompressed = getHeaderBuf();
  // Compute the amount of space needed to hold the uncompressed
  // representation of the headers.  This is an upper bound on the
  // amount of space we'll actually need, because if we end up
  // combining any headers with the same name, the combined
  // representation will be smaller than the original.
  size_t maxUncompressedSize = versionSettings_.nameValueSize;
  for (const Header& header : headers) {
    maxUncompressedSize += versionSettings_.nameValueSize;
    maxUncompressedSize += header.name->length();
    maxUncompressedSize += versionSettings_.nameValueSize;
    maxUncompressedSize += header.value->length();
  }

  // TODO: give on 'onError()' callback if the space in uncompressed buf
  // cannot fit the headers and then skip the "reserve" code below. We
  // have already reserved the maximum legal amount of space for
  // uncompressed headers.

  VLOG(4) << "reserving " << maxUncompressedSize
          << " bytes for uncompressed headers";
  uncompressed.reserve(0, maxUncompressedSize);

  // Serialize the uncompressed representation of the headers.
  uint8_t* dst = uncompressed.writableData();
  dst += versionSettings_.nameValueSize; // Leave space for count of headers.
  HTTPHeaderCode lastCode = HTTP_HEADER_OTHER;
  const string* lastName = &empty_string;
  uint8_t* lastValueLenPtr = nullptr;
  size_t lastValueLen = 0;
  unsigned numHeaders = 0;
  for (const Header& header : headers) {
    if ((header.code != lastCode) || (*header.name != *lastName)) {
      // Simple case: this header name is different from the previous
      // one, so we don't need to combine values.
      numHeaders++;
      versionSettings_.appendSizeFun(dst, header.name->length());

      // lowercasing the header name inline
      char* nameBegin = (char *)dst;
      appendString(dst, *header.name);
      folly::toLowerAscii((char *)nameBegin, header.name->size());

      lastValueLenPtr = dst;
      lastValueLen = header.value->length();
      versionSettings_.appendSizeFun(dst, header.value->length());
      appendString(dst, *header.value);
      lastCode = header.code;
      lastName = header.name;
    } else {
      // More complicated case: we do need to combine values.
      *dst++ = 0;  // SPDY uses a null byte as a separator
      appendString(dst, *header.value);
      // Go back and rewrite the length field in front of the value
      lastValueLen += (1 + header.value->length());
      uint8_t* tmp = lastValueLenPtr;
      versionSettings_.appendSizeFun(tmp, lastValueLen);
    }
  }

  // Compute the uncompressed length; if we combined any header values,
  // we will have used less space than originally estimated.
  size_t uncompressedLen = dst - uncompressed.writableData();

  // Go back and write the count of unique header names at the start.
  dst = uncompressed.writableData();
  versionSettings_.appendSizeFun(dst, numHeaders);

  // Allocate a contiguous space big enough to hold the compressed headers,
  // plus any headroom requested by the caller.
  size_t maxDeflatedSize = deflateBound(&deflater_, uncompressedLen);
  unique_ptr<IOBuf> out(IOBuf::create(maxDeflatedSize + encodeHeadroom_));
  out->advance(encodeHeadroom_);

  // Compress
  deflater_.next_in = uncompressed.writableData();
  deflater_.avail_in = uncompressedLen;
  deflater_.next_out = out->writableData();
  deflater_.avail_out = maxDeflatedSize;
  int r = deflate(&deflater_, Z_SYNC_FLUSH);
  CHECK(r == Z_OK);
  CHECK(deflater_.avail_in == 0);
  out->append(maxDeflatedSize - deflater_.avail_out);

  VLOG(4) << "header size orig=" << uncompressedLen
          << ", max deflated=" << maxDeflatedSize
          << ", actual deflated=" << out->length();

  encodedSize_.compressed = out->length();
  encodedSize_.uncompressed = uncompressedLen;
  if (stats_) {
    stats_->recordEncode(Type::GZIP, encodedSize_);
  }

  return std::move(out);
}

Result<HeaderDecodeResult, HeaderDecodeError>
GzipHeaderCodec::decode(Cursor& cursor, uint32_t length) noexcept {
  outHeaders_.clear();

  // empty header block
  if (length == 0) {
    return HeaderDecodeResult{outHeaders_, 0};
  }

  // Get the thread local buffer space to use
  auto& uncompressed = getHeaderBuf();
  uint32_t consumed = 0;
  // Decompress the headers
  while (length > 0) {
    auto next = cursor.peek();
    uint32_t chunkLen = std::min((uint32_t)next.second, length);
    inflater_.avail_in = chunkLen;
    inflater_.next_in = (uint8_t *)next.first;
    do {
      if (uncompressed.tailroom() == 0) {
        // This code should not execute, since we throw an error if the
        // decompressed size of the headers is too large and we initialize
        // the buffer to that size.
        LOG(ERROR) << "Doubling capacity of SPDY headers buffer";
        uncompressed.reserve(0, uncompressed.capacity());
      }

      inflater_.next_out = uncompressed.writableTail();
      inflater_.avail_out = uncompressed.tailroom();
      int r = inflate(&inflater_, Z_NO_FLUSH);
      if (r == Z_NEED_DICT) {
        // we cannot initialize the inflater dictionary before calling inflate()
        // as it checks the adler-32 checksum of the supplied dictionary
        r = inflateSetDictionary(&inflater_, versionSettings_.dict,
                                 versionSettings_.dictSize);
        if (r != Z_OK) {
          LOG(ERROR) << "inflate set dictionary failed with error=" << r;
          return HeaderDecodeError::INFLATE_DICTIONARY;
        }
        inflater_.avail_out = 0;
        continue;
      }
      if (r != 0) {
        // probably bad encoding
        LOG(ERROR) << "inflate failed with error=" << r;
        return HeaderDecodeError::BAD_ENCODING;
      }
      uncompressed.append(uncompressed.tailroom() - inflater_.avail_out);
      if (uncompressed.length() > maxUncompressed_) {
        LOG(ERROR) << "Decompressed headers too large";
        return HeaderDecodeError::HEADERS_TOO_LARGE;
      }
    } while (inflater_.avail_in > 0 && inflater_.avail_out == 0);
    length -= chunkLen;
    consumed += chunkLen;
    cursor.skip(chunkLen);
  }

  decodedSize_.compressed = consumed;
  decodedSize_.uncompressed = uncompressed.computeChainDataLength();
  if (stats_) {
    stats_->recordDecode(Type::GZIP, decodedSize_);
  }

  size_t expandedHeaderLineBytes = 0;
  try {
    auto result = parseNameValues(uncompressed);
    if (result.isError()) {
      return result.error();
    }
    expandedHeaderLineBytes = result.ok();
  } catch (const std::out_of_range& ex) {
    return HeaderDecodeError::BAD_ENCODING;
  }

  if (UNLIKELY(expandedHeaderLineBytes > kMaxExpandedHeaderLineBytes)) {
    LOG(ERROR) << "expanded headers too large";
    return HeaderDecodeError::HEADERS_TOO_LARGE;
  }

  return HeaderDecodeResult{outHeaders_, consumed};
}

Result<size_t, HeaderDecodeError>
GzipHeaderCodec::parseNameValues(const folly::IOBuf& uncompressed) {

  size_t expandedHeaderLineBytes = 0;
  Cursor headerCursor(&uncompressed);
  uint32_t numNV = versionSettings_.parseSizeFun(&headerCursor);
  const HeaderPiece* headerName = nullptr;

  for (uint32_t i = 0; i < numNV * 2; i++) {
    uint32_t len = versionSettings_.parseSizeFun(&headerCursor);
    if (len == 0 && !headerName) {
      LOG(ERROR) << "empty header name";
      return HeaderDecodeError::EMPTY_HEADER_NAME;
    }
    auto next = headerCursor.peek();
    if (next.second >= len) {
      // string is contiguous, just put a pointer into the headers structure
      outHeaders_.emplace_back((char *)next.first, len, false, false);
      headerCursor.skip(len);
    } else {
      // string is not contiguous, allocate a buffer and pull into it
      unique_ptr<char[]> data (new char[len]);
      headerCursor.pull(data.get(), len);
      outHeaders_.emplace_back(data.release(), len, true, false);
    }
    if (i % 2 == 0) {
      headerName = &outHeaders_.back();
      for (const char c: headerName->str) {
        if (c < 0x20 || c > 0x7e || ('A' <= c && c <= 'Z')) {
          LOG(ERROR) << "invalid header value";
          return HeaderDecodeError::INVALID_HEADER_VALUE;
        }
      }
    } else {
      HeaderPiece& headerValue = outHeaders_.back();
      bool first = true;
      const char* valueStart = headerValue.str.data();
      const char* pos = valueStart;
      const char* stop = valueStart + headerValue.str.size();
      while(pos < stop) {
        if (*pos == '\0') {
          if (pos - valueStart == 0) {
            LOG(ERROR) << "empty header value";
            return HeaderDecodeError::EMPTY_HEADER_VALUE;
          }
          if (first) {
            headerValue.str.reset(valueStart, pos - valueStart);
            first = false;
          } else {
            outHeaders_.emplace_back(headerName->str.data(),
                                     headerName->str.size(),
                                     false, true);
            outHeaders_.emplace_back(valueStart, pos - valueStart, false, true);
            expandedHeaderLineBytes += ((pos - valueStart) +
                                        headerName->str.size());
          }
          valueStart = pos + 1;
        }
        pos++;
      }
      if (!first) {
        // value contained at least one \0, add the last value
        if (pos - valueStart == 0) {
          LOG(ERROR) << "empty header value";
          return HeaderDecodeError::EMPTY_HEADER_VALUE;
        }
        outHeaders_.emplace_back(headerName->str.data(),
                                 headerName->str.size(),
                                 false, true);
        outHeaders_.emplace_back(valueStart, pos - valueStart, false, true);
        expandedHeaderLineBytes += (pos - valueStart) + headerName->str.size();
      }
      headerName = nullptr;
    }
  }
  return expandedHeaderLineBytes;
}

}
<commit_msg>Use static buffer for mobile builds<commit_after>/*
 *  Copyright (c) 2014, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */
#include "proxygen/lib/http/codec/compress/GzipHeaderCodec.h"

#include "proxygen/lib/http/codec/SPDYCodec.h"
#include "proxygen/lib/http/codec/SPDYConstants.h"

#include <folly/Memory.h>
#include <folly/Portability.h>
#include <folly/String.h>
#include <folly/ThreadLocal.h>
#include <folly/io/IOBuf.h>
#include <string>

using folly::IOBuf;
using folly::ThreadLocalPtr;
using folly::io::Cursor;
using proxygen::compress::Header;
using proxygen::compress::HeaderPiece;
using proxygen::compress::HeaderPieceList;
using proxygen::spdy::kMaxFrameLength;
using std::string;
using std::unique_ptr;
using std::vector;

namespace {

// Maximum size of header names+values after expanding multi-value headers
const size_t kMaxExpandedHeaderLineBytes = 80 * 1024;

void appendString(uint8_t*& dst, const string& str) {
  size_t len = str.length();
  memcpy(dst, str.data(), len);
  dst += len;
}

} // anonymous namespace

namespace proxygen {

GzipHeaderCodec::GzipHeaderCodec(int compressionLevel,
                                 const SPDYVersionSettings& versionSettings)
    : versionSettings_(versionSettings) {
  // Create compression and decompression contexts by cloning thread-local
  // copies of the initial SPDY compression state
  auto context = getZlibContext(versionSettings, compressionLevel);
  deflateCopy(&deflater_, const_cast<z_stream*>(&(context->deflater)));
  inflateCopy(&inflater_, const_cast<z_stream*>(&(context->inflater)));
}

GzipHeaderCodec::GzipHeaderCodec(int compressionLevel,
                                 SPDYVersion version)
    : GzipHeaderCodec(
        compressionLevel,
        SPDYCodec::getVersionSettings(version)) {}

GzipHeaderCodec::~GzipHeaderCodec() {
  deflateEnd(&deflater_);
  inflateEnd(&inflater_);
}

folly::IOBuf& GzipHeaderCodec::getHeaderBuf() {
#if defined(__ANDROID__) || TARGET_OS_IPHONE
  // ThreadLocal is unrealiable on iOS, so we're using a simple static IOBuf
  // on both Android and iOS, since all the codec operations are running in the
  // eventbase thread.
  static unique_ptr<IOBuf> headerBuf = IOBuf::create(maxUncompressed_);
  if (maxUncompressed_ > headerBuf->capacity()) {
    headerBuf = IOBuf::create(maxUncompressed_);
  }
  headerBuf->clear();
  return *headerBuf;
#else
  // on server-side we want to use thread-local buffers for efficiency reasons
  static ThreadLocalPtr<IOBuf> buf;
  if (!buf) {
    buf.reset(new IOBuf(IOBuf::CREATE, maxUncompressed_));
  } else {
    if (maxUncompressed_ > buf->capacity()) {
      buf.reset(new IOBuf(IOBuf::CREATE, maxUncompressed_));
    } else {
      buf->clear();
    }
  }
  DCHECK(!buf->isShared());
  return *buf;
#endif
}

const GzipHeaderCodec::ZlibContext* GzipHeaderCodec::getZlibContext(
    SPDYVersionSettings versionSettings, int compressionLevel) {
  static folly::ThreadLocal<ZlibContextMap> zlibContexts_;
  ZlibConfig zlibConfig(versionSettings.version, compressionLevel);
  auto match = zlibContexts_->find(zlibConfig);
  if (match != zlibContexts_->end()) {
    return match->second.get();
  } else {
    // This is the first request for the specified SPDY version and compression
    // level in this thread, so we need to construct the initial compressor and
    // decompressor contexts.
    auto newContext = folly::make_unique<ZlibContext>();
    newContext->deflater.zalloc = Z_NULL;
    newContext->deflater.zfree = Z_NULL;
    newContext->deflater.opaque = Z_NULL;
    newContext->deflater.avail_in = 0;
    newContext->deflater.next_in = Z_NULL;
    int windowBits  = (compressionLevel == Z_NO_COMPRESSION) ? 8 : 11;
    int r = deflateInit2(
        &(newContext->deflater),
        compressionLevel,
        Z_DEFLATED, // compression method
        windowBits, // log2 of the compression window size, negative value
                    // means raw deflate output format w/o libz header
        1,          // memory size for internal compression state, 1-9
        Z_DEFAULT_STRATEGY);
    CHECK(r == Z_OK);
    if (compressionLevel != Z_NO_COMPRESSION) {
      r = deflateSetDictionary(&(newContext->deflater), versionSettings.dict,
                               versionSettings.dictSize);
      CHECK(r == Z_OK);
    }

    newContext->inflater.zalloc = Z_NULL;
    newContext->inflater.zfree = Z_NULL;
    newContext->inflater.opaque = Z_NULL;
    newContext->inflater.avail_in = 0;
    newContext->inflater.next_in = Z_NULL;
    r = inflateInit(&(newContext->inflater));
    CHECK(r == Z_OK);

    auto result = newContext.get();
    zlibContexts_->emplace(zlibConfig, std::move(newContext));
    return result;
  }
}

unique_ptr<IOBuf> GzipHeaderCodec::encode(vector<Header>& headers) noexcept {
  // Build a sequence of the header names and values, sorted by name.
  // The purpose of the sort is to make it easier to combine the
  // values of multiple headers with the same name.  The SPDY spec
  // prohibits any header name from appearing more than once in the
  // Name/Value list, so we must combine values when serializing.
  std::sort(headers.begin(), headers.end());

  auto& uncompressed = getHeaderBuf();
  // Compute the amount of space needed to hold the uncompressed
  // representation of the headers.  This is an upper bound on the
  // amount of space we'll actually need, because if we end up
  // combining any headers with the same name, the combined
  // representation will be smaller than the original.
  size_t maxUncompressedSize = versionSettings_.nameValueSize;
  for (const Header& header : headers) {
    maxUncompressedSize += versionSettings_.nameValueSize;
    maxUncompressedSize += header.name->length();
    maxUncompressedSize += versionSettings_.nameValueSize;
    maxUncompressedSize += header.value->length();
  }

  // TODO: give on 'onError()' callback if the space in uncompressed buf
  // cannot fit the headers and then skip the "reserve" code below. We
  // have already reserved the maximum legal amount of space for
  // uncompressed headers.

  VLOG(4) << "reserving " << maxUncompressedSize
          << " bytes for uncompressed headers";
  uncompressed.reserve(0, maxUncompressedSize);

  // Serialize the uncompressed representation of the headers.
  uint8_t* dst = uncompressed.writableData();
  dst += versionSettings_.nameValueSize; // Leave space for count of headers.
  HTTPHeaderCode lastCode = HTTP_HEADER_OTHER;
  const string* lastName = &empty_string;
  uint8_t* lastValueLenPtr = nullptr;
  size_t lastValueLen = 0;
  unsigned numHeaders = 0;
  for (const Header& header : headers) {
    if ((header.code != lastCode) || (*header.name != *lastName)) {
      // Simple case: this header name is different from the previous
      // one, so we don't need to combine values.
      numHeaders++;
      versionSettings_.appendSizeFun(dst, header.name->length());

      // lowercasing the header name inline
      char* nameBegin = (char *)dst;
      appendString(dst, *header.name);
      folly::toLowerAscii((char *)nameBegin, header.name->size());

      lastValueLenPtr = dst;
      lastValueLen = header.value->length();
      versionSettings_.appendSizeFun(dst, header.value->length());
      appendString(dst, *header.value);
      lastCode = header.code;
      lastName = header.name;
    } else {
      // More complicated case: we do need to combine values.
      *dst++ = 0;  // SPDY uses a null byte as a separator
      appendString(dst, *header.value);
      // Go back and rewrite the length field in front of the value
      lastValueLen += (1 + header.value->length());
      uint8_t* tmp = lastValueLenPtr;
      versionSettings_.appendSizeFun(tmp, lastValueLen);
    }
  }

  // Compute the uncompressed length; if we combined any header values,
  // we will have used less space than originally estimated.
  size_t uncompressedLen = dst - uncompressed.writableData();

  // Go back and write the count of unique header names at the start.
  dst = uncompressed.writableData();
  versionSettings_.appendSizeFun(dst, numHeaders);

  // Allocate a contiguous space big enough to hold the compressed headers,
  // plus any headroom requested by the caller.
  size_t maxDeflatedSize = deflateBound(&deflater_, uncompressedLen);
  unique_ptr<IOBuf> out(IOBuf::create(maxDeflatedSize + encodeHeadroom_));
  out->advance(encodeHeadroom_);

  // Compress
  deflater_.next_in = uncompressed.writableData();
  deflater_.avail_in = uncompressedLen;
  deflater_.next_out = out->writableData();
  deflater_.avail_out = maxDeflatedSize;
  int r = deflate(&deflater_, Z_SYNC_FLUSH);
  CHECK(r == Z_OK);
  CHECK(deflater_.avail_in == 0);
  out->append(maxDeflatedSize - deflater_.avail_out);

  VLOG(4) << "header size orig=" << uncompressedLen
          << ", max deflated=" << maxDeflatedSize
          << ", actual deflated=" << out->length();

  encodedSize_.compressed = out->length();
  encodedSize_.uncompressed = uncompressedLen;
  if (stats_) {
    stats_->recordEncode(Type::GZIP, encodedSize_);
  }

  return std::move(out);
}

Result<HeaderDecodeResult, HeaderDecodeError>
GzipHeaderCodec::decode(Cursor& cursor, uint32_t length) noexcept {
  outHeaders_.clear();

  // empty header block
  if (length == 0) {
    return HeaderDecodeResult{outHeaders_, 0};
  }

  auto& uncompressed = getHeaderBuf();
  uint32_t consumed = 0;
  // Decompress the headers
  while (length > 0) {
    auto next = cursor.peek();
    uint32_t chunkLen = std::min((uint32_t)next.second, length);
    inflater_.avail_in = chunkLen;
    inflater_.next_in = (uint8_t *)next.first;
    do {
      if (uncompressed.tailroom() == 0) {
        // This code should not execute, since we throw an error if the
        // decompressed size of the headers is too large and we initialize
        // the buffer to that size.
        LOG(ERROR) << "Doubling capacity of SPDY headers buffer";
        uncompressed.reserve(0, uncompressed.capacity());
      }

      inflater_.next_out = uncompressed.writableTail();
      inflater_.avail_out = uncompressed.tailroom();
      int r = inflate(&inflater_, Z_NO_FLUSH);
      if (r == Z_NEED_DICT) {
        // we cannot initialize the inflater dictionary before calling inflate()
        // as it checks the adler-32 checksum of the supplied dictionary
        r = inflateSetDictionary(&inflater_, versionSettings_.dict,
                                 versionSettings_.dictSize);
        if (r != Z_OK) {
          LOG(ERROR) << "inflate set dictionary failed with error=" << r;
          return HeaderDecodeError::INFLATE_DICTIONARY;
        }
        inflater_.avail_out = 0;
        continue;
      }
      if (r != 0) {
        // probably bad encoding
        LOG(ERROR) << "inflate failed with error=" << r;
        return HeaderDecodeError::BAD_ENCODING;
      }
      uncompressed.append(uncompressed.tailroom() - inflater_.avail_out);
      if (uncompressed.length() > maxUncompressed_) {
        LOG(ERROR) << "Decompressed headers too large";
        return HeaderDecodeError::HEADERS_TOO_LARGE;
      }
    } while (inflater_.avail_in > 0 && inflater_.avail_out == 0);
    length -= chunkLen;
    consumed += chunkLen;
    cursor.skip(chunkLen);
  }

  decodedSize_.compressed = consumed;
  decodedSize_.uncompressed = uncompressed.computeChainDataLength();
  if (stats_) {
    stats_->recordDecode(Type::GZIP, decodedSize_);
  }

  size_t expandedHeaderLineBytes = 0;
  try {
    auto result = parseNameValues(uncompressed);
    if (result.isError()) {
      return result.error();
    }
    expandedHeaderLineBytes = result.ok();
  } catch (const std::out_of_range& ex) {
    return HeaderDecodeError::BAD_ENCODING;
  }

  if (UNLIKELY(expandedHeaderLineBytes > kMaxExpandedHeaderLineBytes)) {
    LOG(ERROR) << "expanded headers too large";
    return HeaderDecodeError::HEADERS_TOO_LARGE;
  }

  return HeaderDecodeResult{outHeaders_, consumed};
}

Result<size_t, HeaderDecodeError>
GzipHeaderCodec::parseNameValues(const folly::IOBuf& uncompressed) {

  size_t expandedHeaderLineBytes = 0;
  Cursor headerCursor(&uncompressed);
  uint32_t numNV = versionSettings_.parseSizeFun(&headerCursor);
  const HeaderPiece* headerName = nullptr;

  for (uint32_t i = 0; i < numNV * 2; i++) {
    uint32_t len = versionSettings_.parseSizeFun(&headerCursor);
    if (len == 0 && !headerName) {
      LOG(ERROR) << "empty header name";
      return HeaderDecodeError::EMPTY_HEADER_NAME;
    }
    auto next = headerCursor.peek();
    if (next.second >= len) {
      // string is contiguous, just put a pointer into the headers structure
      outHeaders_.emplace_back((char *)next.first, len, false, false);
      headerCursor.skip(len);
    } else {
      // string is not contiguous, allocate a buffer and pull into it
      unique_ptr<char[]> data (new char[len]);
      headerCursor.pull(data.get(), len);
      outHeaders_.emplace_back(data.release(), len, true, false);
    }
    if (i % 2 == 0) {
      headerName = &outHeaders_.back();
      for (const char c: headerName->str) {
        if (c < 0x20 || c > 0x7e || ('A' <= c && c <= 'Z')) {
          LOG(ERROR) << "invalid header value";
          return HeaderDecodeError::INVALID_HEADER_VALUE;
        }
      }
    } else {
      HeaderPiece& headerValue = outHeaders_.back();
      bool first = true;
      const char* valueStart = headerValue.str.data();
      const char* pos = valueStart;
      const char* stop = valueStart + headerValue.str.size();
      while(pos < stop) {
        if (*pos == '\0') {
          if (pos - valueStart == 0) {
            LOG(ERROR) << "empty header value";
            return HeaderDecodeError::EMPTY_HEADER_VALUE;
          }
          if (first) {
            headerValue.str.reset(valueStart, pos - valueStart);
            first = false;
          } else {
            outHeaders_.emplace_back(headerName->str.data(),
                                     headerName->str.size(),
                                     false, true);
            outHeaders_.emplace_back(valueStart, pos - valueStart, false, true);
            expandedHeaderLineBytes += ((pos - valueStart) +
                                        headerName->str.size());
          }
          valueStart = pos + 1;
        }
        pos++;
      }
      if (!first) {
        // value contained at least one \0, add the last value
        if (pos - valueStart == 0) {
          LOG(ERROR) << "empty header value";
          return HeaderDecodeError::EMPTY_HEADER_VALUE;
        }
        outHeaders_.emplace_back(headerName->str.data(),
                                 headerName->str.size(),
                                 false, true);
        outHeaders_.emplace_back(valueStart, pos - valueStart, false, true);
        expandedHeaderLineBytes += (pos - valueStart) + headerName->str.size();
      }
      headerName = nullptr;
    }
  }
  return expandedHeaderLineBytes;
}

}
<|endoftext|>


<commit_before>#include <iostream>
#include <Poco/Logger.h>
#include <Poco/Message.h>
#include <Poco/File.h>
#include <Poco/Util/Option.h>
#include <Poco/Util/OptionSet.h>
#include <Poco/Util/HelpFormatter.h>
#include <Poco/Util/ServerApplication.h>

#include "server/MongooseServer.h"
#include "di/DependencyInjector.h"
#include "UIServerModule.h"

using namespace std;
using namespace Poco;
using namespace Poco::Util;
using namespace BeeeOn;

#define DEFAULT_PORT 8000

#define LOCAL_LOGGING_FILE  "logging.ini"
#define SYSTEM_LOGGING_FILE "/etc/beeeon/ui-server/logging.ini"

#define LOCAL_CONFIG_FILE  "server.ini"
#define SYSTEM_CONFIG_FILE "/etc/beeeon/ui-server/server.ini"

#define LOCAL_SERVICES_FILE  "services.xml"
#define SYSTEM_SERVICES_FILE "/etc/beeeon/ui-server/services.xml"

static Option optConfig("config", "c",
		"general configuration file to be used (xml, ini, properties)",
		false,
		"<file>",
		true);
static Option optServices("services", "s",
		"services configuration file to be used (xml, ini, properties)",
		false,
		"<file>",
		true);
static Option optLogging("logging", "l",
		"logging configuration file to be used (xml, ini, properties)",
		false,
		"<file>",
		true);
static Option optPort("port", "p",
		"server port to listen on",
		false,
		"<port>",
		true);
static Option optHelp("help", "h", "print help");

class Startup : public ServerApplication {
public:
	Startup():
		m_printHelp(false),
		m_serverPort(DEFAULT_PORT)
	{
	}

protected:
	void handleOption(const string &name, const string &value)
	{
		if (name == "services")
			m_userServices = value;
		if (name == "logging")
			m_userLogging = value;
		if (name == "config")
			m_userConfig = value;
		if (name == "help")
			m_printHelp = true;
		if (name == "port")
			m_serverPort = stoi(value);

		Application::handleOption(name, value);
	}

	void findAndLoadConfig()
	{
		File user(m_userConfig);
		File local(LOCAL_CONFIG_FILE);
		File system(SYSTEM_CONFIG_FILE);

		if (!m_userConfig.empty() && user.exists())
			loadConfiguration(user.path());
		else if (local.exists())
			loadConfiguration(local.path());
		else if (system.exists())
			loadConfiguration(system.path());
	}

	void findAndLoadLogging()
	{
		File user(m_userLogging);
		File local(LOCAL_LOGGING_FILE);
		File system(SYSTEM_LOGGING_FILE);

		if (!m_userLogging.empty() && user.exists())
			loadConfiguration(user.path());
		else if (local.exists())
			loadConfiguration(local.path());
		else if (system.exists())
			loadConfiguration(system.path());
	}

	void findAndLoadServices()
	{
		File user(m_userServices);
		File local(LOCAL_SERVICES_FILE);
		File system(SYSTEM_SERVICES_FILE);

		if (!m_userServices.empty() && user.exists()) {
			logger().notice(
				"loading configuration from " + user.path(),
				__FILE__, __LINE__);
			loadConfiguration(user.path());
		}
		else if (local.exists()) {
			logger().notice(
				"loading configuration from " + local.path(),
				__FILE__, __LINE__);
			loadConfiguration(local.path());
		}
		else if (system.exists()) {
			logger().notice(
				"loading configuration from " + system.path(),
				__FILE__, __LINE__);
			loadConfiguration(system.path());
		}
	}

	void initialize(Application &app)
	{
		Logger::root().setLevel(Logger::parseLevel("trace"));
		findAndLoadConfig();
		findAndLoadLogging();
		Application::initialize(app);
		findAndLoadServices();
	}

	void defineOptions(OptionSet &options)
	{
		options.addOption(optConfig);
		options.addOption(optServices);
		options.addOption(optLogging);
		options.addOption(optPort);
		options.addOption(optHelp);
		Application::defineOptions(options);
	}

	int printHelp()
	{
		HelpFormatter help(options());
		help.setCommand(config().getString("application.baseName"));
		help.setUnixStyle(true);
		help.setWidth(80);
		help.setUsage("[-h] ...");
		help.format(cout);

		return EXIT_OK;
	}

	int main(const std::vector <std::string> &args)
	{
		if (m_printHelp)
			return printHelp();

		if (logger().debug())
			ManifestSingleton::reportInfo(logger());

		DependencyInjector injector(config().createView("services"));
		UIServerModule *module = injector
					.create<UIServerModule>("main");

		module->createServer(m_serverPort);
		module->server().start();

		waitForTerminationRequest();
		module->server().stop();
		return EXIT_OK;
	}

private:
	bool m_printHelp;
	unsigned int m_serverPort;
	string m_userLogging;
	string m_userConfig;
	string m_userServices;
};

int main(int argc, char **argv)
{
	Startup server;
	server.setUnixOptions(true);

	try {
		return server.run(argc, argv);
	} catch(Exception &e) {
		cerr << e.displayText() << endl;
	} catch(exception &e) {
		cerr << e.what() << endl;
	} catch(const char *s) {
		cerr << s << endl;
	}
}
<commit_msg>ui: extract method loadAllConfiguration<commit_after>#include <iostream>
#include <Poco/Logger.h>
#include <Poco/Message.h>
#include <Poco/File.h>
#include <Poco/Util/Option.h>
#include <Poco/Util/OptionSet.h>
#include <Poco/Util/HelpFormatter.h>
#include <Poco/Util/ServerApplication.h>

#include "server/MongooseServer.h"
#include "di/DependencyInjector.h"
#include "UIServerModule.h"

using namespace std;
using namespace Poco;
using namespace Poco::Util;
using namespace BeeeOn;

#define DEFAULT_PORT 8000

#define LOCAL_LOGGING_FILE  "logging.ini"
#define SYSTEM_LOGGING_FILE "/etc/beeeon/ui-server/logging.ini"

#define LOCAL_CONFIG_FILE  "server.ini"
#define SYSTEM_CONFIG_FILE "/etc/beeeon/ui-server/server.ini"

#define LOCAL_SERVICES_FILE  "services.xml"
#define SYSTEM_SERVICES_FILE "/etc/beeeon/ui-server/services.xml"

static Option optConfig("config", "c",
		"general configuration file to be used (xml, ini, properties)",
		false,
		"<file>",
		true);
static Option optServices("services", "s",
		"services configuration file to be used (xml, ini, properties)",
		false,
		"<file>",
		true);
static Option optLogging("logging", "l",
		"logging configuration file to be used (xml, ini, properties)",
		false,
		"<file>",
		true);
static Option optPort("port", "p",
		"server port to listen on",
		false,
		"<port>",
		true);
static Option optHelp("help", "h", "print help");

class Startup : public ServerApplication {
public:
	Startup():
		m_printHelp(false),
		m_serverPort(DEFAULT_PORT)
	{
	}

protected:
	void handleOption(const string &name, const string &value)
	{
		if (name == "services")
			m_userServices = value;
		if (name == "logging")
			m_userLogging = value;
		if (name == "config")
			m_userConfig = value;
		if (name == "help")
			m_printHelp = true;
		if (name == "port")
			m_serverPort = stoi(value);

		Application::handleOption(name, value);
	}

	void loadAllConfiguration()
	{
		findAndLoadConfig();
		findAndLoadLogging();
		findAndLoadServices();
	}

	void findAndLoadConfig()
	{
		File user(m_userConfig);
		File local(LOCAL_CONFIG_FILE);
		File system(SYSTEM_CONFIG_FILE);

		if (!m_userConfig.empty() && user.exists())
			loadConfiguration(user.path());
		else if (local.exists())
			loadConfiguration(local.path());
		else if (system.exists())
			loadConfiguration(system.path());
	}

	void findAndLoadLogging()
	{
		File user(m_userLogging);
		File local(LOCAL_LOGGING_FILE);
		File system(SYSTEM_LOGGING_FILE);

		if (!m_userLogging.empty() && user.exists())
			loadConfiguration(user.path());
		else if (local.exists())
			loadConfiguration(local.path());
		else if (system.exists())
			loadConfiguration(system.path());
	}

	void findAndLoadServices()
	{
		File user(m_userServices);
		File local(LOCAL_SERVICES_FILE);
		File system(SYSTEM_SERVICES_FILE);

		if (!m_userServices.empty() && user.exists()) {
			logger().notice(
				"loading configuration from " + user.path(),
				__FILE__, __LINE__);
			loadConfiguration(user.path());
		}
		else if (local.exists()) {
			logger().notice(
				"loading configuration from " + local.path(),
				__FILE__, __LINE__);
			loadConfiguration(local.path());
		}
		else if (system.exists()) {
			logger().notice(
				"loading configuration from " + system.path(),
				__FILE__, __LINE__);
			loadConfiguration(system.path());
		}
	}

	void initialize(Application &app)
	{
		Logger::root().setLevel(Logger::parseLevel("trace"));
		loadAllConfiguration();
		Application::initialize(app);
	}

	void defineOptions(OptionSet &options)
	{
		options.addOption(optConfig);
		options.addOption(optServices);
		options.addOption(optLogging);
		options.addOption(optPort);
		options.addOption(optHelp);
		Application::defineOptions(options);
	}

	int printHelp()
	{
		HelpFormatter help(options());
		help.setCommand(config().getString("application.baseName"));
		help.setUnixStyle(true);
		help.setWidth(80);
		help.setUsage("[-h] ...");
		help.format(cout);

		return EXIT_OK;
	}

	int main(const std::vector <std::string> &args)
	{
		if (m_printHelp)
			return printHelp();

		if (logger().debug())
			ManifestSingleton::reportInfo(logger());

		DependencyInjector injector(config().createView("services"));
		UIServerModule *module = injector
					.create<UIServerModule>("main");

		module->createServer(m_serverPort);
		module->server().start();

		waitForTerminationRequest();
		module->server().stop();
		return EXIT_OK;
	}

private:
	bool m_printHelp;
	unsigned int m_serverPort;
	string m_userLogging;
	string m_userConfig;
	string m_userServices;
};

int main(int argc, char **argv)
{
	Startup server;
	server.setUnixOptions(true);

	try {
		return server.run(argc, argv);
	} catch(Exception &e) {
		cerr << e.displayText() << endl;
	} catch(exception &e) {
		cerr << e.what() << endl;
	} catch(const char *s) {
		cerr << s << endl;
	}
}
<|endoftext|>


<commit_before>#include "THClKernels.h"
#include "EasyCL.h"
#include "THClTensor.h"
#include <stdexcept>
#include "THClReduceApplyUtils.h"
#include "CLKernel_structs.h"

#include <iostream>
using namespace std;

// Constructor
THClKernels::THClKernels(THClState *state, CLKernel *kernel) :
  state(state),
  kernel(kernel) {
}
THClKernels::~THClKernels() {
  for( int i = 0; i < (int)tensorInfoCls.size(); i++ ) {
    delete tensorInfoCls[i];
  }
}
// CLTensors =====================
THClKernels *THClKernels::in(THClTensor *tensor) {
  try {
    kernel->in(THClTensor_wrapper(state, tensor));
    kernel->in((int)THClTensor_storageOffset(state, tensor));
  } catch( runtime_error &e ) {
    THError(e.what());
  }
  return this;
}
THClKernels *THClKernels::inout(THClTensor *tensor) {
  try {
    kernel->inout(THClTensor_wrapper(state, tensor));
    kernel->in((int)THClTensor_storageOffset(state, tensor));
  } catch( runtime_error &e ) {
    THError(e.what());
  }
  return this;
}
THClKernels *THClKernels::out(THClTensor *tensor) {
  try {
    kernel->out(THClTensor_wrapper(state, tensor));
    kernel->in((int)THClTensor_storageOffset(state, tensor));
  } catch( runtime_error &e ) {
    THError(e.what());
  }
  return this;
}
// scalars ==================
THClKernels *THClKernels::in(int value) {
  try {
    kernel->in(value);
  } catch( runtime_error &e ) {
    THError(e.what());
  }
  return this;
}
THClKernels *THClKernels::in(float value) {
  try {
    kernel->in(value);
  } catch( runtime_error &e ) {
    THError(e.what());
  }
  return this;
}
// CLTensorInfos ================
template< typename IndexType >
THClKernels *THClKernels::in(TensorInfo<IndexType>tensorInfo) {
  TensorInfoCl *tensorInfoCl = new TensorInfoCl(tensorInfo);
  kernel->in(1, tensorInfoCl);
  kernel->in(tensorInfo.wrapper);
  tensorInfoCls.push_back(tensorInfoCl);
  return this;
}
template< typename IndexType >
THClKernels *THClKernels::inout(TensorInfo<IndexType>tensorInfo) {
  TensorInfoCl *tensorInfoCl = new TensorInfoCl(tensorInfo);
  kernel->in(1, tensorInfoCl);
  kernel->inout(tensorInfo.wrapper);
  tensorInfoCls.push_back(tensorInfoCl);
  return this;
}
template< typename IndexType >
THClKernels *THClKernels::out(TensorInfo<IndexType>tensorInfo) {
  TensorInfoCl *tensorInfoCl = new TensorInfoCl(tensorInfo);
  if( !tensorInfo.wrapper->isOnDevice() ) {
    tensorInfo.wrapper->createOnDevice();
  }
  kernel->in(1, tensorInfoCl);
  kernel->out(tensorInfo.wrapper);
  tensorInfoCls.push_back(tensorInfoCl);
  return this;
}
// CLWrapper ===============
THClKernels *THClKernels::in(CLWrapper *wrapper) {
  try {
    kernel->in(wrapper);
  } catch( runtime_error &e ) {
    THError(e.what());
  }
  return this;
}
THClKernels *THClKernels::inout(CLWrapper *wrapper) {
  try {
    kernel->inout(wrapper);
  } catch( runtime_error &e ) {
    THError(e.what());
  }
  return this;
}
THClKernels *THClKernels::out(CLWrapper *wrapper) {
  try {
    if( !wrapper->isOnDevice() ) {
      wrapper->createOnDevice();
    }
    kernel->out(wrapper);
  } catch( runtime_error &e ) {
    THError(e.what());
  }
  return this;
}
void THClKernels::run(dim3 grid, dim3 block) {
  dim3 global_ws;
  for( int i = 0; i < 3; i++ ) {
      global_ws.vec[i] = grid.vec[i] * block.vec[i];
  }
  try {
    kernel->run(3, global_ws.as_size_t(), block.as_size_t());
  } catch( runtime_error &e ) {
    cout << e.what() << endl;
    THError(e.what());
  }
}
// locals ==================
THClKernels *THClKernels::localFloats(int count) {
  try {
    kernel->localFloats(count);
  } catch( runtime_error &e ) {
    THError(e.what());
  }
  return this;
}

// template instantiations ====================
#define DECLARE_THCLKERNELS(IndexType) \
template \
THClKernels *THClKernels::in<IndexType>(TensorInfo<IndexType>tensorInfo); \
template \
THClKernels *THClKernels::inout<IndexType>(TensorInfo<IndexType>tensorInfo); \
template \
THClKernels *THClKernels::out<IndexType>(TensorInfo<IndexType>tensorInfo);

DECLARE_THCLKERNELS(unsigned int);
DECLARE_THCLKERNELS(unsigned long);

template CLKernel *CLKernel::in<>(int N, const TensorInfoCl *data);
template CLKernel *CLKernel::inout<>(int N, const TensorInfoCl *data);
template CLKernel *CLKernel::out<>(int N, const TensorInfoCl *data);

<commit_msg>change thclkernels template declaration from long to long long<commit_after>#include "THClKernels.h"
#include "EasyCL.h"
#include "THClTensor.h"
#include <stdexcept>
#include "THClReduceApplyUtils.h"
#include "CLKernel_structs.h"

#include <iostream>
using namespace std;

// Constructor
THClKernels::THClKernels(THClState *state, CLKernel *kernel) :
  state(state),
  kernel(kernel) {
}
THClKernels::~THClKernels() {
  for( int i = 0; i < (int)tensorInfoCls.size(); i++ ) {
    delete tensorInfoCls[i];
  }
}
// CLTensors =====================
THClKernels *THClKernels::in(THClTensor *tensor) {
  try {
    kernel->in(THClTensor_wrapper(state, tensor));
    kernel->in((int)THClTensor_storageOffset(state, tensor));
  } catch( runtime_error &e ) {
    THError(e.what());
  }
  return this;
}
THClKernels *THClKernels::inout(THClTensor *tensor) {
  try {
    kernel->inout(THClTensor_wrapper(state, tensor));
    kernel->in((int)THClTensor_storageOffset(state, tensor));
  } catch( runtime_error &e ) {
    THError(e.what());
  }
  return this;
}
THClKernels *THClKernels::out(THClTensor *tensor) {
  try {
    kernel->out(THClTensor_wrapper(state, tensor));
    kernel->in((int)THClTensor_storageOffset(state, tensor));
  } catch( runtime_error &e ) {
    THError(e.what());
  }
  return this;
}
// scalars ==================
THClKernels *THClKernels::in(int value) {
  try {
    kernel->in(value);
  } catch( runtime_error &e ) {
    THError(e.what());
  }
  return this;
}
THClKernels *THClKernels::in(float value) {
  try {
    kernel->in(value);
  } catch( runtime_error &e ) {
    THError(e.what());
  }
  return this;
}
// CLTensorInfos ================
template< typename IndexType >
THClKernels *THClKernels::in(TensorInfo<IndexType>tensorInfo) {
  TensorInfoCl *tensorInfoCl = new TensorInfoCl(tensorInfo);
  kernel->in(1, tensorInfoCl);
  kernel->in(tensorInfo.wrapper);
  tensorInfoCls.push_back(tensorInfoCl);
  return this;
}
template< typename IndexType >
THClKernels *THClKernels::inout(TensorInfo<IndexType>tensorInfo) {
  TensorInfoCl *tensorInfoCl = new TensorInfoCl(tensorInfo);
  kernel->in(1, tensorInfoCl);
  kernel->inout(tensorInfo.wrapper);
  tensorInfoCls.push_back(tensorInfoCl);
  return this;
}
template< typename IndexType >
THClKernels *THClKernels::out(TensorInfo<IndexType>tensorInfo) {
  TensorInfoCl *tensorInfoCl = new TensorInfoCl(tensorInfo);
  if( !tensorInfo.wrapper->isOnDevice() ) {
    tensorInfo.wrapper->createOnDevice();
  }
  kernel->in(1, tensorInfoCl);
  kernel->out(tensorInfo.wrapper);
  tensorInfoCls.push_back(tensorInfoCl);
  return this;
}
// CLWrapper ===============
THClKernels *THClKernels::in(CLWrapper *wrapper) {
  try {
    kernel->in(wrapper);
  } catch( runtime_error &e ) {
    THError(e.what());
  }
  return this;
}
THClKernels *THClKernels::inout(CLWrapper *wrapper) {
  try {
    kernel->inout(wrapper);
  } catch( runtime_error &e ) {
    THError(e.what());
  }
  return this;
}
THClKernels *THClKernels::out(CLWrapper *wrapper) {
  try {
    if( !wrapper->isOnDevice() ) {
      wrapper->createOnDevice();
    }
    kernel->out(wrapper);
  } catch( runtime_error &e ) {
    THError(e.what());
  }
  return this;
}
void THClKernels::run(dim3 grid, dim3 block) {
  dim3 global_ws;
  for( int i = 0; i < 3; i++ ) {
      global_ws.vec[i] = grid.vec[i] * block.vec[i];
  }
  try {
    kernel->run(3, global_ws.as_size_t(), block.as_size_t());
  } catch( runtime_error &e ) {
    cout << e.what() << endl;
    THError(e.what());
  }
}
// locals ==================
THClKernels *THClKernels::localFloats(int count) {
  try {
    kernel->localFloats(count);
  } catch( runtime_error &e ) {
    THError(e.what());
  }
  return this;
}

// template instantiations ====================
#define DECLARE_THCLKERNELS(IndexType) \
template \
THClKernels *THClKernels::in<IndexType>(TensorInfo<IndexType>tensorInfo); \
template \
THClKernels *THClKernels::inout<IndexType>(TensorInfo<IndexType>tensorInfo); \
template \
THClKernels *THClKernels::out<IndexType>(TensorInfo<IndexType>tensorInfo);

DECLARE_THCLKERNELS(unsigned int);
//DECLARE_THCLKERNELS(unsigned long);
DECLARE_THCLKERNELS(unsigned long long);

template CLKernel *CLKernel::in<>(int N, const TensorInfoCl *data);
template CLKernel *CLKernel::inout<>(int N, const TensorInfoCl *data);
template CLKernel *CLKernel::out<>(int N, const TensorInfoCl *data);

<|endoftext|>


<commit_before>#ifdef EMSCRIPTEN
  #include <emscripten.h>
#endif
#include <iostream>
#include <SDL/SDL.h>

using namespace std;

// Native GBC display info
const int NATIVE_WIDTH   = 160;
const int NATIVE_HEIGHT  = 144;
const float NATIVE_RATIO = 160.0 / 144;

int screenWidth;
int screenHeight;
int pixel_size_w = 5;
int pixel_size_h = 5;
bool surface_drawn = false;
bool keep_ratio = false;

// SDL Variables
SDL_Surface* window;

/**
 * Resize game surface depending on the window
 * @param windowWidth  window width
 * @param windowHeight window height
 */
void resize(int windowWidth, int windowHeight)
{
    float screenRatio = (float)windowWidth / windowHeight;

    float gameWidth;
    float gameHeight;

    if (screenRatio > NATIVE_RATIO) {
        gameWidth = NATIVE_WIDTH * ((float)windowHeight / NATIVE_HEIGHT);
        gameHeight = windowHeight;
    }
    else {
        gameWidth = windowWidth;
        gameHeight = NATIVE_HEIGHT * ((float)windowWidth / NATIVE_WIDTH);
    }

    //TODO : create/update game surface to gameWidth/gameHeight and center it
}

/**
 * Draw a big pixel
 */
void drawPixel(int x, int y, Uint8 r, Uint8 g, Uint8 b)
{
    int containerWidth = window->w;
    int containedWidth = NATIVE_WIDTH * pixel_size_w;
    int containerHeight = window->h;
    int containedHeight = NATIVE_HEIGHT * pixel_size_h;

    int offsetX = (int)(((float)containerWidth / 2) - ((float)containedWidth / 2));
    int offsetY = (int)(((float)containerHeight / 2) - ((float)containedHeight / 2));

    cout << offsetY << endl;

    x = x * pixel_size_w + offsetX;
    y = y * pixel_size_h + offsetY;

    SDL_Rect rect = { x, y, pixel_size_w, pixel_size_h };
    SDL_FillRect(window, &rect, SDL_MapRGB(window->format, r, g, b));
}

/**
 * Draw next frame
 */
void drawScreen()
{
    //TODO: control FPS with emscripten
    SDL_Flip(window);

    if (!surface_drawn) {
        surface_drawn = true;

        int pixelSizeW = window->w / NATIVE_WIDTH;
        int pixelSizeH = window->h / NATIVE_HEIGHT;

        if (!keep_ratio) {
            pixel_size_w = pixelSizeW;
            pixel_size_h = pixelSizeH;
        }
        else {
            pixel_size_w = min(pixelSizeW, pixelSizeH);
            pixel_size_h = pixel_size_w;
        }

        for (size_t i = 0; i < NATIVE_WIDTH; i++) {
            for (size_t j = 0; j < NATIVE_HEIGHT; j++) {
                drawPixel(i, j, rand() % 256, rand() % 256, rand() % 256);
            }
        }
    }
}

void processEvents()
{
    SDL_Event event;

    while(SDL_PollEvent(&event)) {
        switch(event.type) {
            case SDL_QUIT:
                exit(EXIT_SUCCESS);
                break;

            case SDL_VIDEORESIZE:
                resize(event.resize.w, event.resize.h);
        }
    }
}

/**
 * One iteration of the main loop
 */
void oneIteration()
{
    processEvents();
    drawScreen();
}

/**
 * Entry point
 */
int main(int argc, char** argv)
{
    #ifndef EMSCRIPTEN
        atexit(SDL_Quit);
    #endif

    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        cout << "Video initialization failed: " << SDL_GetError() << endl;
        exit(EXIT_FAILURE);
    }

    const SDL_VideoInfo* screenInfo = SDL_GetVideoInfo();
    screenWidth = screenInfo->current_w / 2;
    screenHeight = screenInfo->current_h / 2;
    int bpp = 32;
    int flags = SDL_HWSURFACE | SDL_RESIZABLE | SDL_DOUBLEBUF;

    if (SDL_SetVideoMode(screenWidth, screenHeight, bpp, flags) == 0) {
        cout << "Video mode set failed: " << SDL_GetError() << endl;
        exit(EXIT_SUCCESS);
    }
    SDL_WM_SetCaption("gbcEmulator", NULL);
    resize(screenWidth, screenHeight);

    window = SDL_GetVideoSurface();

    #ifdef EMSCRIPTEN
        emscripten_set_main_loop(oneIteration, 0, 1);
    #else
        while(1) {
            oneIteration();
            //60 FPS
            SDL_Delay(16);
        }

        SDL_Quit();
    #endif

    return EXIT_SUCCESS;
}
<commit_msg>Cleaning<commit_after>#ifdef EMSCRIPTEN
  #include <emscripten.h>
#endif
#include <iostream>
#include <SDL/SDL.h>

using namespace std;

// Native GBC display info
const int NATIVE_WIDTH   = 160;
const int NATIVE_HEIGHT  = 144;

int pixel_size_w = 5;
int pixel_size_h = 5;
bool surface_drawn = false;
bool keep_ratio = false;

// SDL Variables
SDL_Surface* window;

/**
 * Draw a big pixel
 */
void drawPixel(int x, int y, Uint8 r, Uint8 g, Uint8 b)
{
    int containerWidth = window->w;
    int containedWidth = NATIVE_WIDTH * pixel_size_w;
    int containerHeight = window->h;
    int containedHeight = NATIVE_HEIGHT * pixel_size_h;

    int offsetX = (int)(((float)containerWidth / 2) - ((float)containedWidth / 2));
    int offsetY = (int)(((float)containerHeight / 2) - ((float)containedHeight / 2));

    x = x * pixel_size_w + offsetX;
    y = y * pixel_size_h + offsetY;

    SDL_Rect rect = { x, y, pixel_size_w, pixel_size_h };
    SDL_FillRect(window, &rect, SDL_MapRGB(window->format, r, g, b));
}

/**
 * Draw next frame
 */
void drawScreen()
{
    //TODO: control FPS with emscripten
    SDL_Flip(window);

    if (!surface_drawn) {
        surface_drawn = true;

        int pixelSizeW = window->w / NATIVE_WIDTH;
        int pixelSizeH = window->h / NATIVE_HEIGHT;

        if (!keep_ratio) {
            pixel_size_w = pixelSizeW;
            pixel_size_h = pixelSizeH;
        }
        else {
            pixel_size_w = min(pixelSizeW, pixelSizeH);
            pixel_size_h = pixel_size_w;
        }

        for (size_t i = 0; i < NATIVE_WIDTH; i++) {
            for (size_t j = 0; j < NATIVE_HEIGHT; j++) {
                drawPixel(i, j, rand() % 256, rand() % 256, rand() % 256);
            }
        }
    }
}

void processEvents()
{
    SDL_Event event;

    while(SDL_PollEvent(&event)) {
        switch(event.type) {
            case SDL_QUIT:
                exit(EXIT_SUCCESS);
                break;
        }
    }
}

/**
 * One iteration of the main loop
 */
void oneIteration()
{
    processEvents();
    drawScreen();
}

/**
 * Entry point
 */
int main(int argc, char** argv)
{
    #ifndef EMSCRIPTEN
        atexit(SDL_Quit);
    #endif

    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        cout << "Video initialization failed: " << SDL_GetError() << endl;
        exit(EXIT_FAILURE);
    }

    const SDL_VideoInfo* screenInfo = SDL_GetVideoInfo();
    int screenWidth = screenInfo->current_w / 2;
    int screenHeight = screenInfo->current_h / 2;
    int bpp = 32;
    int flags = SDL_HWSURFACE | SDL_RESIZABLE | SDL_DOUBLEBUF;

    if (SDL_SetVideoMode(screenWidth, screenHeight, bpp, flags) == 0) {
        cout << "Video mode set failed: " << SDL_GetError() << endl;
        exit(EXIT_SUCCESS);
    }
    SDL_WM_SetCaption("gbcEmulator", NULL);

    window = SDL_GetVideoSurface();

    #ifdef EMSCRIPTEN
        emscripten_set_main_loop(oneIteration, 0, 1);
    #else
        while(1) {
            oneIteration();
            //60 FPS
            SDL_Delay(16);
        }

        SDL_Quit();
    #endif

    return EXIT_SUCCESS;
}
<|endoftext|>