<commit_before>// Copyright (c) 2020 The Orbit 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 "OrbitCaptureClient/CaptureClient.h"

#include <absl/container/flat_hash_set.h>
#include <absl/flags/declare.h>
#include <absl/time/time.h>

#include <cstdint>
#include <outcome.hpp>
#include <string>
#include <type_traits>
#include <utility>

#include "OrbitBase/Future.h"
#include "OrbitBase/Logging.h"
#include "OrbitBase/Result.h"
#include "OrbitBase/Tracing.h"
#include "OrbitCaptureClient/CaptureEventProcessor.h"
#include "OrbitCaptureClient/CaptureListener.h"
#include "OrbitClientData/FunctionUtils.h"
#include "OrbitClientData/ModuleData.h"
#include "OrbitClientData/ProcessData.h"
#include "absl/flags/flag.h"
#include "absl/strings/str_format.h"
#include "capture.pb.h"
#include "tracepoint.pb.h"

ABSL_DECLARE_FLAG(uint16_t, sampling_rate);
ABSL_DECLARE_FLAG(bool, frame_pointer_unwinding);

using orbit_client_protos::FunctionInfo;

using orbit_grpc_protos::CaptureOptions;
using orbit_grpc_protos::CaptureRequest;
using orbit_grpc_protos::CaptureResponse;
using orbit_grpc_protos::TracepointInfo;

using orbit_base::Future;

static CaptureOptions::InstrumentedFunction::FunctionType InstrumentedFunctionTypeFromOrbitType(
    FunctionInfo::OrbitType orbit_type) {
  switch (orbit_type) {
    case FunctionInfo::kOrbitTimerStart:
      return CaptureOptions::InstrumentedFunction::kTimerStart;
    case FunctionInfo::kOrbitTimerStop:
      return CaptureOptions::InstrumentedFunction::kTimerStop;
    default:
      return CaptureOptions::InstrumentedFunction::kRegular;
  }
}

Future<ErrorMessageOr<CaptureListener::CaptureOutcome>> CaptureClient::Capture(
    ThreadPool* thread_pool, const ProcessData& process,
    const orbit_client_data::ModuleManager& module_manager,
    absl::flat_hash_map<uint64_t, FunctionInfo> selected_functions,
    TracepointInfoSet selected_tracepoints, absl::flat_hash_set<uint64_t> frame_track_function_ids,
    bool collect_thread_state, bool enable_introspection) {
  absl::MutexLock lock(&state_mutex_);
  if (state_ != State::kStopped) {
    return {
        ErrorMessage("Capture cannot be started, the previous capture is still "
                     "running/stopping.")};
  }

  state_ = State::kStarting;

  // TODO(168797897) Here a copy of the process is created. The loaded modules of this process were
  // likely filled when the process was selected, which might be a while back. Between then and now
  // the loaded modules might have changed. Up to date information about which modules are loaded
  // should be used here. (Even better: while taking a capture this should always be up to date)
  ProcessData process_copy = process;

  auto capture_result = thread_pool->Schedule(
      [this, process = std::move(process_copy), &module_manager,
       selected_functions = std::move(selected_functions), selected_tracepoints,
       frame_track_function_ids = std::move(frame_track_function_ids), collect_thread_state,
       enable_introspection]() mutable {
        return CaptureSync(std::move(process), module_manager, std::move(selected_functions),
                           std::move(selected_tracepoints), std::move(frame_track_function_ids),
                           collect_thread_state, enable_introspection);
      });

  return capture_result;
}

ErrorMessageOr<CaptureListener::CaptureOutcome> CaptureClient::CaptureSync(
    ProcessData&& process, const orbit_client_data::ModuleManager& module_manager,
    absl::flat_hash_map<uint64_t, FunctionInfo> selected_functions,
    TracepointInfoSet selected_tracepoints, absl::flat_hash_set<uint64_t> frame_track_function_ids,
    bool collect_thread_state, bool enable_introspection) {
  ORBIT_SCOPE_FUNCTION;
  writes_done_failed_ = false;
  try_abort_ = false;
  {
    absl::WriterMutexLock lock{&context_and_stream_mutex_};
    CHECK(client_context_ == nullptr);
    CHECK(reader_writer_ == nullptr);
    client_context_ = std::make_unique<grpc::ClientContext>();
    reader_writer_ = capture_service_->Capture(client_context_.get());
  }

  CaptureRequest request;
  CaptureOptions* capture_options = request.mutable_capture_options();
  capture_options->set_trace_context_switches(true);
  capture_options->set_pid(process.pid());
  uint16_t sampling_rate = absl::GetFlag(FLAGS_sampling_rate);
  if (sampling_rate == 0) {
    capture_options->set_unwinding_method(CaptureOptions::kUndefined);
  } else {
    capture_options->set_sampling_rate(sampling_rate);
    if (absl::GetFlag(FLAGS_frame_pointer_unwinding)) {
      capture_options->set_unwinding_method(CaptureOptions::kFramePointers);
    } else {
      capture_options->set_unwinding_method(CaptureOptions::kDwarf);
    }
  }

  capture_options->set_trace_thread_state(collect_thread_state);
  capture_options->set_trace_gpu_driver(true);
  for (const auto& [function_id, function] : selected_functions) {
    CaptureOptions::InstrumentedFunction* instrumented_function =
        capture_options->add_instrumented_functions();
    instrumented_function->set_file_path(function.loaded_module_path());
    const ModuleData* module = module_manager.GetModuleByPath(function.loaded_module_path());
    CHECK(module != nullptr);
    instrumented_function->set_file_offset(function_utils::Offset(function, *module));
    instrumented_function->set_function_id(function_id);
    instrumented_function->set_function_type(
        InstrumentedFunctionTypeFromOrbitType(function.orbit_type()));
  }

  for (const auto& tracepoint : selected_tracepoints) {
    TracepointInfo* instrumented_tracepoint = capture_options->add_instrumented_tracepoint();
    instrumented_tracepoint->set_category(tracepoint.category());
    instrumented_tracepoint->set_name(tracepoint.name());
  }

  capture_options->set_enable_introspection(enable_introspection);

  bool request_write_succeeded;
  {
    absl::ReaderMutexLock lock{&context_and_stream_mutex_};
    request_write_succeeded = reader_writer_->Write(request);
    if (!request_write_succeeded) {
      reader_writer_->WritesDone();
    }
  }
  if (!request_write_succeeded) {
    ERROR("Sending CaptureRequest on Capture's gRPC stream");
    ErrorMessageOr<void> finish_result = FinishCapture();
    std::string error_string =
        absl::StrFormat("Error sending capture request.%s",
                        finish_result.has_error() ? ("\n" + finish_result.error().message()) : "");
    return ErrorMessage{error_string};
  }
  LOG("Sent CaptureRequest on Capture's gRPC stream: asking to start capturing");

  {
    absl::MutexLock lock{&state_mutex_};
    state_ = State::kStarted;
  }

  CaptureEventProcessor event_processor(capture_listener_);

  capture_listener_->OnCaptureStarted(std::move(process), std::move(selected_functions),
                                      std::move(selected_tracepoints),
                                      std::move(frame_track_function_ids));

  while (!writes_done_failed_ && !try_abort_) {
    CaptureResponse response;
    bool read_succeeded;
    {
      absl::ReaderMutexLock lock{&context_and_stream_mutex_};
      read_succeeded = reader_writer_->Read(&response);
    }
    if (read_succeeded) {
      event_processor.ProcessEvents(response.capture_events());
    } else {
      break;
    }
  }

  ErrorMessageOr<void> finish_result = FinishCapture();
  if (try_abort_) {
    LOG("TryCancel on Capture's gRPC context was called: Read on Capture's gRPC stream failed");
    return CaptureListener::CaptureOutcome::kCancelled;
  }

  if (writes_done_failed_) {
    LOG("WritesDone on Capture's gRPC stream failed: stop reading and try to finish the gRPC call");
    std::string error_string = absl::StrFormat(
        "Unable to finish the capture in orderly manner, performing emergency stop.%s",
        finish_result.has_error() ? ("\n" + finish_result.error().message()) : "");
    return ErrorMessage{error_string};
  }

  LOG("Finished reading from Capture's gRPC stream: all capture data has been received");
  if (finish_result.has_error()) return finish_result.error();

  return CaptureListener::CaptureOutcome::kComplete;
}

bool CaptureClient::StopCapture() {
  {
    absl::MutexLock lock(&state_mutex_);
    if (state_ == State::kStarting) {
      // Block and wait until the state is not kStarting
      bool (*is_not_starting)(State*) = [](State* state) { return *state != State::kStarting; };
      state_mutex_.Await(absl::Condition(is_not_starting, &state_));
    }

    if (state_ != State::kStarted) {
      LOG("StopCapture ignored, because it is already stopping or stopped");
      return false;
    }
    state_ = State::kStopping;
  }

  bool writes_done_succeeded;
  {
    absl::ReaderMutexLock lock{&context_and_stream_mutex_};
    CHECK(reader_writer_ != nullptr);
    writes_done_succeeded = reader_writer_->WritesDone();
  }
  if (!writes_done_succeeded) {
    // Normally the capture thread waits until service stops sending messages,
    // but in this case since we failed to notify the service we pull emergency
    // stop plug. Setting this flag forces capture thread to exit as soon
    // as it notices that it was set.
    ERROR(
        "WritesDone on Capture's gRPC stream failed: unable to finish the "
        "capture in orderly manner, initiating emergency stop");
    writes_done_failed_ = true;
  } else {
    LOG("Finished writing on Capture's gRPC stream: asking to stop capturing");
  }

  return true;
}

bool CaptureClient::AbortCaptureAndWait(int64_t max_wait_ms) {
  {
    absl::ReaderMutexLock lock{&context_and_stream_mutex_};
    if (client_context_ == nullptr) {
      LOG("AbortCaptureAndWait ignored: no ClientContext to TryCancel");
      return false;
    }
    LOG("Calling TryCancel on Capture's gRPC context: aborting the capture");
    try_abort_ = true;
    client_context_->TryCancel();  // reader_writer_->Read in Capture should then fail
  }

  // With this wait we want to leave at least some time for FinishCapture to be called, so that
  // reader_writer_ and in particular client_context_ are destroyed before returning to the caller.
  {
    absl::MutexLock lock(&state_mutex_);
    state_mutex_.AwaitWithTimeout(
        absl::Condition(
            +[](State* state) { return *state == State::kStopped; }, &state_),
        absl::Milliseconds(max_wait_ms));
  }
  return true;
}

ErrorMessageOr<void> CaptureClient::FinishCapture() {
  ORBIT_SCOPE_FUNCTION;

  grpc::Status status;
  {
    absl::WriterMutexLock lock{&context_and_stream_mutex_};
    CHECK(reader_writer_ != nullptr);
    status = reader_writer_->Finish();
    reader_writer_.reset();
    CHECK(client_context_ != nullptr);
    client_context_.reset();
  }

  {
    absl::MutexLock lock(&state_mutex_);
    state_ = State::kStopped;
  }

  if (!status.ok()) {
    ERROR("Finishing gRPC call to Capture: %s", status.error_message());
    return ErrorMessage{status.error_message()};
  }
  return outcome::success();
}
<commit_msg>Improve error message in CaptureClient<commit_after>// Copyright (c) 2020 The Orbit 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 "OrbitCaptureClient/CaptureClient.h"

#include <absl/container/flat_hash_set.h>
#include <absl/flags/declare.h>
#include <absl/time/time.h>

#include <cstdint>
#include <outcome.hpp>
#include <string>
#include <type_traits>
#include <utility>

#include "OrbitBase/Future.h"
#include "OrbitBase/Logging.h"
#include "OrbitBase/Result.h"
#include "OrbitBase/Tracing.h"
#include "OrbitCaptureClient/CaptureEventProcessor.h"
#include "OrbitCaptureClient/CaptureListener.h"
#include "OrbitClientData/FunctionUtils.h"
#include "OrbitClientData/ModuleData.h"
#include "OrbitClientData/ProcessData.h"
#include "absl/flags/flag.h"
#include "absl/strings/str_format.h"
#include "capture.pb.h"
#include "tracepoint.pb.h"

ABSL_DECLARE_FLAG(uint16_t, sampling_rate);
ABSL_DECLARE_FLAG(bool, frame_pointer_unwinding);

using orbit_client_protos::FunctionInfo;

using orbit_grpc_protos::CaptureOptions;
using orbit_grpc_protos::CaptureRequest;
using orbit_grpc_protos::CaptureResponse;
using orbit_grpc_protos::TracepointInfo;

using orbit_base::Future;

static CaptureOptions::InstrumentedFunction::FunctionType InstrumentedFunctionTypeFromOrbitType(
    FunctionInfo::OrbitType orbit_type) {
  switch (orbit_type) {
    case FunctionInfo::kOrbitTimerStart:
      return CaptureOptions::InstrumentedFunction::kTimerStart;
    case FunctionInfo::kOrbitTimerStop:
      return CaptureOptions::InstrumentedFunction::kTimerStop;
    default:
      return CaptureOptions::InstrumentedFunction::kRegular;
  }
}

Future<ErrorMessageOr<CaptureListener::CaptureOutcome>> CaptureClient::Capture(
    ThreadPool* thread_pool, const ProcessData& process,
    const orbit_client_data::ModuleManager& module_manager,
    absl::flat_hash_map<uint64_t, FunctionInfo> selected_functions,
    TracepointInfoSet selected_tracepoints, absl::flat_hash_set<uint64_t> frame_track_function_ids,
    bool collect_thread_state, bool enable_introspection) {
  absl::MutexLock lock(&state_mutex_);
  if (state_ != State::kStopped) {
    return {
        ErrorMessage("Capture cannot be started, the previous capture is still "
                     "running/stopping.")};
  }

  state_ = State::kStarting;

  // TODO(168797897) Here a copy of the process is created. The loaded modules of this process were
  // likely filled when the process was selected, which might be a while back. Between then and now
  // the loaded modules might have changed. Up to date information about which modules are loaded
  // should be used here. (Even better: while taking a capture this should always be up to date)
  ProcessData process_copy = process;

  auto capture_result = thread_pool->Schedule(
      [this, process = std::move(process_copy), &module_manager,
       selected_functions = std::move(selected_functions), selected_tracepoints,
       frame_track_function_ids = std::move(frame_track_function_ids), collect_thread_state,
       enable_introspection]() mutable {
        return CaptureSync(std::move(process), module_manager, std::move(selected_functions),
                           std::move(selected_tracepoints), std::move(frame_track_function_ids),
                           collect_thread_state, enable_introspection);
      });

  return capture_result;
}

ErrorMessageOr<CaptureListener::CaptureOutcome> CaptureClient::CaptureSync(
    ProcessData&& process, const orbit_client_data::ModuleManager& module_manager,
    absl::flat_hash_map<uint64_t, FunctionInfo> selected_functions,
    TracepointInfoSet selected_tracepoints, absl::flat_hash_set<uint64_t> frame_track_function_ids,
    bool collect_thread_state, bool enable_introspection) {
  ORBIT_SCOPE_FUNCTION;
  writes_done_failed_ = false;
  try_abort_ = false;
  {
    absl::WriterMutexLock lock{&context_and_stream_mutex_};
    CHECK(client_context_ == nullptr);
    CHECK(reader_writer_ == nullptr);
    client_context_ = std::make_unique<grpc::ClientContext>();
    reader_writer_ = capture_service_->Capture(client_context_.get());
  }

  CaptureRequest request;
  CaptureOptions* capture_options = request.mutable_capture_options();
  capture_options->set_trace_context_switches(true);
  capture_options->set_pid(process.pid());
  uint16_t sampling_rate = absl::GetFlag(FLAGS_sampling_rate);
  if (sampling_rate == 0) {
    capture_options->set_unwinding_method(CaptureOptions::kUndefined);
  } else {
    capture_options->set_sampling_rate(sampling_rate);
    if (absl::GetFlag(FLAGS_frame_pointer_unwinding)) {
      capture_options->set_unwinding_method(CaptureOptions::kFramePointers);
    } else {
      capture_options->set_unwinding_method(CaptureOptions::kDwarf);
    }
  }

  capture_options->set_trace_thread_state(collect_thread_state);
  capture_options->set_trace_gpu_driver(true);
  for (const auto& [function_id, function] : selected_functions) {
    CaptureOptions::InstrumentedFunction* instrumented_function =
        capture_options->add_instrumented_functions();
    instrumented_function->set_file_path(function.loaded_module_path());
    const ModuleData* module = module_manager.GetModuleByPath(function.loaded_module_path());
    CHECK(module != nullptr);
    instrumented_function->set_file_offset(function_utils::Offset(function, *module));
    instrumented_function->set_function_id(function_id);
    instrumented_function->set_function_type(
        InstrumentedFunctionTypeFromOrbitType(function.orbit_type()));
  }

  for (const auto& tracepoint : selected_tracepoints) {
    TracepointInfo* instrumented_tracepoint = capture_options->add_instrumented_tracepoint();
    instrumented_tracepoint->set_category(tracepoint.category());
    instrumented_tracepoint->set_name(tracepoint.name());
  }

  capture_options->set_enable_introspection(enable_introspection);

  bool request_write_succeeded;
  {
    absl::ReaderMutexLock lock{&context_and_stream_mutex_};
    request_write_succeeded = reader_writer_->Write(request);
    if (!request_write_succeeded) {
      reader_writer_->WritesDone();
    }
  }
  if (!request_write_succeeded) {
    ERROR("Sending CaptureRequest on Capture's gRPC stream");
    ErrorMessageOr<void> finish_result = FinishCapture();
    std::string error_string =
        absl::StrFormat("Error sending capture request.%s",
                        finish_result.has_error() ? ("\n" + finish_result.error().message()) : "");
    return ErrorMessage{error_string};
  }
  LOG("Sent CaptureRequest on Capture's gRPC stream: asking to start capturing");

  {
    absl::MutexLock lock{&state_mutex_};
    state_ = State::kStarted;
  }

  CaptureEventProcessor event_processor(capture_listener_);

  capture_listener_->OnCaptureStarted(std::move(process), std::move(selected_functions),
                                      std::move(selected_tracepoints),
                                      std::move(frame_track_function_ids));

  while (!writes_done_failed_ && !try_abort_) {
    CaptureResponse response;
    bool read_succeeded;
    {
      absl::ReaderMutexLock lock{&context_and_stream_mutex_};
      read_succeeded = reader_writer_->Read(&response);
    }
    if (read_succeeded) {
      event_processor.ProcessEvents(response.capture_events());
    } else {
      break;
    }
  }

  ErrorMessageOr<void> finish_result = FinishCapture();
  if (try_abort_) {
    LOG("TryCancel on Capture's gRPC context was called: Read on Capture's gRPC stream failed");
    return CaptureListener::CaptureOutcome::kCancelled;
  }

  if (writes_done_failed_) {
    LOG("WritesDone on Capture's gRPC stream failed: stop reading and try to finish the gRPC call");
    std::string error_string = absl::StrFormat(
        "Unable to finish the capture in orderly manner, performing emergency stop.%s",
        finish_result.has_error() ? ("\n" + finish_result.error().message()) : "");
    return ErrorMessage{error_string};
  }

  LOG("Finished reading from Capture's gRPC stream: all capture data has been received");
  if (finish_result.has_error()) {
    return ErrorMessage{absl::StrFormat(
        "Unable to finish the capture in an orderly manner. The following error occurred: %s",
        finish_result.error().message())};
  }
  return CaptureListener::CaptureOutcome::kComplete;
}

bool CaptureClient::StopCapture() {
  {
    absl::MutexLock lock(&state_mutex_);
    if (state_ == State::kStarting) {
      // Block and wait until the state is not kStarting
      bool (*is_not_starting)(State*) = [](State* state) { return *state != State::kStarting; };
      state_mutex_.Await(absl::Condition(is_not_starting, &state_));
    }

    if (state_ != State::kStarted) {
      LOG("StopCapture ignored, because it is already stopping or stopped");
      return false;
    }
    state_ = State::kStopping;
  }

  bool writes_done_succeeded;
  {
    absl::ReaderMutexLock lock{&context_and_stream_mutex_};
    CHECK(reader_writer_ != nullptr);
    writes_done_succeeded = reader_writer_->WritesDone();
  }
  if (!writes_done_succeeded) {
    // Normally the capture thread waits until service stops sending messages,
    // but in this case since we failed to notify the service we pull emergency
    // stop plug. Setting this flag forces capture thread to exit as soon
    // as it notices that it was set.
    ERROR(
        "WritesDone on Capture's gRPC stream failed: unable to finish the "
        "capture in orderly manner, initiating emergency stop");
    writes_done_failed_ = true;
  } else {
    LOG("Finished writing on Capture's gRPC stream: asking to stop capturing");
  }

  return true;
}

bool CaptureClient::AbortCaptureAndWait(int64_t max_wait_ms) {
  {
    absl::ReaderMutexLock lock{&context_and_stream_mutex_};
    if (client_context_ == nullptr) {
      LOG("AbortCaptureAndWait ignored: no ClientContext to TryCancel");
      return false;
    }
    LOG("Calling TryCancel on Capture's gRPC context: aborting the capture");
    try_abort_ = true;
    client_context_->TryCancel();  // reader_writer_->Read in Capture should then fail
  }

  // With this wait we want to leave at least some time for FinishCapture to be called, so that
  // reader_writer_ and in particular client_context_ are destroyed before returning to the caller.
  {
    absl::MutexLock lock(&state_mutex_);
    state_mutex_.AwaitWithTimeout(
        absl::Condition(
            +[](State* state) { return *state == State::kStopped; }, &state_),
        absl::Milliseconds(max_wait_ms));
  }
  return true;
}

ErrorMessageOr<void> CaptureClient::FinishCapture() {
  ORBIT_SCOPE_FUNCTION;

  grpc::Status status;
  {
    absl::WriterMutexLock lock{&context_and_stream_mutex_};
    CHECK(reader_writer_ != nullptr);
    status = reader_writer_->Finish();
    reader_writer_.reset();
    CHECK(client_context_ != nullptr);
    client_context_.reset();
  }

  {
    absl::MutexLock lock(&state_mutex_);
    state_ = State::kStopped;
  }

  if (!status.ok()) {
    ERROR("Finishing gRPC call to Capture: %s", status.error_message());
    return ErrorMessage{status.error_message()};
  }
  return outcome::success();
}
<|endoftext|>


<commit_before>#include "common.h"
#include <v8.h>
#include <Psapi.h>
#include <vector>
using namespace std;

namespace NodeJudger {

string GetLastErrorAsString()
{
    //Get the error message, if any.
    DWORD error_message_id = GetLastError();

    // No error message has been recorded
    if(error_message_id == 0) return std::string();

    LPSTR message_buffer = nullptr;
    size_t size = FormatMessageA(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, error_message_id,
            MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), (LPSTR)&message_buffer, 0, NULL);

    std::string message(message_buffer, size);

    // Free the buffer.
    LocalFree(message_buffer);

    return message;
}

string GetEnvironmentVar(LPCSTR key)
{
    // use GetEnvironmentVariable
    // refer to https://github.com/nodejs/node/blob/v6.9.4/src/node.cc#L2736
    char buffer[32767];
    DWORD result = GetEnvironmentVariableA(key, buffer, sizeof(buffer));

    // If result >= sizeof buffer the buffer was too small. That should never
    // happen. If result == 0 and result != ERROR_SUCCESS the variable was not
    // not found.
    if((result > 0 || GetLastError() == ERROR_SUCCESS) &&
            result < sizeof(buffer))
    {
        return buffer;
    }

    return "";
}

string GetTempDirectory()
{
    // refet to https://github.com/nodejs/node/blob/v6.9.4/lib/os.js#L34
    string path = "";
    path = GetEnvironmentVar("TEMP");
    if(!path.size()) path = GetEnvironmentVar("TMP");
    if(!path.size()) path = GetEnvironmentVar("SystemRoot") + "\\temp";
    if(!path.size() || path == "\\temp") path = GetEnvironmentVar("windir") + "\\temp";

    if(path.size() && path[path.size() - 1] == '\\' && (path.size() < 2 || path[path.size() - 2] != ':'))
    {
        path = path.substr(0, path.size() - 1);
    }

    return path;
}

string GetDLLNameFromDebug(const LOAD_DLL_DEBUG_INFO& load_dll_info)
{
    BOOL success = FALSE;
    char filename[MAX_PATH + 1];
    HANDLE file_map;

    DWORD file_size_hi = 0;
    DWORD file_size_lo = GetFileSize(load_dll_info.hFile, &file_size_hi);

    if(file_size_lo == 0 && file_size_hi == 0)
    {
        return "";
    }

    file_map = CreateFileMapping(load_dll_info.hFile,
            NULL,
            PAGE_READONLY,
            0,
            1,
            NULL);

    if(file_map)
    {
        void* mem = MapViewOfFile(file_map, FILE_MAP_READ, 0, 0, 1);

        if(mem)
        {
            if(GetMappedFileName(GetCurrentProcess(),
                    mem,
                    filename,
                    MAX_PATH))
            {
                UnmapViewOfFile(mem);
                CloseHandle(file_map);
                return filename;
            }
        }

        UnmapViewOfFile(mem);
        CloseHandle(file_map);
    }

    return "";
}

vector<string> __dlls;
void AddSupportedDLLName(string name)
{
    __dlls.push_back(name);
}

bool IsDLLSupported(string dll_path)
{
    for(int i = 0; i < __dlls.size(); i++)
    {
        if(dll_path.indexOf(__dlls[i]) != string::npos)
        {
            return true;
        }
    }

    return false;
}

}<commit_msg>fix: indexOf -> find<commit_after>#include "common.h"
#include <v8.h>
#include <Psapi.h>
#include <vector>
using namespace std;

namespace NodeJudger {

string GetLastErrorAsString()
{
    //Get the error message, if any.
    DWORD error_message_id = GetLastError();

    // No error message has been recorded
    if(error_message_id == 0) return std::string();

    LPSTR message_buffer = nullptr;
    size_t size = FormatMessageA(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, error_message_id,
            MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), (LPSTR)&message_buffer, 0, NULL);

    std::string message(message_buffer, size);

    // Free the buffer.
    LocalFree(message_buffer);

    return message;
}

string GetEnvironmentVar(LPCSTR key)
{
    // use GetEnvironmentVariable
    // refer to https://github.com/nodejs/node/blob/v6.9.4/src/node.cc#L2736
    char buffer[32767];
    DWORD result = GetEnvironmentVariableA(key, buffer, sizeof(buffer));

    // If result >= sizeof buffer the buffer was too small. That should never
    // happen. If result == 0 and result != ERROR_SUCCESS the variable was not
    // not found.
    if((result > 0 || GetLastError() == ERROR_SUCCESS) &&
            result < sizeof(buffer))
    {
        return buffer;
    }

    return "";
}

string GetTempDirectory()
{
    // refet to https://github.com/nodejs/node/blob/v6.9.4/lib/os.js#L34
    string path = "";
    path = GetEnvironmentVar("TEMP");
    if(!path.size()) path = GetEnvironmentVar("TMP");
    if(!path.size()) path = GetEnvironmentVar("SystemRoot") + "\\temp";
    if(!path.size() || path == "\\temp") path = GetEnvironmentVar("windir") + "\\temp";

    if(path.size() && path[path.size() - 1] == '\\' && (path.size() < 2 || path[path.size() - 2] != ':'))
    {
        path = path.substr(0, path.size() - 1);
    }

    return path;
}

string GetDLLNameFromDebug(const LOAD_DLL_DEBUG_INFO& load_dll_info)
{
    BOOL success = FALSE;
    char filename[MAX_PATH + 1];
    HANDLE file_map;

    DWORD file_size_hi = 0;
    DWORD file_size_lo = GetFileSize(load_dll_info.hFile, &file_size_hi);

    if(file_size_lo == 0 && file_size_hi == 0)
    {
        return "";
    }

    file_map = CreateFileMapping(load_dll_info.hFile,
            NULL,
            PAGE_READONLY,
            0,
            1,
            NULL);

    if(file_map)
    {
        void* mem = MapViewOfFile(file_map, FILE_MAP_READ, 0, 0, 1);

        if(mem)
        {
            if(GetMappedFileName(GetCurrentProcess(),
                    mem,
                    filename,
                    MAX_PATH))
            {
                UnmapViewOfFile(mem);
                CloseHandle(file_map);
                return filename;
            }
        }

        UnmapViewOfFile(mem);
        CloseHandle(file_map);
    }

    return "";
}

vector<string> __dlls;
void AddSupportedDLLName(string name)
{
    __dlls.push_back(name);
}

bool IsDLLSupported(string dll_path)
{
    for(int i = 0; i < __dlls.size(); i++)
    {
        if(dll_path.find(__dlls[i]) != string::npos)
        {
            return true;
        }
    }

    return false;
}

}<|endoftext|>


<commit_before>//
// RemotePhotoTool - remote camera control software
// Copyright (C) 2008-2014 Michael Fink
//
/// \file PhotoModeManager.cpp Photo mode manager classes
//

// includes
#include "stdafx.h"
#include "PhotoModeManager.hpp"
#include "IPhotoModeViewHost.hpp"
#include "PhotomatixInterface.hpp"
#include "ImageFileManager.hpp"
#include "RemoteReleaseControl.hpp"
#include "ShutterReleaseSettings.hpp"
#include "ViewFinderView.hpp"
#include "CameraErrorDlg.hpp"
#include "ShootingMode.hpp"
#include "ShutterSpeedValue.hpp"
#include "HuginInterface.hpp"

//
// HDRPhotoModeManager
//

bool HDRPhotoModeManager::Init(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl)
{
   m_spRemoteReleaseControl = spRemoteReleaseControl;

   // set default release settings
   try
   {
      ShutterReleaseSettings& settings = m_host.GetReleaseSettings();

      CString cszFilename =
         m_host.GetImageFileManager().NextFilename(imageTypeHDR);
      settings.Filename(cszFilename);

      m_spRemoteReleaseControl->SetReleaseSettings(settings);
   }
   catch (CameraException& ex)
   {
      CameraErrorDlg dlg(_T("Error while setting shooting settings"), ex);
      dlg.DoModal(m_hWnd);
      return false;
   }

   return true;
}

bool HDRPhotoModeManager::CheckManualMode()
{
   ShootingMode mode(m_spRemoteReleaseControl);

   // shooting mode change supported?
   if (!mode.IsSupportedChanging())
   {
      // no, notify user to switch to M
      ImageProperty shootingModeM = mode.Manual();
      ImageProperty currentShootingMode = mode.Current();

      if (currentShootingMode != shootingModeM)
      {
         AtlMessageBox(m_hWnd, _T("Please switch to Manual mode on camera!"), IDR_MAINFRAME, MB_OK);
         return false;
      }
   }
   else
   {
      // yes, switch to M
      try
      {
         ImageProperty shootingModeM = mode.Manual();
         m_spRemoteReleaseControl->SetImageProperty(shootingModeM);
      }
      catch (CameraException& ex)
      {
         CameraErrorDlg dlg(_T("Couldn't switch to Manual mode"), ex);
         dlg.DoModal(m_hWnd);
         return false;
      }
   }

   return true;
}

void HDRPhotoModeManager::OnReleasedAEBLast()
{
   // close viewfinder, if used at all
   m_spViewfinder.reset();

   m_bAEBInProgress = false;

   // now send images to Photomatix
   PhotomatixInterface pi(m_host.GetAppSettings().m_cszPhotomatixPath);
   if (!pi.IsInstalled())
   {
      AtlMessageBox(m_hWnd, _T("Photomatix is not installed"), IDR_MAINFRAME, MB_OK);
      return;
   }

   m_host.SetStatusText(_T("Starting Photomatix..."));

   pi.RunUI(m_vecAEBFilenameList);

   // enable viewfinder again when active
   if (m_bViewfinderActiveBeforeStart)
   {
      ViewFinderView* pViewfinder = m_host.GetViewFinderView();
      if (pViewfinder != NULL)
         pViewfinder->EnableUpdate(true);

      m_bViewfinderActiveBeforeStart = false;
   }
}

void HDRPhotoModeManager::RecalcAEBShutterSpeedList(size_t uiNumShots)
{
   m_vecAEBShutterSpeedValues.clear();

   unsigned int uiShutterSpeedPropertyId =
      m_spRemoteReleaseControl->MapImagePropertyTypeToId(T_enImagePropertyType::propTv);

   try
   {
      ImageProperty currentShutterSpeed = m_spRemoteReleaseControl->GetImageProperty(uiShutterSpeedPropertyId);

      ShutterSpeedValue shutterSpeedBase(currentShutterSpeed, m_spRemoteReleaseControl);
      ShutterSpeedValue shutterDown = shutterSpeedBase, shutterUp = shutterSpeedBase;

      for (size_t ui = 1; ui <= uiNumShots; ui++)
      {
         if (ui == 1)
         {
            m_vecAEBShutterSpeedValues.push_back(shutterSpeedBase.Value());
         }
         else
            if ((ui & 1) == 0) // even: 2, 4, 6, ...
            {
            ShutterSpeedValue prev = shutterDown;
            shutterDown.Subtract2EV();

            // limit
            if (prev != shutterDown)
               m_vecAEBShutterSpeedValues.push_back(shutterDown.Value());
            }
            else
               if ((ui & 1) == 1) // odd: 3, 5, 7, ...
               {
                  ShutterSpeedValue prev = shutterUp;
                  shutterUp.Add2EV();

                  // limit
                  if (prev != shutterUp)
                     m_vecAEBShutterSpeedValues.push_back(shutterUp.Value());
               }
      }
   }
   catch (CameraException& ex)
   {
      CameraErrorDlg dlg(_T("Couldn't get shutter speed values"), ex);
      dlg.DoModal(m_hWnd);
   }
}

void HDRPhotoModeManager::ReleaseAEBFirst()
{
   // disable viewfinder while shooting
   {
      ViewFinderView* pViewfinder = m_host.GetViewFinderView();

      m_bViewfinderActiveBeforeStart = pViewfinder != NULL;

      if (m_bViewfinderActiveBeforeStart)
         pViewfinder->EnableUpdate(false);
   }

   // action mode is only unlocked when we receive an image
   if (m_host.GetReleaseSettings().SaveTarget() != ShutterReleaseSettings::saveToCamera)
      m_host.LockActionMode(true);

   m_bAEBInProgress = true;
   m_vecAEBFilenameList.clear();
   m_uiCurrentAEBShutterSpeed = 0;

   if (!m_bViewfinderActiveBeforeStart)
   {
      try
      {
         // init viewfinder; this is done to speed up taking images;
         // in future it could be done with mirror lockup
         m_spViewfinder = m_spRemoteReleaseControl->StartViewfinder();
      }
      catch (CameraException& ex)
      {
         CameraErrorDlg dlg(_T("Couldn't start viewfinder"), ex);
         dlg.DoModal(m_hWnd);
      }
   }

   ReleaseAEBNext();
}

void HDRPhotoModeManager::ReleaseAEBNext()
{
   // called when shutter speed was changed successfully
   bool bLastShot = m_uiCurrentAEBShutterSpeed + 1 == m_vecAEBShutterSpeedValues.size();

   ShutterReleaseSettings& settings = m_host.GetReleaseSettings();

   settings.HandlerOnFinishedTransfer(
      bLastShot ?
         std::bind(&HDRPhotoModeManager::OnFinishedTransferLastAEB, this, std::placeholders::_1) :
         std::bind(&HDRPhotoModeManager::OnFinishedTransferNextAEB, this, std::placeholders::_1));

   CString cszFilename =
      m_host.GetImageFileManager().NextFilename(imageTypeHDR, m_uiCurrentAEBShutterSpeed == 0);
   settings.Filename(cszFilename);

   m_spRemoteReleaseControl->SetReleaseSettings(settings);

   // set status text
   CString cszText;
   cszText.Format(_T("Taking picture %Iu of %Iu with shutter speed %s"),
      m_uiCurrentAEBShutterSpeed + 1,
      m_vecAEBShutterSpeedValues.size(),
      m_vecAEBShutterSpeedValues[m_uiCurrentAEBShutterSpeed].AsString().GetString());
   m_host.SetStatusText(cszText);

   try
   {
      m_spRemoteReleaseControl->SetImageProperty(m_vecAEBShutterSpeedValues[m_uiCurrentAEBShutterSpeed]);

      m_spRemoteReleaseControl->Release();

      m_uiCurrentAEBShutterSpeed++;
   }
   catch (CameraException& ex)
   {
      CameraErrorDlg dlg(_T("Couldn't release AEB shutter"), ex);
      dlg.DoModal(m_hWnd);
   }
}

void HDRPhotoModeManager::OnFinishedTransferNextAEB(const ShutterReleaseSettings& settings)
{
   // save filename for further processing
   CString cszFilename = settings.Filename();
   m_vecAEBFilenameList.push_back(cszFilename);

   ATLASSERT(m_uiCurrentAEBShutterSpeed < m_vecAEBShutterSpeedValues.size());

   PostMessage(m_hWnd, WM_HDR_AEB_NEXT, 0, 0);
}

void HDRPhotoModeManager::OnFinishedTransferLastAEB(const ShutterReleaseSettings& settings)
{
   // save filename for further processing
   CString cszFilename = settings.Filename();
   m_vecAEBFilenameList.push_back(cszFilename);

   m_host.OnTransferredImage(cszFilename);

   PostMessage(m_hWnd, WM_HDR_AEB_LAST, 0, 0);
}

//
// PanoramaPhotoModeManager
//

bool PanoramaPhotoModeManager::Init(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl)
{
   m_spRemoteReleaseControl = spRemoteReleaseControl;

   // set default release settings
   try
   {
      ShutterReleaseSettings& settings = m_host.GetReleaseSettings();

      CString cszFilename =
         m_host.GetImageFileManager().NextFilename(imageTypePano);
      settings.Filename(cszFilename);

      m_spRemoteReleaseControl->SetReleaseSettings(settings);
   }
   catch (CameraException& ex)
   {
      CameraErrorDlg dlg(_T("Error while setting default shooting settings"), ex);
      dlg.DoModal(m_hWnd);
      return false;
   }

   return true;
}

void PanoramaPhotoModeManager::StartPanorama()
{
   HuginInterface hi(m_host.GetAppSettings().m_cszHuginPath);
   if (!hi.IsInstalled())
      AtlMessageBox(m_hWnd, _T("Hugin is not installed; panorama pictures will not be stitched at the end."), IDR_MAINFRAME, MB_OK);

   m_bStarted = true;
   m_vecPanoramaFilenameList.clear();
}

void PanoramaPhotoModeManager::StopPanorama()
{
   m_bStarted = false;
   m_vecPanoramaFilenameList.clear();
}

void PanoramaPhotoModeManager::StartHugin()
{
   HuginInterface hi(m_host.GetAppSettings().m_cszHuginPath);
   if (!hi.IsInstalled())
   {
      m_host.SetStatusText(_T("Finished taking panorama images"));
      return;
   }

   m_host.SetStatusText(_T("Starting Hugin..."));

   hi.RunUI(m_vecPanoramaFilenameList);
}

void PanoramaPhotoModeManager::ReleasePanorama()
{
   // called when shutter speed was changed successfully
   ShutterReleaseSettings& settings = m_host.GetReleaseSettings();

   settings.HandlerOnFinishedTransfer(
      std::bind(&PanoramaPhotoModeManager::OnFinishedTransfer, this, std::placeholders::_1));

   bool bNewPanorama = m_vecPanoramaFilenameList.empty();

   CString cszFilename =
      m_host.GetImageFileManager().NextFilename(imageTypePano, bNewPanorama);
   settings.Filename(cszFilename);

   m_spRemoteReleaseControl->SetReleaseSettings(settings);

   // set status text
   CString cszText;
   cszText.Format(_T("Taking picture; already took %Iu pictures."),
      m_vecPanoramaFilenameList.size() + 1);
   m_host.SetStatusText(cszText);

   // action mode is only unlocked when we receive an image
   if (m_host.GetReleaseSettings().SaveTarget() != ShutterReleaseSettings::saveToCamera)
      m_host.LockActionMode(true);

   try
   {
      m_spRemoteReleaseControl->Release();
   }
   catch (CameraException& ex)
   {
      CameraErrorDlg dlg(_T("Couldn't release shutter"), ex);
      dlg.DoModal(m_hWnd);
   }
}

void PanoramaPhotoModeManager::OnFinishedTransfer(const ShutterReleaseSettings& settings)
{
   // save panorama filename
   CString cszFilename = settings.Filename();
   m_vecPanoramaFilenameList.push_back(cszFilename);

   m_host.OnTransferredImage(cszFilename);

   m_host.LockActionMode(false);
}
<commit_msg>fixed crash when handler for finished images wasn't reset in HDRPhotoModeManager and PanoramaPhotoModeManager<commit_after>//
// RemotePhotoTool - remote camera control software
// Copyright (C) 2008-2014 Michael Fink
//
/// \file PhotoModeManager.cpp Photo mode manager classes
//

// includes
#include "stdafx.h"
#include "PhotoModeManager.hpp"
#include "IPhotoModeViewHost.hpp"
#include "PhotomatixInterface.hpp"
#include "ImageFileManager.hpp"
#include "RemoteReleaseControl.hpp"
#include "ShutterReleaseSettings.hpp"
#include "ViewFinderView.hpp"
#include "CameraErrorDlg.hpp"
#include "ShootingMode.hpp"
#include "ShutterSpeedValue.hpp"
#include "HuginInterface.hpp"

//
// HDRPhotoModeManager
//

bool HDRPhotoModeManager::Init(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl)
{
   m_spRemoteReleaseControl = spRemoteReleaseControl;

   // set default release settings
   try
   {
      ShutterReleaseSettings& settings = m_host.GetReleaseSettings();

      CString cszFilename =
         m_host.GetImageFileManager().NextFilename(imageTypeHDR);
      settings.Filename(cszFilename);

      settings.HandlerOnFinishedTransfer(nullptr);

      m_spRemoteReleaseControl->SetReleaseSettings(settings);
   }
   catch (CameraException& ex)
   {
      CameraErrorDlg dlg(_T("Error while setting shooting settings"), ex);
      dlg.DoModal(m_hWnd);
      return false;
   }

   return true;
}

bool HDRPhotoModeManager::CheckManualMode()
{
   ShootingMode mode(m_spRemoteReleaseControl);

   // shooting mode change supported?
   if (!mode.IsSupportedChanging())
   {
      // no, notify user to switch to M
      ImageProperty shootingModeM = mode.Manual();
      ImageProperty currentShootingMode = mode.Current();

      if (currentShootingMode != shootingModeM)
      {
         AtlMessageBox(m_hWnd, _T("Please switch to Manual mode on camera!"), IDR_MAINFRAME, MB_OK);
         return false;
      }
   }
   else
   {
      // yes, switch to M
      try
      {
         ImageProperty shootingModeM = mode.Manual();
         m_spRemoteReleaseControl->SetImageProperty(shootingModeM);
      }
      catch (CameraException& ex)
      {
         CameraErrorDlg dlg(_T("Couldn't switch to Manual mode"), ex);
         dlg.DoModal(m_hWnd);
         return false;
      }
   }

   return true;
}

void HDRPhotoModeManager::OnReleasedAEBLast()
{
   // close viewfinder, if used at all
   m_spViewfinder.reset();

   m_bAEBInProgress = false;

   // now send images to Photomatix
   PhotomatixInterface pi(m_host.GetAppSettings().m_cszPhotomatixPath);
   if (!pi.IsInstalled())
   {
      AtlMessageBox(m_hWnd, _T("Photomatix is not installed"), IDR_MAINFRAME, MB_OK);
      return;
   }

   m_host.SetStatusText(_T("Starting Photomatix..."));

   pi.RunUI(m_vecAEBFilenameList);

   // enable viewfinder again when active
   if (m_bViewfinderActiveBeforeStart)
   {
      ViewFinderView* pViewfinder = m_host.GetViewFinderView();
      if (pViewfinder != NULL)
         pViewfinder->EnableUpdate(true);

      m_bViewfinderActiveBeforeStart = false;
   }
}

void HDRPhotoModeManager::RecalcAEBShutterSpeedList(size_t uiNumShots)
{
   m_vecAEBShutterSpeedValues.clear();

   unsigned int uiShutterSpeedPropertyId =
      m_spRemoteReleaseControl->MapImagePropertyTypeToId(T_enImagePropertyType::propTv);

   try
   {
      ImageProperty currentShutterSpeed = m_spRemoteReleaseControl->GetImageProperty(uiShutterSpeedPropertyId);

      ShutterSpeedValue shutterSpeedBase(currentShutterSpeed, m_spRemoteReleaseControl);
      ShutterSpeedValue shutterDown = shutterSpeedBase, shutterUp = shutterSpeedBase;

      for (size_t ui = 1; ui <= uiNumShots; ui++)
      {
         if (ui == 1)
         {
            m_vecAEBShutterSpeedValues.push_back(shutterSpeedBase.Value());
         }
         else
            if ((ui & 1) == 0) // even: 2, 4, 6, ...
            {
            ShutterSpeedValue prev = shutterDown;
            shutterDown.Subtract2EV();

            // limit
            if (prev != shutterDown)
               m_vecAEBShutterSpeedValues.push_back(shutterDown.Value());
            }
            else
               if ((ui & 1) == 1) // odd: 3, 5, 7, ...
               {
                  ShutterSpeedValue prev = shutterUp;
                  shutterUp.Add2EV();

                  // limit
                  if (prev != shutterUp)
                     m_vecAEBShutterSpeedValues.push_back(shutterUp.Value());
               }
      }
   }
   catch (CameraException& ex)
   {
      CameraErrorDlg dlg(_T("Couldn't get shutter speed values"), ex);
      dlg.DoModal(m_hWnd);
   }
}

void HDRPhotoModeManager::ReleaseAEBFirst()
{
   // disable viewfinder while shooting
   {
      ViewFinderView* pViewfinder = m_host.GetViewFinderView();

      m_bViewfinderActiveBeforeStart = pViewfinder != NULL;

      if (m_bViewfinderActiveBeforeStart)
         pViewfinder->EnableUpdate(false);
   }

   // action mode is only unlocked when we receive an image
   if (m_host.GetReleaseSettings().SaveTarget() != ShutterReleaseSettings::saveToCamera)
      m_host.LockActionMode(true);

   m_bAEBInProgress = true;
   m_vecAEBFilenameList.clear();
   m_uiCurrentAEBShutterSpeed = 0;

   if (!m_bViewfinderActiveBeforeStart)
   {
      try
      {
         // init viewfinder; this is done to speed up taking images;
         // in future it could be done with mirror lockup
         m_spViewfinder = m_spRemoteReleaseControl->StartViewfinder();
      }
      catch (CameraException& ex)
      {
         CameraErrorDlg dlg(_T("Couldn't start viewfinder"), ex);
         dlg.DoModal(m_hWnd);
      }
   }

   ReleaseAEBNext();
}

void HDRPhotoModeManager::ReleaseAEBNext()
{
   // called when shutter speed was changed successfully
   bool bLastShot = m_uiCurrentAEBShutterSpeed + 1 == m_vecAEBShutterSpeedValues.size();

   ShutterReleaseSettings& settings = m_host.GetReleaseSettings();

   settings.HandlerOnFinishedTransfer(
      bLastShot ?
         std::bind(&HDRPhotoModeManager::OnFinishedTransferLastAEB, this, std::placeholders::_1) :
         std::bind(&HDRPhotoModeManager::OnFinishedTransferNextAEB, this, std::placeholders::_1));

   CString cszFilename =
      m_host.GetImageFileManager().NextFilename(imageTypeHDR, m_uiCurrentAEBShutterSpeed == 0);
   settings.Filename(cszFilename);

   m_spRemoteReleaseControl->SetReleaseSettings(settings);

   // set status text
   CString cszText;
   cszText.Format(_T("Taking picture %Iu of %Iu with shutter speed %s"),
      m_uiCurrentAEBShutterSpeed + 1,
      m_vecAEBShutterSpeedValues.size(),
      m_vecAEBShutterSpeedValues[m_uiCurrentAEBShutterSpeed].AsString().GetString());
   m_host.SetStatusText(cszText);

   try
   {
      m_spRemoteReleaseControl->SetImageProperty(m_vecAEBShutterSpeedValues[m_uiCurrentAEBShutterSpeed]);

      m_spRemoteReleaseControl->Release();

      m_uiCurrentAEBShutterSpeed++;
   }
   catch (CameraException& ex)
   {
      CameraErrorDlg dlg(_T("Couldn't release AEB shutter"), ex);
      dlg.DoModal(m_hWnd);
   }
}

void HDRPhotoModeManager::OnFinishedTransferNextAEB(const ShutterReleaseSettings& settings)
{
   // save filename for further processing
   CString cszFilename = settings.Filename();
   m_vecAEBFilenameList.push_back(cszFilename);

   ATLASSERT(m_uiCurrentAEBShutterSpeed < m_vecAEBShutterSpeedValues.size());

   PostMessage(m_hWnd, WM_HDR_AEB_NEXT, 0, 0);
}

void HDRPhotoModeManager::OnFinishedTransferLastAEB(const ShutterReleaseSettings& settings)
{
   // save filename for further processing
   CString cszFilename = settings.Filename();
   m_vecAEBFilenameList.push_back(cszFilename);

   m_host.OnTransferredImage(cszFilename);

   PostMessage(m_hWnd, WM_HDR_AEB_LAST, 0, 0);
}

//
// PanoramaPhotoModeManager
//

bool PanoramaPhotoModeManager::Init(std::shared_ptr<RemoteReleaseControl> spRemoteReleaseControl)
{
   m_spRemoteReleaseControl = spRemoteReleaseControl;

   // set default release settings
   try
   {
      ShutterReleaseSettings& settings = m_host.GetReleaseSettings();

      CString cszFilename =
         m_host.GetImageFileManager().NextFilename(imageTypePano);
      settings.Filename(cszFilename);

      settings.HandlerOnFinishedTransfer(nullptr);

      m_spRemoteReleaseControl->SetReleaseSettings(settings);
   }
   catch (CameraException& ex)
   {
      CameraErrorDlg dlg(_T("Error while setting default shooting settings"), ex);
      dlg.DoModal(m_hWnd);
      return false;
   }

   return true;
}

void PanoramaPhotoModeManager::StartPanorama()
{
   HuginInterface hi(m_host.GetAppSettings().m_cszHuginPath);
   if (!hi.IsInstalled())
      AtlMessageBox(m_hWnd, _T("Hugin is not installed; panorama pictures will not be stitched at the end."), IDR_MAINFRAME, MB_OK);

   m_bStarted = true;
   m_vecPanoramaFilenameList.clear();
}

void PanoramaPhotoModeManager::StopPanorama()
{
   m_bStarted = false;
   m_vecPanoramaFilenameList.clear();
}

void PanoramaPhotoModeManager::StartHugin()
{
   HuginInterface hi(m_host.GetAppSettings().m_cszHuginPath);
   if (!hi.IsInstalled())
   {
      m_host.SetStatusText(_T("Finished taking panorama images"));
      return;
   }

   m_host.SetStatusText(_T("Starting Hugin..."));

   hi.RunUI(m_vecPanoramaFilenameList);
}

void PanoramaPhotoModeManager::ReleasePanorama()
{
   // called when shutter speed was changed successfully
   ShutterReleaseSettings& settings = m_host.GetReleaseSettings();

   settings.HandlerOnFinishedTransfer(
      std::bind(&PanoramaPhotoModeManager::OnFinishedTransfer, this, std::placeholders::_1));

   bool bNewPanorama = m_vecPanoramaFilenameList.empty();

   CString cszFilename =
      m_host.GetImageFileManager().NextFilename(imageTypePano, bNewPanorama);
   settings.Filename(cszFilename);

   m_spRemoteReleaseControl->SetReleaseSettings(settings);

   // set status text
   CString cszText;
   cszText.Format(_T("Taking picture; already took %Iu pictures."),
      m_vecPanoramaFilenameList.size() + 1);
   m_host.SetStatusText(cszText);

   // action mode is only unlocked when we receive an image
   if (m_host.GetReleaseSettings().SaveTarget() != ShutterReleaseSettings::saveToCamera)
      m_host.LockActionMode(true);

   try
   {
      m_spRemoteReleaseControl->Release();
   }
   catch (CameraException& ex)
   {
      CameraErrorDlg dlg(_T("Couldn't release shutter"), ex);
      dlg.DoModal(m_hWnd);
   }
}

void PanoramaPhotoModeManager::OnFinishedTransfer(const ShutterReleaseSettings& settings)
{
   // save panorama filename
   CString cszFilename = settings.Filename();
   m_vecPanoramaFilenameList.push_back(cszFilename);

   m_host.OnTransferredImage(cszFilename);

   m_host.LockActionMode(false);
}
<|endoftext|>


<commit_before>#pragma once

#include "gui/controllers/metasprite-common.h"
#include "gui/view/common/namedlist.h"
#include "gui/view/common/orderedlist.h"

namespace UnTech {
namespace View {

namespace MSC = UnTech::MetaSpriteCommon;

// ANIMATIONS
// ==========
template <>
void NamedListCtrl<MSC::Animation>::CreateColumns();

template <>
void NamedListCtrl<MSC::Animation>::CreateColumns()
{
    AppendColumn("Animation", wxLIST_FORMAT_LEFT);

    HideHeader();
    BindColumnsToEqualWidth();
}

template <>
wxString NamedListCtrl<MSC::Animation>::OnGetItemText(long item, long column) const
{
    if (item < 0 || (unsigned)item >= _ptrList.size()) {
        return wxEmptyString;
    }

    switch (column) {
    case 0: {
        return _nameList[item];
    }
    default:
        return wxEmptyString;
    }
}

// ANIMATION INSTRUCTIONS
// ======================
template <>
void OrderedListCtrl<MSC::AnimationInstruction>::CreateColumns();

template <>
void OrderedListCtrl<MSC::AnimationInstruction>::CreateColumns()
{
    AppendColumn("Instruction", wxLIST_FORMAT_LEFT);
    AppendColumn("Frame", wxLIST_FORMAT_LEFT);
    AppendColumn("Parameter", wxLIST_FORMAT_LEFT);

    BindColumnsToEqualWidth();
}

template <>
wxString OrderedListCtrl<MSC::AnimationInstruction>::OnGetItemText(long item, long column) const
{
    typedef MSC::AnimationBytecode::Enum BC;

    const MSC::AnimationInstruction::list_t* list = _controller.list();

    if (list == nullptr) {
        return wxEmptyString;
    }

    const MSC::AnimationInstruction& inst = list->at(item);
    const MSC::AnimationBytecode& op = inst.operation();

    switch (column) {
    case 0: {
        return op.string();
    }

    case 1: {
        if (op.usesFrame()) {
            const auto& fref = inst.frame();

            wxString ret = fref.frameName;

            if (!fref.hFlip) {
                if (fref.vFlip) {
                    ret += " (vFlip)";
                }
            }
            else {
                if (!fref.vFlip) {
                    ret += " (hFlip)";
                }
                else {
                    ret += " (hvFlip)";
                }
            }

            return ret;
        }
        else {
            return wxEmptyString;
        }

    case 2:
        switch (op.value()) {
        case BC::GOTO_OFFSET:
            return wxString::Format("%d", inst.parameter());
            break;

        case BC::SET_FRAME_AND_WAIT_FRAMES:
            return wxString::Format("%d frames", inst.parameter());
            break;

        case BC::SET_FRAME_AND_WAIT_TIME:
            return wxString::Format("%d ms", inst.parameter() * 1000 / 75);

        case BC::SET_FRAME_AND_WAIT_XVECL:
        case BC::SET_FRAME_AND_WAIT_YVECL:
            return wxString::Format("%0.3f px", (double)inst.parameter() / 32);

        default:
            return wxEmptyString;
        }
    }

    default:
        return wxEmptyString;
    }
}
}
}
<commit_msg>fix: show goto label in animation sidebar list<commit_after>#pragma once

#include "gui/controllers/metasprite-common.h"
#include "gui/view/common/namedlist.h"
#include "gui/view/common/orderedlist.h"

namespace UnTech {
namespace View {

namespace MSC = UnTech::MetaSpriteCommon;

// ANIMATIONS
// ==========
template <>
void NamedListCtrl<MSC::Animation>::CreateColumns();

template <>
void NamedListCtrl<MSC::Animation>::CreateColumns()
{
    AppendColumn("Animation", wxLIST_FORMAT_LEFT);

    HideHeader();
    BindColumnsToEqualWidth();
}

template <>
wxString NamedListCtrl<MSC::Animation>::OnGetItemText(long item, long column) const
{
    if (item < 0 || (unsigned)item >= _ptrList.size()) {
        return wxEmptyString;
    }

    switch (column) {
    case 0: {
        return _nameList[item];
    }
    default:
        return wxEmptyString;
    }
}

// ANIMATION INSTRUCTIONS
// ======================
template <>
void OrderedListCtrl<MSC::AnimationInstruction>::CreateColumns();

template <>
void OrderedListCtrl<MSC::AnimationInstruction>::CreateColumns()
{
    AppendColumn("Instruction", wxLIST_FORMAT_LEFT);
    AppendColumn("Frame", wxLIST_FORMAT_LEFT);
    AppendColumn("Parameter", wxLIST_FORMAT_LEFT);

    BindColumnsToEqualWidth();
}

template <>
wxString OrderedListCtrl<MSC::AnimationInstruction>::OnGetItemText(long item, long column) const
{
    typedef MSC::AnimationBytecode::Enum BC;

    const MSC::AnimationInstruction::list_t* list = _controller.list();

    if (list == nullptr) {
        return wxEmptyString;
    }

    const MSC::AnimationInstruction& inst = list->at(item);
    const MSC::AnimationBytecode& op = inst.operation();

    switch (column) {
    case 0: {
        return op.string();
    }

    case 1: {
        if (op.usesFrame()) {
            const auto& fref = inst.frame();

            wxString ret = fref.frameName;

            if (!fref.hFlip) {
                if (fref.vFlip) {
                    ret += " (vFlip)";
                }
            }
            else {
                if (!fref.vFlip) {
                    ret += " (hFlip)";
                }
                else {
                    ret += " (hvFlip)";
                }
            }

            return ret;
        }
        else {
            return wxEmptyString;
        }

    case 2:
        switch (op.value()) {
        case BC::GOTO_OFFSET:
            return wxString::Format("%d", inst.parameter());
            break;

        case BC::GOTO_ANIMATION:
            return inst.gotoLabel();
            break;

        case BC::SET_FRAME_AND_WAIT_FRAMES:
            return wxString::Format("%d frames", inst.parameter());
            break;

        case BC::SET_FRAME_AND_WAIT_TIME:
            return wxString::Format("%d ms", inst.parameter() * 1000 / 75);

        case BC::SET_FRAME_AND_WAIT_XVECL:
        case BC::SET_FRAME_AND_WAIT_YVECL:
            return wxString::Format("%0.3f px", (double)inst.parameter() / 32);

        default:
            return wxEmptyString;
        }
    }

    default:
        return wxEmptyString;
    }
}
}
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/fir/check.H $   */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file check.H
/// @brief Subroutines for checking MSS FIR
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Marc Gollub <gollub@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#ifndef _MSS_CHECK_FIR_H_
#define _MSS_CHECK_FIR_H_

#include <fapi2.H>

namespace mss
{

namespace check
{

///
/// @brief Check FIR bits during PHY reset
/// @note For DDRPHYFIR and some MBACALFIR errors, up to and including phy reset, need to
/// handle within the phy reset procedure, since we may get errors from a 'non-functional'
/// magic port, which PRD can't analyze.
/// @tparam T the fapi2::TargetType which hold the FIR bits
/// @param[in] i_target the fapi2::Target
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff ok
///
template< fapi2::TargetType T >
fapi2::ReturnCode during_phy_reset( const fapi2::Target<T>& i_target );

}
}
#endif
<commit_msg>Add FIR checking to training error checking<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/fir/check.H $   */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file check.H
/// @brief Subroutines for checking MSS FIR
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Marc Gollub <gollub@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#ifndef _MSS_CHECK_FIR_H_
#define _MSS_CHECK_FIR_H_

#include <fapi2.H>

namespace mss
{

namespace check
{

///
/// @brief Check FIR bits during PHY reset
/// @note For DDRPHYFIR and some MBACALFIR errors, up to and including phy reset, need to
/// handle within the phy reset procedure, since we may get errors from a 'non-functional'
/// magic port, which PRD can't analyze.
/// @tparam T the fapi2::TargetType which hold the FIR bits
/// @param[in] i_target the fapi2::Target
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff ok
///
template< fapi2::TargetType T >
fapi2::ReturnCode during_phy_reset( const fapi2::Target<T>& i_target );

///
/// @brief Check FIR bits during draminit training
/// @param[in] i_target the dimm that was trained
/// @note We check for fir errors after training each rank
/// to see if there was a problem with the engine
/// FFDC errors return from this will be handle similar to other training errors
/// Logged if it affects less than a nibble and a bit.
/// Reported if it affects more than that
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS iff ok
///
template< fapi2::TargetType T >
fapi2::ReturnCode during_draminit_training( const fapi2::Target<T>& i_target );

}
}
#endif
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/utils/pos.H $   */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2016                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file pos.H
/// @brief Tools to return target's position from a fapi2 target
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: HB:FSP

#ifndef _MSS_POS_H_
#define _MSS_POS_H_

#include <fapi2.H>
#include <lib/shared/mss_const.H>

namespace mss
{

///
/// @brief Trait classes for the mss::pos functions
///
template<fapi2::TargetType T>
class posTraits
{
    public:
        // Needed as some targets have chip_unit_pos attributes,
        // uint8_t and some attr_pos, uint32_t. We don't really care
        // but the type checking in the macros sure does ...
        typedef uint8_t pos_type;
};

///
/// @brief DIMM Trait class for the mss::pos functions
///
template<>
class posTraits<fapi2::TARGET_TYPE_DIMM>
{
    public:
        typedef uint32_t pos_type;
};

///
/// @brief Processor Trait class for the mss::pos functions
///
template<>
class posTraits<fapi2::TARGET_TYPE_PROC_CHIP>
{
    public:
        typedef uint32_t pos_type;
};

///
/// @brief Return a target's position from a fapi2 target
/// @tparam T the fapi2::TargetType
/// @param[in] i_target a target representing the target in question
/// @return The position relative to the chip
///
template< fapi2::TargetType T, typename TT = posTraits<T> >
inline typename TT::pos_type pos(const fapi2::Target<T>& i_target)
{
    typename TT::pos_type i_pos = 0;

    // Don't use FAPI_TRY as you'll mess up fapi2::current_err which
    // lmits where this can be used.
    if (FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, i_target, i_pos) != fapi2::FAPI2_RC_SUCCESS)
    {
        goto fapi_try_exit;
    }

    return i_pos;

fapi_try_exit:
    // If we can't get our unit position, we're in other trouble
    FAPI_ERR("can't get our chip unit position");

    // Cronusflex doesn't support Assert.
    // Enable once move to dev complete - AAM
#if MOVED_AWAY_FROM_CRONUSFLEX
    fapi2::Assert(false);
#endif
    return 0;
}

///
/// @brief Return a DIMM's position from a fapi2 target
/// @param[in] i_target a target representing the target in question
/// @return The position relative to the chip
///
template<>
inline posTraits<fapi2::TARGET_TYPE_DIMM>::pos_type pos(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target)
{
    posTraits<fapi2::TARGET_TYPE_DIMM>::pos_type i_pos = 0;

    if (FAPI_ATTR_GET(fapi2::ATTR_POS, i_target, i_pos) != fapi2::FAPI2_RC_SUCCESS)
    {
        goto fapi_try_exit;
    }

    return i_pos;

fapi_try_exit:
    // If we can't get our position, we're in other trouble
    FAPI_ERR("can't get our position");
#if MOVED_AWAY_FROM_CRONUSFLEX
    fapi2::Assert(false);
#endif
    return 0;

}

///
/// @brief Return a processor's position from a fapi2 target
/// @param[in] i_target a target representing the target in question
/// @return The position relative to the chip
///
template<>
inline posTraits<fapi2::TARGET_TYPE_PROC_CHIP>::pos_type pos(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target)
{
    posTraits<fapi2::TARGET_TYPE_PROC_CHIP>::pos_type i_pos = 0;

    if (FAPI_ATTR_GET(fapi2::ATTR_POS, i_target, i_pos) != fapi2::FAPI2_RC_SUCCESS)
    {
        goto fapi_try_exit;
    }

    return i_pos;

fapi_try_exit:
    // If we can't get our position, we're in other trouble
    FAPI_ERR("can't get our position");
#if MOVED_AWAY_FROM_CRONUSFLEX
    fapi2::Assert(false);
#endif
    return 0;

}

///
/// @brief Return a target's relative position from a fapi2 target
/// @tparam T the fapi2::TargetType
/// @tparam R the fapi2::TargetType we want the position relative to
/// @param[in] i_target a target representing the target in question
/// @return The position relative to chiplet R
///
template< fapi2::TargetType R, fapi2::TargetType T, typename TT = posTraits<T> >
inline typename TT::pos_type relative_pos(const fapi2::Target<T>& i_target);

///
/// @brief Return a MCA's relative position from an MCBIST
/// @param[in] i_target a target representing the target in question
/// @return The position relative to chiplet R
///
template<>
inline posTraits<fapi2::TARGET_TYPE_MCA>::pos_type
relative_pos<fapi2::TARGET_TYPE_MCBIST>(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target)
{
    return pos(i_target) % PORTS_PER_MCBIST;
}

///
/// @brief Return a DIMM's relative position from an MCS
/// @param[in] i_target a target representing the target in question
/// @return The position relative to chiplet R
///
template<>
inline posTraits<fapi2::TARGET_TYPE_DIMM>::pos_type
relative_pos<fapi2::TARGET_TYPE_MCS>(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target)
{
    constexpr uint64_t MAX_DIMM_PER_MCS = PORTS_PER_MCS * MAX_DIMM_PER_PORT;
    return pos(i_target) % MAX_DIMM_PER_MCS;
}

///
/// @brief Return an MCS's relative position from a processor
/// @param[in] i_target a target representing the target in question
/// @return The position relative to chiplet R
///
template<>
inline posTraits<fapi2::TARGET_TYPE_MCS>::pos_type
relative_pos<fapi2::TARGET_TYPE_PROC_CHIP>(const fapi2::Target<fapi2::TARGET_TYPE_MCS>& i_target)
{
    constexpr uint64_t MCS_PER_PROC = MC_PER_MODULE * MCS_PER_MC;
    return pos(i_target) % MCS_PER_PROC;
}

///
/// @brief Return an MCA's relative position from an MCS
/// @param[in] i_target a target representing the target in question
/// @return The position relative to chiplet R
///
template<>
inline posTraits<fapi2::TARGET_TYPE_MCA>::pos_type
relative_pos<fapi2::TARGET_TYPE_MCS>(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target)
{
    return pos(i_target) % PORTS_PER_MCS;
}

///
/// @brief Return a target's fapi position from a fapi2 target
/// @tparam T the fapi2::TargetType
/// @param[in] i_target a target representing the target in question
/// @return The position relative to the system
///
template< fapi2::TargetType T, typename TT = posTraits<T> >
inline uint32_t fapi_pos(const fapi2::Target<T>& i_target)
{
    uint32_t i_pos = 0;

    // Don't use FAPI_TRY as you'll mess up fapi2::current_err which
    // lmits where this can be used.
    if (FAPI_ATTR_GET(fapi2::ATTR_FAPI_POS, i_target, i_pos) != fapi2::FAPI2_RC_SUCCESS)
    {
        goto fapi_try_exit;
    }

    return i_pos;

fapi_try_exit:
    // If we can't get our fapi position, we're in other trouble
    FAPI_ERR("can't get our fapi position");
#if MOVED_AWAY_FROM_CRONUSFLEX
    fapi2::Assert(false);
#endif
    return 0;
}

}
#endif
<commit_msg>Change mss::pos for DIMM to leverage FAPI_POS<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/utils/pos.H $   */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2017                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file pos.H
/// @brief Tools to return target's position from a fapi2 target
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: HB:FSP

#ifndef _MSS_POS_H_
#define _MSS_POS_H_

#include <fapi2.H>
#include <lib/shared/mss_const.H>

namespace mss
{

///
/// @brief Trait classes for the mss::pos functions
///
template<fapi2::TargetType T>
class posTraits
{
    public:
        // Needed as some targets have chip_unit_pos attributes,
        // uint8_t and some attr_pos, uint32_t. We don't really care
        // but the type checking in the macros sure does ...
        typedef uint8_t pos_type;
};

///
/// @brief DIMM Trait class for the mss::pos functions
///
template<>
class posTraits<fapi2::TARGET_TYPE_DIMM>
{
    public:
        typedef uint32_t pos_type;
};

///
/// @brief Processor Trait class for the mss::pos functions
///
template<>
class posTraits<fapi2::TARGET_TYPE_PROC_CHIP>
{
    public:
        typedef uint32_t pos_type;
};

///
/// @brief Return a target's position from a fapi2 target
/// @tparam T the fapi2::TargetType
/// @param[in] i_target a target representing the target in question
/// @return The position relative to the chip
///
template< fapi2::TargetType T, typename TT = posTraits<T> >
inline typename TT::pos_type pos(const fapi2::Target<T>& i_target)
{
    typename TT::pos_type l_pos = 0;

    // Don't use FAPI_TRY as you'll mess up fapi2::current_err which
    // lmits where this can be used.
    if (FAPI_ATTR_GET(fapi2::ATTR_CHIP_UNIT_POS, i_target, l_pos) != fapi2::FAPI2_RC_SUCCESS)
    {
        goto fapi_try_exit;
    }

    return l_pos;

fapi_try_exit:
    // If we can't get our unit position, we're in other trouble
    FAPI_ERR("can't get our chip unit position");
    fapi2::Assert(false);
    return 0;
}

///
/// @brief Return a processor's position from a fapi2 target
/// @param[in] i_target a target representing the target in question
/// @return The position relative to the chip
///
template<>
inline posTraits<fapi2::TARGET_TYPE_PROC_CHIP>::pos_type pos(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target)
{
    posTraits<fapi2::TARGET_TYPE_PROC_CHIP>::pos_type l_pos = 0;

    if (FAPI_ATTR_GET(fapi2::ATTR_POS, i_target, l_pos) != fapi2::FAPI2_RC_SUCCESS)
    {
        goto fapi_try_exit;
    }

    return l_pos;

fapi_try_exit:
    // If we can't get our position, we're in other trouble
    FAPI_ERR("can't get our position");
    fapi2::Assert(false);
    return 0;

}

///
/// @brief Return a DIMM's position from a fapi2 target
/// @param[in] i_target a target representing the target in question
/// @return The position relative to the chip
///
template<>
inline posTraits<fapi2::TARGET_TYPE_DIMM>::pos_type pos(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target)
{
    // Proc 0 is DIMM 0-15, proc 2 is 64-79 - 64 is the stride between processors
    constexpr uint64_t DIMM_STRIDE_PER_PROC = 64;
    constexpr uint64_t TOTAL_DIMM = MC_PER_MODULE * MCS_PER_MC * PORTS_PER_MCS * MAX_DIMM_PER_PORT;

    posTraits<fapi2::TARGET_TYPE_DIMM>::pos_type l_pos = 0;

    // Using fapi2 rather than mss::find as this is pretty low level stuff.
    const auto l_proc_pos =
        mss::template pos(i_target.getParent<fapi2::TARGET_TYPE_MCA>().getParent<fapi2::TARGET_TYPE_PROC_CHIP>());

    if (FAPI_ATTR_GET(fapi2::ATTR_FAPI_POS, i_target, l_pos) != fapi2::FAPI2_RC_SUCCESS)
    {
        goto fapi_try_exit;
    }

    // To get the FAPI_POS to the equivilent of ATTR_POS, we need to normalize the fapi_pos value
    // to the processor (stride across which ever processor we're on) and then add in the delta
    // per processor as ATTR_POS isn't processor relative (delta is the total dimm on a processor)
    return ((l_pos - (l_proc_pos * DIMM_STRIDE_PER_PROC)) % TOTAL_DIMM) + (TOTAL_DIMM * l_proc_pos);

fapi_try_exit:
    // If we can't get our position, we're in other trouble
    FAPI_ERR("can't get our fapi position");
    fapi2::Assert(false);
    return 0;

}

///
/// @brief Return a target's relative position from a fapi2 target
/// @tparam T the fapi2::TargetType
/// @tparam R the fapi2::TargetType we want the position relative to
/// @param[in] i_target a target representing the target in question
/// @return The position relative to chiplet R
///
template< fapi2::TargetType R, fapi2::TargetType T, typename TT = posTraits<T> >
inline typename TT::pos_type relative_pos(const fapi2::Target<T>& i_target);

///
/// @brief Return a MCA's relative position from an MCBIST
/// @param[in] i_target a target representing the target in question
/// @return The position relative to chiplet R
///
template<>
inline posTraits<fapi2::TARGET_TYPE_MCA>::pos_type
relative_pos<fapi2::TARGET_TYPE_MCBIST>(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target)
{
    return pos(i_target) % PORTS_PER_MCBIST;
}

///
/// @brief Return a DIMM's relative position from an MCS
/// @param[in] i_target a target representing the target in question
/// @return The position relative to chiplet R
///
template<>
inline posTraits<fapi2::TARGET_TYPE_DIMM>::pos_type
relative_pos<fapi2::TARGET_TYPE_MCS>(const fapi2::Target<fapi2::TARGET_TYPE_DIMM>& i_target)
{
    constexpr uint64_t MAX_DIMM_PER_MCS = PORTS_PER_MCS * MAX_DIMM_PER_PORT;
    return pos(i_target) % MAX_DIMM_PER_MCS;
}

///
/// @brief Return an MCS's relative position from a processor
/// @param[in] i_target a target representing the target in question
/// @return The position relative to chiplet R
///
template<>
inline posTraits<fapi2::TARGET_TYPE_MCS>::pos_type
relative_pos<fapi2::TARGET_TYPE_PROC_CHIP>(const fapi2::Target<fapi2::TARGET_TYPE_MCS>& i_target)
{
    constexpr uint64_t MCS_PER_PROC = MC_PER_MODULE * MCS_PER_MC;
    return pos(i_target) % MCS_PER_PROC;
}

///
/// @brief Return an MCA's relative position from an MCS
/// @param[in] i_target a target representing the target in question
/// @return The position relative to chiplet R
///
template<>
inline posTraits<fapi2::TARGET_TYPE_MCA>::pos_type
relative_pos<fapi2::TARGET_TYPE_MCS>(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target)
{
    return pos(i_target) % PORTS_PER_MCS;
}

///
/// @brief Return a target's fapi position from a fapi2 target
/// @tparam T the fapi2::TargetType
/// @param[in] i_target a target representing the target in question
/// @return The position relative to the system
///
template< fapi2::TargetType T, typename TT = posTraits<T> >
inline uint32_t fapi_pos(const fapi2::Target<T>& i_target)
{
    uint32_t l_pos = 0;

    // Don't use FAPI_TRY as you'll mess up fapi2::current_err which
    // lmits where this can be used.
    if (FAPI_ATTR_GET(fapi2::ATTR_FAPI_POS, i_target, l_pos) != fapi2::FAPI2_RC_SUCCESS)
    {
        goto fapi_try_exit;
    }

    return l_pos;

fapi_try_exit:
    // If we can't get our fapi position, we're in other trouble
    FAPI_ERR("can't get our fapi position");
    fapi2::Assert(false);
    return 0;
}

}
#endif
<|endoftext|>


<commit_before>#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cstdarg>
#include <cerrno>
#include <vector>
#include <map>
#include <string>

#include <unistd.h>

#include "riscv-types.h"
#include "riscv-endian.h"
#include "riscv-regs.h"
#include "riscv-processor.h"
#include "riscv-format.h"
#include "riscv-opcodes.h"
#include "riscv-util.h"
#include "riscv-imm.h"
#include "riscv-decode.h"
#include "riscv-decode-switch.h"
#include "riscv-csr.h"
#include "riscv-compression.h"
#include "riscv-elf.h"
#include "riscv-elf-file.h"
#include "riscv-elf-format.h"

void riscv_execute_instruction(riscv_decode &dec, riscv_proc_state *proc)
{
	riscv_ptr next_pc = riscv_decode_instruction(dec, proc);
	switch (dec.op) {
		case riscv_op_addi:
			proc->i_reg[dec.rd].lu = proc->i_reg[dec.rs1].lu + dec.imm;
			proc->pc = next_pc;
			break;
		case riscv_op_lui:
			proc->i_reg[dec.rd].lu = dec.imm;
			proc->pc = next_pc;
			break;
		case riscv_op_scall:
			switch (proc->i_reg[riscv_ireg_a7].lu) {
				case 64: /* sys_write */
					proc->i_reg[riscv_ireg_a0].lu = write(proc->i_reg[riscv_ireg_a0].lu,
						proc->mem + proc->i_reg[riscv_ireg_a1].lu - proc->vaddr, proc->i_reg[riscv_ireg_a2].lu);
					break;
				case 93: /* sys_exit */
					exit(proc->i_reg[riscv_ireg_a0].lu);
					break;
				default:
					panic("illegal syscall: %d", proc->i_reg[riscv_ireg_a7].lu);
			}
			proc->pc = next_pc;
			break;
		default:
			panic("illegal instruciton: %s", riscv_instruction_name[dec.op]);
	}
}

void run_rv64(riscv_ptr mem, riscv_lu vaddr, riscv_lu entry)
{
	riscv_decode dec;
	riscv_proc_state proc = { 0 };
	proc.p_type = riscv_proc_type_rv64i;
	proc.mem = mem;
	proc.vaddr = vaddr;
	proc.pc = mem + entry - vaddr;
	while (true) {
		riscv_execute_instruction(dec, &proc);
	}
}

int main(int argc, char *argv[])
{
	if (argc != 2) panic("usage: %s <elf_file>", argv[0]);
	elf_file elf(argv[1]);
	for (size_t i = 0; i < elf.phdrs.size(); i++) {
		Elf64_Phdr &phdr = elf.phdrs[i];
		if (phdr.p_flags & PT_LOAD) {
			run_rv64(elf.buf.data(), phdr.p_vaddr, elf.ehdr.e_entry);
			break;
		}
	}
	panic("could not execute");
	return 0;
}
<commit_msg>Add #include <functional> to test-emulate<commit_after>#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cstdarg>
#include <cerrno>
#include <vector>
#include <map>
#include <string>
#include <functional>

#include <unistd.h>

#include "riscv-types.h"
#include "riscv-endian.h"
#include "riscv-regs.h"
#include "riscv-processor.h"
#include "riscv-format.h"
#include "riscv-opcodes.h"
#include "riscv-util.h"
#include "riscv-imm.h"
#include "riscv-decode.h"
#include "riscv-decode-switch.h"
#include "riscv-csr.h"
#include "riscv-compression.h"
#include "riscv-elf.h"
#include "riscv-elf-file.h"
#include "riscv-elf-format.h"

void riscv_execute_instruction(riscv_decode &dec, riscv_proc_state *proc)
{
	riscv_ptr next_pc = riscv_decode_instruction(dec, proc);
	switch (dec.op) {
		case riscv_op_addi:
			proc->i_reg[dec.rd].lu = proc->i_reg[dec.rs1].lu + dec.imm;
			proc->pc = next_pc;
			break;
		case riscv_op_lui:
			proc->i_reg[dec.rd].lu = dec.imm;
			proc->pc = next_pc;
			break;
		case riscv_op_scall:
			switch (proc->i_reg[riscv_ireg_a7].lu) {
				case 64: /* sys_write */
					proc->i_reg[riscv_ireg_a0].lu = write(proc->i_reg[riscv_ireg_a0].lu,
						proc->mem + proc->i_reg[riscv_ireg_a1].lu - proc->vaddr, proc->i_reg[riscv_ireg_a2].lu);
					break;
				case 93: /* sys_exit */
					exit(proc->i_reg[riscv_ireg_a0].lu);
					break;
				default:
					panic("illegal syscall: %d", proc->i_reg[riscv_ireg_a7].lu);
			}
			proc->pc = next_pc;
			break;
		default:
			panic("illegal instruciton: %s", riscv_instruction_name[dec.op]);
	}
}

void run_rv64(riscv_ptr mem, riscv_lu vaddr, riscv_lu entry)
{
	riscv_decode dec;
	riscv_proc_state proc = { 0 };
	proc.p_type = riscv_proc_type_rv64i;
	proc.mem = mem;
	proc.vaddr = vaddr;
	proc.pc = mem + entry - vaddr;
	while (true) {
		riscv_execute_instruction(dec, &proc);
	}
}

int main(int argc, char *argv[])
{
	if (argc != 2) panic("usage: %s <elf_file>", argv[0]);
	elf_file elf(argv[1]);
	for (size_t i = 0; i < elf.phdrs.size(); i++) {
		Elf64_Phdr &phdr = elf.phdrs[i];
		if (phdr.p_flags & PT_LOAD) {
			run_rv64(elf.buf.data(), phdr.p_vaddr, elf.ehdr.e_entry);
			break;
		}
	}
	panic("could not execute");
	return 0;
}
<|endoftext|>


<commit_before>
#include "Globals.h"
#include "FireworksSerializer.h"
#include "WorldStorage/FastNBT.h"

void cFireworkItem::WriteToNBTCompound(const cFireworkItem & a_FireworkItem, cFastNBTWriter & a_Writer, const ENUM_ITEM_ID a_Type)
{
	switch (a_Type)
	{
		case E_ITEM_FIREWORK_ROCKET:
		{
			a_Writer.BeginCompound("Fireworks");
			a_Writer.AddByte("Flight", a_FireworkItem.m_FlightTimeInTicks / 20);
			a_Writer.BeginList("Explosions", TAG_Compound);
			a_Writer.BeginCompound("");
			a_Writer.AddByte("Flicker", a_FireworkItem.m_HasFlicker);
			a_Writer.AddByte("Trail", a_FireworkItem.m_HasTrail);
			a_Writer.AddByte("Type", a_FireworkItem.m_Type);
			if (!a_FireworkItem.m_Colours.empty())
			{
				a_Writer.AddIntArray("Colors", &(a_FireworkItem.m_Colours[0]), a_FireworkItem.m_Colours.size());
			}
			if (!a_FireworkItem.m_FadeColours.empty())
			{
				a_Writer.AddIntArray("FadeColors", &(a_FireworkItem.m_FadeColours[0]), a_FireworkItem.m_FadeColours.size());
			}
			a_Writer.EndCompound();
			a_Writer.EndList();
			a_Writer.EndCompound();
			break;
		}
		case E_ITEM_FIREWORK_STAR:
		{
			a_Writer.BeginCompound("Explosion");
			a_Writer.AddByte("Flicker", a_FireworkItem.m_HasFlicker);
			a_Writer.AddByte("Trail", a_FireworkItem.m_HasTrail);
			a_Writer.AddByte("Type", a_FireworkItem.m_Type);
			if (!a_FireworkItem.m_Colours.empty())
			{
				a_Writer.AddIntArray("Colors", &(a_FireworkItem.m_Colours[0]), a_FireworkItem.m_Colours.size());
			}
			if (!a_FireworkItem.m_FadeColours.empty())
			{
				a_Writer.AddIntArray("FadeColors", &(a_FireworkItem.m_FadeColours[0]), a_FireworkItem.m_FadeColours.size());
			}
			a_Writer.EndCompound();
			break;
		}
		default: ASSERT(!"Unhandled firework item!"); break;
	}
}

void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNBT & a_NBT, int a_TagIdx, const ENUM_ITEM_ID a_Type)
{
	if (a_TagIdx < 0)
	{
		return;
	}

	switch (a_Type)
	{
		case E_ITEM_FIREWORK_STAR:
		{
			for (int explosiontag = a_NBT.GetFirstChild(a_TagIdx); explosiontag >= 0; explosiontag = a_NBT.GetNextSibling(explosiontag))
			{
				eTagType TagType = a_NBT.GetType(explosiontag);
				if (TagType == TAG_Byte) // Custon name tag
				{
					AString ExplosionName = a_NBT.GetName(explosiontag);

					if (ExplosionName == "Flicker")
					{
						a_FireworkItem.m_HasFlicker = (a_NBT.GetByte(explosiontag) == 1);
					}
					else if (ExplosionName == "Trail")
					{
						a_FireworkItem.m_HasTrail = (a_NBT.GetByte(explosiontag) == 1);
					}
					else if (ExplosionName == "Type")
					{
						a_FireworkItem.m_Type = a_NBT.GetByte(explosiontag);
					}
				}
				else if (TagType == TAG_IntArray)
				{
					AString ExplosionName = a_NBT.GetName(explosiontag);

					if (ExplosionName == "Colors")
					{
						// Divide by four as data length returned in bytes
						size_t DataLength = a_NBT.GetDataLength(explosiontag);
						// round to the next highest multiple of four
						DataLength -= DataLength % 4;
						if (DataLength == 0)
						{
							continue;
						}

						const char * ColourData = (a_NBT.GetData(explosiontag));
						for (int i = 0; i < DataLength; i += 4 /* Size of network int*/)
						{
							a_FireworkItem.m_Colours.push_back(GetBEInt(ColourData + i));
						}
					}
					else if (ExplosionName == "FadeColors")
					{
						size_t DataLength = a_NBT.GetDataLength(explosiontag) / 4;
						// round to the next highest multiple of four
						DataLength -= DataLength % 4;
						if (DataLength == 0)
						{
							continue;
						}

						const char * FadeColourData = (a_NBT.GetData(explosiontag));
						for (int i = 0; i < DataLength; i += 4 /* Size of network int*/)
						{
							a_FireworkItem.m_FadeColours.push_back(GetBEInt(FadeColourData + i));
						}
					}
				}
			}
			break;
		}
		case E_ITEM_FIREWORK_ROCKET:
		{
			for (int fireworkstag = a_NBT.GetFirstChild(a_TagIdx); fireworkstag >= 0; fireworkstag = a_NBT.GetNextSibling(fireworkstag))
			{
				eTagType TagType = a_NBT.GetType(fireworkstag);
				if (TagType == TAG_Byte) // Custon name tag
				{
					if (a_NBT.GetName(fireworkstag) == "Flight")
					{
						a_FireworkItem.m_FlightTimeInTicks = a_NBT.GetByte(fireworkstag) * 20;
					}
				}
				else if ((TagType == TAG_List) && (a_NBT.GetName(fireworkstag) == "Explosions"))
				{
					int ExplosionsChild = a_NBT.GetFirstChild(fireworkstag);
					if ((a_NBT.GetType(ExplosionsChild) == TAG_Compound) && (a_NBT.GetName(ExplosionsChild).empty()))
					{
						ParseFromNBT(a_FireworkItem, a_NBT, ExplosionsChild, E_ITEM_FIREWORK_STAR);
					}
				}
			}
			break;
		}
		default: ASSERT(!"Unhandled firework item!"); break;
	}
}

AString cFireworkItem::ColoursToString(const cFireworkItem & a_FireworkItem)
{
	AString Result;

	for (std::vector<int>::const_iterator itr = a_FireworkItem.m_Colours.begin(); itr != a_FireworkItem.m_Colours.end(); ++itr)
	{
		AppendPrintf(Result, "%i;", *itr);
	}

	return Result;
}

void cFireworkItem::ColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem)
{
	AStringVector Split = StringSplit(a_String, ";");

	for (size_t itr = 0; itr < Split.size(); ++itr)
	{
		if (Split[itr].empty())
		{
			continue;
		}

		a_FireworkItem.m_Colours.push_back(atoi(Split[itr].c_str()));
	}
}

AString cFireworkItem::FadeColoursToString(const cFireworkItem & a_FireworkItem)
{
	AString Result;

	for (std::vector<int>::const_iterator itr = a_FireworkItem.m_FadeColours.begin(); itr != a_FireworkItem.m_FadeColours.end(); ++itr)
	{
		AppendPrintf(Result, "%i;", *itr);
	}

	return Result;
}

void cFireworkItem::FadeColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem)
{
	AStringVector Split = StringSplit(a_String, ";");

	for (size_t itr = 0; itr < Split.size(); ++itr)
	{
		if (Split[itr].empty())
		{
			continue;
		}

		a_FireworkItem.m_FadeColours.push_back(atoi(Split[itr].c_str()));
	}
}

int cFireworkItem::GetVanillaColourCodeFromDye(NIBBLETYPE a_DyeMeta)
{
	/*
	Colours are supposed to be calculated via: R << 16 + G << 8 + B
	However, the RGB values fireworks use aren't the same as the ones for dyes (the ones listed in the MC Wiki)
	Therefore, here is a list of numbers gotten via the Protocol Proxy
	*/

	switch (a_DyeMeta)
	{
		case E_META_DYE_BLACK: return 0x1E1B1B;
		case E_META_DYE_RED: return 0xB3312C;
		case E_META_DYE_GREEN: return 0x3B511A;
		case E_META_DYE_BROWN:  return 0x51301A;
		case E_META_DYE_BLUE: return 0x253192;
		case E_META_DYE_PURPLE: return 0x7B2FBE;
		case E_META_DYE_CYAN: return 0x287697;
		case E_META_DYE_LIGHTGRAY: return 0xABABAB;
		case E_META_DYE_GRAY: return 0x434343;
		case E_META_DYE_PINK: return 0xD88198;
		case E_META_DYE_LIGHTGREEN: return 0x41CD34;
		case E_META_DYE_YELLOW: return 0xDECF2A;
		case E_META_DYE_LIGHTBLUE: return 0x6689D3;
		case E_META_DYE_MAGENTA: return 0xC354CD;
		case E_META_DYE_ORANGE: return 0xEB8844;
		case E_META_DYE_WHITE: return 0xF0F0F0;
		default: ASSERT(!"Unhandled dye meta whilst trying to get colour code for fireworks!"); return 0;
	}
}
<commit_msg>Fixed size_t in FireworksSerializer.<commit_after>
#include "Globals.h"
#include "FireworksSerializer.h"
#include "WorldStorage/FastNBT.h"

void cFireworkItem::WriteToNBTCompound(const cFireworkItem & a_FireworkItem, cFastNBTWriter & a_Writer, const ENUM_ITEM_ID a_Type)
{
	switch (a_Type)
	{
		case E_ITEM_FIREWORK_ROCKET:
		{
			a_Writer.BeginCompound("Fireworks");
			a_Writer.AddByte("Flight", a_FireworkItem.m_FlightTimeInTicks / 20);
			a_Writer.BeginList("Explosions", TAG_Compound);
			a_Writer.BeginCompound("");
			a_Writer.AddByte("Flicker", a_FireworkItem.m_HasFlicker);
			a_Writer.AddByte("Trail", a_FireworkItem.m_HasTrail);
			a_Writer.AddByte("Type", a_FireworkItem.m_Type);
			if (!a_FireworkItem.m_Colours.empty())
			{
				a_Writer.AddIntArray("Colors", &(a_FireworkItem.m_Colours[0]), a_FireworkItem.m_Colours.size());
			}
			if (!a_FireworkItem.m_FadeColours.empty())
			{
				a_Writer.AddIntArray("FadeColors", &(a_FireworkItem.m_FadeColours[0]), a_FireworkItem.m_FadeColours.size());
			}
			a_Writer.EndCompound();
			a_Writer.EndList();
			a_Writer.EndCompound();
			break;
		}
		case E_ITEM_FIREWORK_STAR:
		{
			a_Writer.BeginCompound("Explosion");
			a_Writer.AddByte("Flicker", a_FireworkItem.m_HasFlicker);
			a_Writer.AddByte("Trail", a_FireworkItem.m_HasTrail);
			a_Writer.AddByte("Type", a_FireworkItem.m_Type);
			if (!a_FireworkItem.m_Colours.empty())
			{
				a_Writer.AddIntArray("Colors", &(a_FireworkItem.m_Colours[0]), a_FireworkItem.m_Colours.size());
			}
			if (!a_FireworkItem.m_FadeColours.empty())
			{
				a_Writer.AddIntArray("FadeColors", &(a_FireworkItem.m_FadeColours[0]), a_FireworkItem.m_FadeColours.size());
			}
			a_Writer.EndCompound();
			break;
		}
		default: ASSERT(!"Unhandled firework item!"); break;
	}
}

void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNBT & a_NBT, int a_TagIdx, const ENUM_ITEM_ID a_Type)
{
	if (a_TagIdx < 0)
	{
		return;
	}

	switch (a_Type)
	{
		case E_ITEM_FIREWORK_STAR:
		{
			for (int explosiontag = a_NBT.GetFirstChild(a_TagIdx); explosiontag >= 0; explosiontag = a_NBT.GetNextSibling(explosiontag))
			{
				eTagType TagType = a_NBT.GetType(explosiontag);
				if (TagType == TAG_Byte) // Custon name tag
				{
					AString ExplosionName = a_NBT.GetName(explosiontag);

					if (ExplosionName == "Flicker")
					{
						a_FireworkItem.m_HasFlicker = (a_NBT.GetByte(explosiontag) == 1);
					}
					else if (ExplosionName == "Trail")
					{
						a_FireworkItem.m_HasTrail = (a_NBT.GetByte(explosiontag) == 1);
					}
					else if (ExplosionName == "Type")
					{
						a_FireworkItem.m_Type = a_NBT.GetByte(explosiontag);
					}
				}
				else if (TagType == TAG_IntArray)
				{
					AString ExplosionName = a_NBT.GetName(explosiontag);

					if (ExplosionName == "Colors")
					{
						// Divide by four as data length returned in bytes
						size_t DataLength = a_NBT.GetDataLength(explosiontag);
						// round to the next highest multiple of four
						DataLength -= DataLength % 4;
						if (DataLength == 0)
						{
							continue;
						}

						const char * ColourData = (a_NBT.GetData(explosiontag));
						for (size_t i = 0; i < DataLength; i += 4)
						{
							a_FireworkItem.m_Colours.push_back(GetBEInt(ColourData + i));
						}
					}
					else if (ExplosionName == "FadeColors")
					{
						size_t DataLength = a_NBT.GetDataLength(explosiontag) / 4;
						// round to the next highest multiple of four
						DataLength -= DataLength % 4;
						if (DataLength == 0)
						{
							continue;
						}

						const char * FadeColourData = (a_NBT.GetData(explosiontag));
						for (size_t i = 0; i < DataLength; i += 4)
						{
							a_FireworkItem.m_FadeColours.push_back(GetBEInt(FadeColourData + i));
						}
					}
				}
			}
			break;
		}
		case E_ITEM_FIREWORK_ROCKET:
		{
			for (int fireworkstag = a_NBT.GetFirstChild(a_TagIdx); fireworkstag >= 0; fireworkstag = a_NBT.GetNextSibling(fireworkstag))
			{
				eTagType TagType = a_NBT.GetType(fireworkstag);
				if (TagType == TAG_Byte) // Custon name tag
				{
					if (a_NBT.GetName(fireworkstag) == "Flight")
					{
						a_FireworkItem.m_FlightTimeInTicks = a_NBT.GetByte(fireworkstag) * 20;
					}
				}
				else if ((TagType == TAG_List) && (a_NBT.GetName(fireworkstag) == "Explosions"))
				{
					int ExplosionsChild = a_NBT.GetFirstChild(fireworkstag);
					if ((a_NBT.GetType(ExplosionsChild) == TAG_Compound) && (a_NBT.GetName(ExplosionsChild).empty()))
					{
						ParseFromNBT(a_FireworkItem, a_NBT, ExplosionsChild, E_ITEM_FIREWORK_STAR);
					}
				}
			}
			break;
		}
		default: ASSERT(!"Unhandled firework item!"); break;
	}
}

AString cFireworkItem::ColoursToString(const cFireworkItem & a_FireworkItem)
{
	AString Result;

	for (std::vector<int>::const_iterator itr = a_FireworkItem.m_Colours.begin(); itr != a_FireworkItem.m_Colours.end(); ++itr)
	{
		AppendPrintf(Result, "%i;", *itr);
	}

	return Result;
}

void cFireworkItem::ColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem)
{
	AStringVector Split = StringSplit(a_String, ";");

	for (size_t itr = 0; itr < Split.size(); ++itr)
	{
		if (Split[itr].empty())
		{
			continue;
		}

		a_FireworkItem.m_Colours.push_back(atoi(Split[itr].c_str()));
	}
}

AString cFireworkItem::FadeColoursToString(const cFireworkItem & a_FireworkItem)
{
	AString Result;

	for (std::vector<int>::const_iterator itr = a_FireworkItem.m_FadeColours.begin(); itr != a_FireworkItem.m_FadeColours.end(); ++itr)
	{
		AppendPrintf(Result, "%i;", *itr);
	}

	return Result;
}

void cFireworkItem::FadeColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem)
{
	AStringVector Split = StringSplit(a_String, ";");

	for (size_t itr = 0; itr < Split.size(); ++itr)
	{
		if (Split[itr].empty())
		{
			continue;
		}

		a_FireworkItem.m_FadeColours.push_back(atoi(Split[itr].c_str()));
	}
}

int cFireworkItem::GetVanillaColourCodeFromDye(NIBBLETYPE a_DyeMeta)
{
	/*
	Colours are supposed to be calculated via: R << 16 + G << 8 + B
	However, the RGB values fireworks use aren't the same as the ones for dyes (the ones listed in the MC Wiki)
	Therefore, here is a list of numbers gotten via the Protocol Proxy
	*/

	switch (a_DyeMeta)
	{
		case E_META_DYE_BLACK: return 0x1E1B1B;
		case E_META_DYE_RED: return 0xB3312C;
		case E_META_DYE_GREEN: return 0x3B511A;
		case E_META_DYE_BROWN:  return 0x51301A;
		case E_META_DYE_BLUE: return 0x253192;
		case E_META_DYE_PURPLE: return 0x7B2FBE;
		case E_META_DYE_CYAN: return 0x287697;
		case E_META_DYE_LIGHTGRAY: return 0xABABAB;
		case E_META_DYE_GRAY: return 0x434343;
		case E_META_DYE_PINK: return 0xD88198;
		case E_META_DYE_LIGHTGREEN: return 0x41CD34;
		case E_META_DYE_YELLOW: return 0xDECF2A;
		case E_META_DYE_LIGHTBLUE: return 0x6689D3;
		case E_META_DYE_MAGENTA: return 0xC354CD;
		case E_META_DYE_ORANGE: return 0xEB8844;
		case E_META_DYE_WHITE: return 0xF0F0F0;
		default: ASSERT(!"Unhandled dye meta whilst trying to get colour code for fireworks!"); return 0;
	}
}
<|endoftext|>