<commit_before>// Copyright (c) 2015 The Chromium 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 "net/third_party/quiche/src/quic/tools/quic_client_base.h"

#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h"
#include "net/third_party/quiche/src/quic/core/quic_server_id.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"

namespace quic {

QuicClientBase::NetworkHelper::~NetworkHelper() = default;

QuicClientBase::QuicClientBase(
    const QuicServerId& server_id,
    const ParsedQuicVersionVector& supported_versions,
    const QuicConfig& config,
    QuicConnectionHelperInterface* helper,
    QuicAlarmFactory* alarm_factory,
    std::unique_ptr<NetworkHelper> network_helper,
    std::unique_ptr<ProofVerifier> proof_verifier,
    std::unique_ptr<SessionCache> session_cache)
    : server_id_(server_id),
      initialized_(false),
      local_port_(0),
      config_(config),
      crypto_config_(std::move(proof_verifier), std::move(session_cache)),
      helper_(helper),
      alarm_factory_(alarm_factory),
      supported_versions_(supported_versions),
      initial_max_packet_length_(0),
      num_sent_client_hellos_(0),
      connection_error_(QUIC_NO_ERROR),
      connected_or_attempting_connect_(false),
      network_helper_(std::move(network_helper)),
      connection_debug_visitor_(nullptr),
      server_connection_id_length_(kQuicDefaultConnectionIdLength),
      client_connection_id_length_(0) {}

QuicClientBase::~QuicClientBase() = default;

bool QuicClientBase::Initialize() {
  num_sent_client_hellos_ = 0;
  connection_error_ = QUIC_NO_ERROR;
  connected_or_attempting_connect_ = false;

  // If an initial flow control window has not explicitly been set, then use the
  // same values that Chrome uses.
  const uint32_t kSessionMaxRecvWindowSize = 15 * 1024 * 1024;  // 15 MB
  const uint32_t kStreamMaxRecvWindowSize = 6 * 1024 * 1024;    //  6 MB
  if (config()->GetInitialStreamFlowControlWindowToSend() ==
      kDefaultFlowControlSendWindow) {
    config()->SetInitialStreamFlowControlWindowToSend(kStreamMaxRecvWindowSize);
  }
  if (config()->GetInitialSessionFlowControlWindowToSend() ==
      kDefaultFlowControlSendWindow) {
    config()->SetInitialSessionFlowControlWindowToSend(
        kSessionMaxRecvWindowSize);
  }

  if (!network_helper_->CreateUDPSocketAndBind(server_address_,
                                               bind_to_address_, local_port_)) {
    return false;
  }

  initialized_ = true;
  return true;
}

bool QuicClientBase::Connect() {
  // Attempt multiple connects until the maximum number of client hellos have
  // been sent.
  int num_attempts = 0;
  while (!connected() &&
         num_attempts <= QuicCryptoClientStream::kMaxClientHellos) {
    StartConnect();
    while (EncryptionBeingEstablished()) {
      WaitForEvents();
    }
    ParsedQuicVersion version = UnsupportedQuicVersion();
    if (session() != nullptr && !CanReconnectWithDifferentVersion(&version)) {
      // We've successfully created a session but we're not connected, and we
      // cannot reconnect with a different version.  Give up trying.
      break;
    }
    num_attempts++;
  }
  if (session() == nullptr) {
    QUIC_BUG << "Missing session after Connect";
    return false;
  }
  return session()->connection()->connected();
}

void QuicClientBase::StartConnect() {
  DCHECK(initialized_);
  DCHECK(!connected());
  QuicPacketWriter* writer = network_helper_->CreateQuicPacketWriter();
  ParsedQuicVersion mutual_version = UnsupportedQuicVersion();
  const bool can_reconnect_with_different_version =
      CanReconnectWithDifferentVersion(&mutual_version);
  if (connected_or_attempting_connect()) {
    // Clear queued up data if client can not try to connect with a different
    // version.
    if (!can_reconnect_with_different_version) {
      ClearDataToResend();
    }
    // Before we destroy the last session and create a new one, gather its stats
    // and update the stats for the overall connection.
    UpdateStats();
  }

  session_ = CreateQuicClientSession(
      supported_versions(),
      new QuicConnection(GetNextConnectionId(), server_address(), helper(),
                         alarm_factory(), writer,
                         /* owns_writer= */ false, Perspective::IS_CLIENT,
                         can_reconnect_with_different_version
                             ? ParsedQuicVersionVector{mutual_version}
                             : supported_versions()));
  if (connection_debug_visitor_ != nullptr) {
    session()->connection()->set_debug_visitor(connection_debug_visitor_);
  }
  session()->connection()->set_client_connection_id(GetClientConnectionId());
  if (initial_max_packet_length_ != 0) {
    session()->connection()->SetMaxPacketLength(initial_max_packet_length_);
  }
  // Reset |writer()| after |session()| so that the old writer outlives the old
  // session.
  set_writer(writer);
  InitializeSession();
  if (can_reconnect_with_different_version) {
    // This is a reconnect using server supported |mutual_version|.
    session()->connection()->SetVersionNegotiated();
  }
  set_connected_or_attempting_connect(true);
}

void QuicClientBase::InitializeSession() {
  session()->Initialize();
}

void QuicClientBase::Disconnect() {
  DCHECK(initialized_);

  initialized_ = false;
  if (connected()) {
    session()->connection()->CloseConnection(
        QUIC_PEER_GOING_AWAY, "Client disconnecting",
        ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
  }

  ClearDataToResend();

  network_helper_->CleanUpAllUDPSockets();
}

ProofVerifier* QuicClientBase::proof_verifier() const {
  return crypto_config_.proof_verifier();
}

bool QuicClientBase::EncryptionBeingEstablished() {
  return !session_->IsEncryptionEstablished() &&
         session_->connection()->connected();
}

bool QuicClientBase::WaitForEvents() {
  if (!connected()) {
    QUIC_BUG << "Cannot call WaitForEvents on non-connected client";
    return false;
  }

  network_helper_->RunEventLoop();

  DCHECK(session() != nullptr);
  ParsedQuicVersion version = UnsupportedQuicVersion();
  if (!connected() && CanReconnectWithDifferentVersion(&version)) {
    QUIC_DLOG(INFO) << "Can reconnect with version: " << version
                    << ", attempting to reconnect.";

    Connect();
  }

  return HasActiveRequests();
}

bool QuicClientBase::MigrateSocket(const QuicIpAddress& new_host) {
  return MigrateSocketWithSpecifiedPort(new_host, local_port_);
}

bool QuicClientBase::MigrateSocketWithSpecifiedPort(
    const QuicIpAddress& new_host,
    int port) {
  if (!connected()) {
    return false;
  }

  network_helper_->CleanUpAllUDPSockets();

  set_bind_to_address(new_host);
  if (!network_helper_->CreateUDPSocketAndBind(server_address_,
                                               bind_to_address_, port)) {
    return false;
  }

  session()->connection()->SetSelfAddress(
      network_helper_->GetLatestClientAddress());

  QuicPacketWriter* writer = network_helper_->CreateQuicPacketWriter();
  set_writer(writer);
  session()->connection()->SetQuicPacketWriter(writer, false);

  return true;
}

bool QuicClientBase::ChangeEphemeralPort() {
  auto current_host = network_helper_->GetLatestClientAddress().host();
  return MigrateSocketWithSpecifiedPort(current_host, 0 /*any ephemeral port*/);
}

QuicSession* QuicClientBase::session() {
  return session_.get();
}

const QuicSession* QuicClientBase::session() const {
  return session_.get();
}

QuicClientBase::NetworkHelper* QuicClientBase::network_helper() {
  return network_helper_.get();
}

const QuicClientBase::NetworkHelper* QuicClientBase::network_helper() const {
  return network_helper_.get();
}

void QuicClientBase::WaitForStreamToClose(QuicStreamId id) {
  if (!connected()) {
    QUIC_BUG << "Cannot WaitForStreamToClose on non-connected client";
    return;
  }

  while (connected() && !session_->IsClosedStream(id)) {
    WaitForEvents();
  }
}

bool QuicClientBase::WaitForOneRttKeysAvailable() {
  if (!connected()) {
    QUIC_BUG << "Cannot WaitForOneRttKeysAvailable on non-connected client";
    return false;
  }

  while (connected() && !session_->OneRttKeysAvailable()) {
    WaitForEvents();
  }

  // If the handshake fails due to a timeout, the connection will be closed.
  QUIC_LOG_IF(ERROR, !connected()) << "Handshake with server failed.";
  return connected();
}

bool QuicClientBase::WaitForHandshakeConfirmed() {
  if (!session_->connection()->version().HasHandshakeDone()) {
    return WaitForOneRttKeysAvailable();
  }
  while (connected() && session_->GetHandshakeState() < HANDSHAKE_CONFIRMED) {
    WaitForEvents();
  }

  // If the handshake fails due to a timeout, the connection will be closed.
  QUIC_LOG_IF(ERROR, !connected()) << "Handshake with server failed.";
  return connected();
}

bool QuicClientBase::connected() const {
  return session_.get() && session_->connection() &&
         session_->connection()->connected();
}

bool QuicClientBase::goaway_received() const {
  return session_ != nullptr && session_->goaway_received();
}

int QuicClientBase::GetNumSentClientHellos() {
  // If we are not actively attempting to connect, the session object
  // corresponds to the previous connection and should not be used.
  const int current_session_hellos = !connected_or_attempting_connect_
                                         ? 0
                                         : GetNumSentClientHellosFromSession();
  return num_sent_client_hellos_ + current_session_hellos;
}

void QuicClientBase::UpdateStats() {
  num_sent_client_hellos_ += GetNumSentClientHellosFromSession();
}

int QuicClientBase::GetNumReceivedServerConfigUpdates() {
  // If we are not actively attempting to connect, the session object
  // corresponds to the previous connection and should not be used.
  return !connected_or_attempting_connect_
             ? 0
             : GetNumReceivedServerConfigUpdatesFromSession();
}

QuicErrorCode QuicClientBase::connection_error() const {
  // Return the high-level error if there was one.  Otherwise, return the
  // connection error from the last session.
  if (connection_error_ != QUIC_NO_ERROR) {
    return connection_error_;
  }
  if (session_ == nullptr) {
    return QUIC_NO_ERROR;
  }
  return session_->error();
}

QuicConnectionId QuicClientBase::GetNextConnectionId() {
  return GenerateNewConnectionId();
}

QuicConnectionId QuicClientBase::GenerateNewConnectionId() {
  return QuicUtils::CreateRandomConnectionId(server_connection_id_length_);
}

QuicConnectionId QuicClientBase::GetClientConnectionId() {
  return QuicUtils::CreateRandomConnectionId(client_connection_id_length_);
}

bool QuicClientBase::CanReconnectWithDifferentVersion(
    ParsedQuicVersion* version) const {
  if (session_ == nullptr || session_->connection() == nullptr ||
      session_->error() != QUIC_INVALID_VERSION ||
      session_->connection()->server_supported_versions().empty()) {
    return false;
  }
  for (const auto& client_version : supported_versions_) {
    if (QuicContainsValue(session_->connection()->server_supported_versions(),
                          client_version)) {
      *version = client_version;
      return true;
    }
  }
  return false;
}

}  // namespace quic
<commit_msg>Fix client supported versions when quic_client reconnects. Client code only, not protected.<commit_after>// Copyright (c) 2015 The Chromium 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 "net/third_party/quiche/src/quic/tools/quic_client_base.h"

#include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h"
#include "net/third_party/quiche/src/quic/core/quic_server_id.h"
#include "net/third_party/quiche/src/quic/core/quic_utils.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"

namespace quic {

QuicClientBase::NetworkHelper::~NetworkHelper() = default;

QuicClientBase::QuicClientBase(
    const QuicServerId& server_id,
    const ParsedQuicVersionVector& supported_versions,
    const QuicConfig& config,
    QuicConnectionHelperInterface* helper,
    QuicAlarmFactory* alarm_factory,
    std::unique_ptr<NetworkHelper> network_helper,
    std::unique_ptr<ProofVerifier> proof_verifier,
    std::unique_ptr<SessionCache> session_cache)
    : server_id_(server_id),
      initialized_(false),
      local_port_(0),
      config_(config),
      crypto_config_(std::move(proof_verifier), std::move(session_cache)),
      helper_(helper),
      alarm_factory_(alarm_factory),
      supported_versions_(supported_versions),
      initial_max_packet_length_(0),
      num_sent_client_hellos_(0),
      connection_error_(QUIC_NO_ERROR),
      connected_or_attempting_connect_(false),
      network_helper_(std::move(network_helper)),
      connection_debug_visitor_(nullptr),
      server_connection_id_length_(kQuicDefaultConnectionIdLength),
      client_connection_id_length_(0) {}

QuicClientBase::~QuicClientBase() = default;

bool QuicClientBase::Initialize() {
  num_sent_client_hellos_ = 0;
  connection_error_ = QUIC_NO_ERROR;
  connected_or_attempting_connect_ = false;

  // If an initial flow control window has not explicitly been set, then use the
  // same values that Chrome uses.
  const uint32_t kSessionMaxRecvWindowSize = 15 * 1024 * 1024;  // 15 MB
  const uint32_t kStreamMaxRecvWindowSize = 6 * 1024 * 1024;    //  6 MB
  if (config()->GetInitialStreamFlowControlWindowToSend() ==
      kDefaultFlowControlSendWindow) {
    config()->SetInitialStreamFlowControlWindowToSend(kStreamMaxRecvWindowSize);
  }
  if (config()->GetInitialSessionFlowControlWindowToSend() ==
      kDefaultFlowControlSendWindow) {
    config()->SetInitialSessionFlowControlWindowToSend(
        kSessionMaxRecvWindowSize);
  }

  if (!network_helper_->CreateUDPSocketAndBind(server_address_,
                                               bind_to_address_, local_port_)) {
    return false;
  }

  initialized_ = true;
  return true;
}

bool QuicClientBase::Connect() {
  // Attempt multiple connects until the maximum number of client hellos have
  // been sent.
  int num_attempts = 0;
  while (!connected() &&
         num_attempts <= QuicCryptoClientStream::kMaxClientHellos) {
    StartConnect();
    while (EncryptionBeingEstablished()) {
      WaitForEvents();
    }
    ParsedQuicVersion version = UnsupportedQuicVersion();
    if (session() != nullptr && !CanReconnectWithDifferentVersion(&version)) {
      // We've successfully created a session but we're not connected, and we
      // cannot reconnect with a different version.  Give up trying.
      break;
    }
    num_attempts++;
  }
  if (session() == nullptr) {
    QUIC_BUG << "Missing session after Connect";
    return false;
  }
  return session()->connection()->connected();
}

void QuicClientBase::StartConnect() {
  DCHECK(initialized_);
  DCHECK(!connected());
  QuicPacketWriter* writer = network_helper_->CreateQuicPacketWriter();
  ParsedQuicVersion mutual_version = UnsupportedQuicVersion();
  const bool can_reconnect_with_different_version =
      CanReconnectWithDifferentVersion(&mutual_version);
  if (connected_or_attempting_connect()) {
    // Clear queued up data if client can not try to connect with a different
    // version.
    if (!can_reconnect_with_different_version) {
      ClearDataToResend();
    }
    // Before we destroy the last session and create a new one, gather its stats
    // and update the stats for the overall connection.
    UpdateStats();
  }

  const quic::ParsedQuicVersionVector client_supported_versions =
      can_reconnect_with_different_version
          ? ParsedQuicVersionVector{mutual_version}
          : supported_versions();

  session_ = CreateQuicClientSession(
      client_supported_versions,
      new QuicConnection(GetNextConnectionId(), server_address(), helper(),
                         alarm_factory(), writer,
                         /* owns_writer= */ false, Perspective::IS_CLIENT,
                         client_supported_versions));
  if (connection_debug_visitor_ != nullptr) {
    session()->connection()->set_debug_visitor(connection_debug_visitor_);
  }
  session()->connection()->set_client_connection_id(GetClientConnectionId());
  if (initial_max_packet_length_ != 0) {
    session()->connection()->SetMaxPacketLength(initial_max_packet_length_);
  }
  // Reset |writer()| after |session()| so that the old writer outlives the old
  // session.
  set_writer(writer);
  InitializeSession();
  if (can_reconnect_with_different_version) {
    // This is a reconnect using server supported |mutual_version|.
    session()->connection()->SetVersionNegotiated();
  }
  set_connected_or_attempting_connect(true);
}

void QuicClientBase::InitializeSession() {
  session()->Initialize();
}

void QuicClientBase::Disconnect() {
  DCHECK(initialized_);

  initialized_ = false;
  if (connected()) {
    session()->connection()->CloseConnection(
        QUIC_PEER_GOING_AWAY, "Client disconnecting",
        ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
  }

  ClearDataToResend();

  network_helper_->CleanUpAllUDPSockets();
}

ProofVerifier* QuicClientBase::proof_verifier() const {
  return crypto_config_.proof_verifier();
}

bool QuicClientBase::EncryptionBeingEstablished() {
  return !session_->IsEncryptionEstablished() &&
         session_->connection()->connected();
}

bool QuicClientBase::WaitForEvents() {
  if (!connected()) {
    QUIC_BUG << "Cannot call WaitForEvents on non-connected client";
    return false;
  }

  network_helper_->RunEventLoop();

  DCHECK(session() != nullptr);
  ParsedQuicVersion version = UnsupportedQuicVersion();
  if (!connected() && CanReconnectWithDifferentVersion(&version)) {
    QUIC_DLOG(INFO) << "Can reconnect with version: " << version
                    << ", attempting to reconnect.";

    Connect();
  }

  return HasActiveRequests();
}

bool QuicClientBase::MigrateSocket(const QuicIpAddress& new_host) {
  return MigrateSocketWithSpecifiedPort(new_host, local_port_);
}

bool QuicClientBase::MigrateSocketWithSpecifiedPort(
    const QuicIpAddress& new_host,
    int port) {
  if (!connected()) {
    return false;
  }

  network_helper_->CleanUpAllUDPSockets();

  set_bind_to_address(new_host);
  if (!network_helper_->CreateUDPSocketAndBind(server_address_,
                                               bind_to_address_, port)) {
    return false;
  }

  session()->connection()->SetSelfAddress(
      network_helper_->GetLatestClientAddress());

  QuicPacketWriter* writer = network_helper_->CreateQuicPacketWriter();
  set_writer(writer);
  session()->connection()->SetQuicPacketWriter(writer, false);

  return true;
}

bool QuicClientBase::ChangeEphemeralPort() {
  auto current_host = network_helper_->GetLatestClientAddress().host();
  return MigrateSocketWithSpecifiedPort(current_host, 0 /*any ephemeral port*/);
}

QuicSession* QuicClientBase::session() {
  return session_.get();
}

const QuicSession* QuicClientBase::session() const {
  return session_.get();
}

QuicClientBase::NetworkHelper* QuicClientBase::network_helper() {
  return network_helper_.get();
}

const QuicClientBase::NetworkHelper* QuicClientBase::network_helper() const {
  return network_helper_.get();
}

void QuicClientBase::WaitForStreamToClose(QuicStreamId id) {
  if (!connected()) {
    QUIC_BUG << "Cannot WaitForStreamToClose on non-connected client";
    return;
  }

  while (connected() && !session_->IsClosedStream(id)) {
    WaitForEvents();
  }
}

bool QuicClientBase::WaitForOneRttKeysAvailable() {
  if (!connected()) {
    QUIC_BUG << "Cannot WaitForOneRttKeysAvailable on non-connected client";
    return false;
  }

  while (connected() && !session_->OneRttKeysAvailable()) {
    WaitForEvents();
  }

  // If the handshake fails due to a timeout, the connection will be closed.
  QUIC_LOG_IF(ERROR, !connected()) << "Handshake with server failed.";
  return connected();
}

bool QuicClientBase::WaitForHandshakeConfirmed() {
  if (!session_->connection()->version().HasHandshakeDone()) {
    return WaitForOneRttKeysAvailable();
  }
  while (connected() && session_->GetHandshakeState() < HANDSHAKE_CONFIRMED) {
    WaitForEvents();
  }

  // If the handshake fails due to a timeout, the connection will be closed.
  QUIC_LOG_IF(ERROR, !connected()) << "Handshake with server failed.";
  return connected();
}

bool QuicClientBase::connected() const {
  return session_.get() && session_->connection() &&
         session_->connection()->connected();
}

bool QuicClientBase::goaway_received() const {
  return session_ != nullptr && session_->goaway_received();
}

int QuicClientBase::GetNumSentClientHellos() {
  // If we are not actively attempting to connect, the session object
  // corresponds to the previous connection and should not be used.
  const int current_session_hellos = !connected_or_attempting_connect_
                                         ? 0
                                         : GetNumSentClientHellosFromSession();
  return num_sent_client_hellos_ + current_session_hellos;
}

void QuicClientBase::UpdateStats() {
  num_sent_client_hellos_ += GetNumSentClientHellosFromSession();
}

int QuicClientBase::GetNumReceivedServerConfigUpdates() {
  // If we are not actively attempting to connect, the session object
  // corresponds to the previous connection and should not be used.
  return !connected_or_attempting_connect_
             ? 0
             : GetNumReceivedServerConfigUpdatesFromSession();
}

QuicErrorCode QuicClientBase::connection_error() const {
  // Return the high-level error if there was one.  Otherwise, return the
  // connection error from the last session.
  if (connection_error_ != QUIC_NO_ERROR) {
    return connection_error_;
  }
  if (session_ == nullptr) {
    return QUIC_NO_ERROR;
  }
  return session_->error();
}

QuicConnectionId QuicClientBase::GetNextConnectionId() {
  return GenerateNewConnectionId();
}

QuicConnectionId QuicClientBase::GenerateNewConnectionId() {
  return QuicUtils::CreateRandomConnectionId(server_connection_id_length_);
}

QuicConnectionId QuicClientBase::GetClientConnectionId() {
  return QuicUtils::CreateRandomConnectionId(client_connection_id_length_);
}

bool QuicClientBase::CanReconnectWithDifferentVersion(
    ParsedQuicVersion* version) const {
  if (session_ == nullptr || session_->connection() == nullptr ||
      session_->error() != QUIC_INVALID_VERSION ||
      session_->connection()->server_supported_versions().empty()) {
    return false;
  }
  for (const auto& client_version : supported_versions_) {
    if (QuicContainsValue(session_->connection()->server_supported_versions(),
                          client_version)) {
      *version = client_version;
      return true;
    }
  }
  return false;
}

}  // namespace quic
<|endoftext|>


<commit_before>// Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// 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.

#include <rcl/error_handling.h>
#include <rcl/event.h>
#include <rcl/types.h>
#include <rcpputils/scope_exit.hpp>
#include <rmw/incompatible_qos_events_statuses.h>

#include <memory>
#include <utility>

#include "rclpy_common/common.h"
#include "rclpy_common/handle.h"
#include "rclpy_common/exceptions.hpp"

#include "qos_events.hpp"

namespace rclpy
{

namespace
{

#define PYMODULE_NAME "rclpy.qos_event"

typedef union qos_event_callback_data {
  // Subscription events
  rmw_requested_deadline_missed_status_t requested_deadline_missed;
  rmw_liveliness_changed_status_t liveliness_changed;
  rmw_message_lost_status_t message_lost;
  rmw_requested_qos_incompatible_event_status_t requested_incompatible_qos;
  // Publisher events
  rmw_offered_deadline_missed_status_t offered_deadline_missed;
  rmw_liveliness_lost_status_t liveliness_lost;
  rmw_offered_qos_incompatible_event_status_t offered_incompatible_qos;
} qos_event_callback_data_t;

typedef py::object qos_event_data_filler_function (const qos_event_callback_data_t *);

template<typename T>
using unique_cstruct_ptr = std::unique_ptr<T, void (*)(T *)>;

unique_cstruct_ptr<rcl_event_t>
create_zero_initialized_event()
{
  unique_cstruct_ptr<rcl_event_t> event(
    static_cast<rcl_event_t *>(PyMem_Malloc(sizeof(rcl_event_t))),
    [](rcl_event_t * event) {
      if (!event) {
        PyErr_Clear();
        int stack_level = 1;
        PyErr_WarnFormat(
          PyExc_RuntimeWarning, stack_level,
          "no rcl_event_t to delete");
      }
      rcl_ret_t ret = rcl_event_fini(event);
      if (RCL_RET_OK != ret) {
        int stack_level = 1;
        PyErr_WarnFormat(
          PyExc_RuntimeWarning, stack_level,
          "failed to fini event: %s",
          rcl_get_error_string().str);
        rcl_reset_error();
      }
      PyMem_Free(event);
    });
  if (!event) {
    throw std::bad_alloc();
  }
  *event = rcl_get_zero_initialized_event();
  return event;
}

py::object
_requested_deadline_missed_to_py_object(const qos_event_callback_data_t * data)
{
  py::module qos_events = py::module::import(PYMODULE_NAME);
  py::object pyclass = qos_events.attr("QoSRequestedDeadlineMissedInfo");
  return pyclass(
    data->requested_deadline_missed.total_count,
    data->requested_deadline_missed.total_count_change);
}

py::object
_liveliness_changed_to_py_object(const qos_event_callback_data_t * data)
{
  py::module qos_events = py::module::import(PYMODULE_NAME);
  py::object pyclass = qos_events.attr("QoSLivelinessChangedInfo");
  return pyclass(
    data->liveliness_changed.alive_count,
    data->liveliness_changed.not_alive_count,
    data->liveliness_changed.alive_count_change,
    data->liveliness_changed.not_alive_count_change);
}

py::object
_message_lost_to_py_object(const qos_event_callback_data_t * data)
{
  py::module qos_events = py::module::import(PYMODULE_NAME);
  py::object pyclass = qos_events.attr("QoSMessageLostInfo");
  return pyclass(
    data->message_lost.total_count,
    data->message_lost.total_count_change);
}

py::object
_requested_incompatible_qos_to_py_object(const qos_event_callback_data_t * data)
{
  py::module qos_events = py::module::import(PYMODULE_NAME);
  py::object pyclass = qos_events.attr("QoSRequestedIncompatibleQoSInfo");
  return pyclass(
    data->requested_incompatible_qos.total_count,
    data->requested_incompatible_qos.total_count_change,
    // enum does not specify underlying data type, need intermediate cast
    static_cast<int>(data->requested_incompatible_qos.last_policy_kind));
}

py::object
_offered_deadline_missed_to_py_object(const qos_event_callback_data_t * data)
{
  py::module qos_events = py::module::import(PYMODULE_NAME);
  py::object pyclass = qos_events.attr("QoSOfferedDeadlineMissedInfo");
  return pyclass(
    data->offered_deadline_missed.total_count,
    data->offered_deadline_missed.total_count_change);
}

py::object
_liveliness_lost_to_py_object(const qos_event_callback_data_t * data)
{
  py::module qos_events = py::module::import(PYMODULE_NAME);
  py::object pyclass = qos_events.attr("QoSLivelinessLostInfo");
  return pyclass(
    data->liveliness_lost.total_count,
    data->liveliness_lost.total_count_change);
}

py::object
_offered_incompatible_qos_to_py_object(const qos_event_callback_data_t * data)
{
  py::module qos_events = py::module::import(PYMODULE_NAME);
  py::object pyclass = qos_events.attr("QoSOfferedIncompatibleQoSInfo");
  return pyclass(
    data->offered_incompatible_qos.total_count,
    data->offered_incompatible_qos.total_count_change,
    // enum does not specify underlying data type, need intermediate cast
    static_cast<int>(data->offered_incompatible_qos.last_policy_kind));
}

qos_event_data_filler_function *
qos_event_data_filler_function_for(py::capsule pyparent, py::object pyevent_type)
{
  if (strcmp(pyparent.name(), "rclpy_subscription_t") == 0) {
    switch (pyevent_type.cast<rcl_subscription_event_type_t>()) {
      case RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED:
        return &_requested_deadline_missed_to_py_object;
      case RCL_SUBSCRIPTION_LIVELINESS_CHANGED:
        return &_liveliness_changed_to_py_object;
      case RCL_SUBSCRIPTION_MESSAGE_LOST:
        return &_message_lost_to_py_object;
      case RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS:
        return &_requested_incompatible_qos_to_py_object;
      default:
        throw py::value_error("event type for subscriptions not understood");
        // although this suggests a misalignment between C and Python interfaces
    }
  }
  if (strcmp(pyparent.name(), "rclpy_publisher_t") == 0) {
    switch (pyevent_type.cast<rcl_publisher_event_type_t>()) {
      case RCL_PUBLISHER_OFFERED_DEADLINE_MISSED:
        return &_offered_deadline_missed_to_py_object;
      case RCL_PUBLISHER_LIVELINESS_LOST:
        return &_liveliness_lost_to_py_object;
      case RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS:
        return &_offered_incompatible_qos_to_py_object;
      default:
        throw py::value_error("event type for publishers not understood");
        // although this suggests a misalignment between C and Python interfaces
    }
  }
  throw py::type_error("event parent is neither a publisher nor a subscription");
}

py::capsule
event_wrap_in_capsule(unique_cstruct_ptr<rcl_event_t> event, py::capsule pyparent)
{
  rclpy_handle_destructor_t destructor =
    reinterpret_cast<rclpy_handle_destructor_t>(event.get_deleter());
  PyObject * pyevent_c =
    rclpy_create_handle_capsule(event.get(), "rcl_event_t", destructor);
  if (!pyevent_c) {
    throw py::error_already_set();
  }
  auto pyevent = py::reinterpret_steal<py::capsule>(pyevent_c);
  event.release();  // pyevent now owns rcl_event_t

  rclpy_handle_t * event_handle = static_cast<rclpy_handle_t *>(pyevent);
  rclpy_handle_t * parent_handle = static_cast<rclpy_handle_t *>(pyparent);
  _rclpy_handle_add_dependency(event_handle, parent_handle);
  if (PyErr_Occurred()) {
    throw py::error_already_set();
  }
  return pyevent;
}

py::object
publisher_event_create(rcl_publisher_event_type_t event_type, py::capsule pypublisher)
{
  auto wrapper = static_cast<rclpy_publisher_t *>(
    rclpy_handle_get_pointer_from_capsule(pypublisher.ptr(), "rclpy_publisher_t"));
  if (!wrapper) {
    throw py::error_already_set();
  }

  unique_cstruct_ptr<rcl_event_t> event = create_zero_initialized_event();

  rcl_ret_t ret = rcl_publisher_event_init(
    event.get(), &(wrapper->publisher), event_type);
  if (RCL_RET_OK != ret) {
    if (RCL_RET_BAD_ALLOC == ret) {
      rcl_reset_error();
      throw std::bad_alloc();
    }
    if (RCL_RET_UNSUPPORTED == ret) {
      throw UnsupportedEventTypeError("publisher event is unsupported");
    }
    throw RCLError("failed to create publisher event");
  }

  return event_wrap_in_capsule(std::move(event), pypublisher);
}

py::object
subscription_event_create(rcl_subscription_event_type_t event_type, py::capsule pysubscription)
{
  auto wrapper = static_cast<rclpy_subscription_t *>(
    rclpy_handle_get_pointer_from_capsule(pysubscription.ptr(), "rclpy_subscription_t"));
  if (!wrapper) {
    throw py::error_already_set();
  }

  unique_cstruct_ptr<rcl_event_t> event = create_zero_initialized_event();

  rcl_ret_t ret = rcl_subscription_event_init(
    event.get(), &(wrapper->subscription), event_type);
  if (RCL_RET_OK != ret) {
    if (RCL_RET_BAD_ALLOC == ret) {
      rcl_reset_error();
      throw std::bad_alloc();
    }
    if (RCL_RET_UNSUPPORTED == ret) {
      throw UnsupportedEventTypeError("subscription event is unsupported");
    }
    throw RCLError("failed to create subscription event");
  }

  return event_wrap_in_capsule(std::move(event), pysubscription);
}

}  // namespace

py::object
create_event(py::object pyevent_type, py::capsule pyparent)
{
  if (strcmp(pyparent.name(), "rclpy_subscription_t") == 0) {
    auto event_type = pyevent_type.cast<rcl_subscription_event_type_t>();
    return subscription_event_create(event_type, pyparent);
  }
  if (strcmp(pyparent.name(), "rclpy_publisher_t") == 0) {
    auto event_type = pyevent_type.cast<rcl_publisher_event_type_t>();
    return publisher_event_create(event_type, pyparent);
  }
  throw py::type_error("event parent is neither a publisher nor a subscription");
}

py::object
take_event(py::capsule pyevent, py::capsule pyparent, py::object pyevent_type)
{
  auto event = static_cast<rcl_event_t *>(
    rclpy_handle_get_pointer_from_capsule(pyevent.ptr(), "rcl_event_t"));
  if (!event) {
    throw py::error_already_set();
  }

  qos_event_data_filler_function * event_filler =
    qos_event_data_filler_function_for(pyparent, pyevent_type);

  qos_event_callback_data_t event_data;
  rcl_ret_t ret = rcl_take_event(event, &event_data);
  if (RCL_RET_OK != ret) {
    if (RCL_RET_BAD_ALLOC == ret) {
      rcl_reset_error();
      throw std::bad_alloc();
    }
    if (RCL_RET_EVENT_TAKE_FAILED == ret) {
      return py::none();
    }
    throw RCLError("failed to take event");
  }

  return event_filler(&event_data);
}

}  // namespace rclpy
<commit_msg>Include pybind11 first to fix windows debug warning (#731)<commit_after>// Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// 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.

// Include pybind11 before rclpy_common/handle.h includes Python.h
#include <pybind11/pybind11.h>

#include <rcl/error_handling.h>
#include <rcl/event.h>
#include <rcl/types.h>
#include <rcpputils/scope_exit.hpp>
#include <rmw/incompatible_qos_events_statuses.h>

#include <memory>
#include <utility>

#include "rclpy_common/common.h"
#include "rclpy_common/handle.h"
#include "rclpy_common/exceptions.hpp"

#include "qos_events.hpp"

namespace rclpy
{

namespace
{

#define PYMODULE_NAME "rclpy.qos_event"

typedef union qos_event_callback_data {
  // Subscription events
  rmw_requested_deadline_missed_status_t requested_deadline_missed;
  rmw_liveliness_changed_status_t liveliness_changed;
  rmw_message_lost_status_t message_lost;
  rmw_requested_qos_incompatible_event_status_t requested_incompatible_qos;
  // Publisher events
  rmw_offered_deadline_missed_status_t offered_deadline_missed;
  rmw_liveliness_lost_status_t liveliness_lost;
  rmw_offered_qos_incompatible_event_status_t offered_incompatible_qos;
} qos_event_callback_data_t;

typedef py::object qos_event_data_filler_function (const qos_event_callback_data_t *);

template<typename T>
using unique_cstruct_ptr = std::unique_ptr<T, void (*)(T *)>;

unique_cstruct_ptr<rcl_event_t>
create_zero_initialized_event()
{
  unique_cstruct_ptr<rcl_event_t> event(
    static_cast<rcl_event_t *>(PyMem_Malloc(sizeof(rcl_event_t))),
    [](rcl_event_t * event) {
      if (!event) {
        PyErr_Clear();
        int stack_level = 1;
        PyErr_WarnFormat(
          PyExc_RuntimeWarning, stack_level,
          "no rcl_event_t to delete");
      }
      rcl_ret_t ret = rcl_event_fini(event);
      if (RCL_RET_OK != ret) {
        int stack_level = 1;
        PyErr_WarnFormat(
          PyExc_RuntimeWarning, stack_level,
          "failed to fini event: %s",
          rcl_get_error_string().str);
        rcl_reset_error();
      }
      PyMem_Free(event);
    });
  if (!event) {
    throw std::bad_alloc();
  }
  *event = rcl_get_zero_initialized_event();
  return event;
}

py::object
_requested_deadline_missed_to_py_object(const qos_event_callback_data_t * data)
{
  py::module qos_events = py::module::import(PYMODULE_NAME);
  py::object pyclass = qos_events.attr("QoSRequestedDeadlineMissedInfo");
  return pyclass(
    data->requested_deadline_missed.total_count,
    data->requested_deadline_missed.total_count_change);
}

py::object
_liveliness_changed_to_py_object(const qos_event_callback_data_t * data)
{
  py::module qos_events = py::module::import(PYMODULE_NAME);
  py::object pyclass = qos_events.attr("QoSLivelinessChangedInfo");
  return pyclass(
    data->liveliness_changed.alive_count,
    data->liveliness_changed.not_alive_count,
    data->liveliness_changed.alive_count_change,
    data->liveliness_changed.not_alive_count_change);
}

py::object
_message_lost_to_py_object(const qos_event_callback_data_t * data)
{
  py::module qos_events = py::module::import(PYMODULE_NAME);
  py::object pyclass = qos_events.attr("QoSMessageLostInfo");
  return pyclass(
    data->message_lost.total_count,
    data->message_lost.total_count_change);
}

py::object
_requested_incompatible_qos_to_py_object(const qos_event_callback_data_t * data)
{
  py::module qos_events = py::module::import(PYMODULE_NAME);
  py::object pyclass = qos_events.attr("QoSRequestedIncompatibleQoSInfo");
  return pyclass(
    data->requested_incompatible_qos.total_count,
    data->requested_incompatible_qos.total_count_change,
    // enum does not specify underlying data type, need intermediate cast
    static_cast<int>(data->requested_incompatible_qos.last_policy_kind));
}

py::object
_offered_deadline_missed_to_py_object(const qos_event_callback_data_t * data)
{
  py::module qos_events = py::module::import(PYMODULE_NAME);
  py::object pyclass = qos_events.attr("QoSOfferedDeadlineMissedInfo");
  return pyclass(
    data->offered_deadline_missed.total_count,
    data->offered_deadline_missed.total_count_change);
}

py::object
_liveliness_lost_to_py_object(const qos_event_callback_data_t * data)
{
  py::module qos_events = py::module::import(PYMODULE_NAME);
  py::object pyclass = qos_events.attr("QoSLivelinessLostInfo");
  return pyclass(
    data->liveliness_lost.total_count,
    data->liveliness_lost.total_count_change);
}

py::object
_offered_incompatible_qos_to_py_object(const qos_event_callback_data_t * data)
{
  py::module qos_events = py::module::import(PYMODULE_NAME);
  py::object pyclass = qos_events.attr("QoSOfferedIncompatibleQoSInfo");
  return pyclass(
    data->offered_incompatible_qos.total_count,
    data->offered_incompatible_qos.total_count_change,
    // enum does not specify underlying data type, need intermediate cast
    static_cast<int>(data->offered_incompatible_qos.last_policy_kind));
}

qos_event_data_filler_function *
qos_event_data_filler_function_for(py::capsule pyparent, py::object pyevent_type)
{
  if (strcmp(pyparent.name(), "rclpy_subscription_t") == 0) {
    switch (pyevent_type.cast<rcl_subscription_event_type_t>()) {
      case RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED:
        return &_requested_deadline_missed_to_py_object;
      case RCL_SUBSCRIPTION_LIVELINESS_CHANGED:
        return &_liveliness_changed_to_py_object;
      case RCL_SUBSCRIPTION_MESSAGE_LOST:
        return &_message_lost_to_py_object;
      case RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS:
        return &_requested_incompatible_qos_to_py_object;
      default:
        throw py::value_error("event type for subscriptions not understood");
        // although this suggests a misalignment between C and Python interfaces
    }
  }
  if (strcmp(pyparent.name(), "rclpy_publisher_t") == 0) {
    switch (pyevent_type.cast<rcl_publisher_event_type_t>()) {
      case RCL_PUBLISHER_OFFERED_DEADLINE_MISSED:
        return &_offered_deadline_missed_to_py_object;
      case RCL_PUBLISHER_LIVELINESS_LOST:
        return &_liveliness_lost_to_py_object;
      case RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS:
        return &_offered_incompatible_qos_to_py_object;
      default:
        throw py::value_error("event type for publishers not understood");
        // although this suggests a misalignment between C and Python interfaces
    }
  }
  throw py::type_error("event parent is neither a publisher nor a subscription");
}

py::capsule
event_wrap_in_capsule(unique_cstruct_ptr<rcl_event_t> event, py::capsule pyparent)
{
  rclpy_handle_destructor_t destructor =
    reinterpret_cast<rclpy_handle_destructor_t>(event.get_deleter());
  PyObject * pyevent_c =
    rclpy_create_handle_capsule(event.get(), "rcl_event_t", destructor);
  if (!pyevent_c) {
    throw py::error_already_set();
  }
  auto pyevent = py::reinterpret_steal<py::capsule>(pyevent_c);
  event.release();  // pyevent now owns rcl_event_t

  rclpy_handle_t * event_handle = static_cast<rclpy_handle_t *>(pyevent);
  rclpy_handle_t * parent_handle = static_cast<rclpy_handle_t *>(pyparent);
  _rclpy_handle_add_dependency(event_handle, parent_handle);
  if (PyErr_Occurred()) {
    throw py::error_already_set();
  }
  return pyevent;
}

py::object
publisher_event_create(rcl_publisher_event_type_t event_type, py::capsule pypublisher)
{
  auto wrapper = static_cast<rclpy_publisher_t *>(
    rclpy_handle_get_pointer_from_capsule(pypublisher.ptr(), "rclpy_publisher_t"));
  if (!wrapper) {
    throw py::error_already_set();
  }

  unique_cstruct_ptr<rcl_event_t> event = create_zero_initialized_event();

  rcl_ret_t ret = rcl_publisher_event_init(
    event.get(), &(wrapper->publisher), event_type);
  if (RCL_RET_OK != ret) {
    if (RCL_RET_BAD_ALLOC == ret) {
      rcl_reset_error();
      throw std::bad_alloc();
    }
    if (RCL_RET_UNSUPPORTED == ret) {
      throw UnsupportedEventTypeError("publisher event is unsupported");
    }
    throw RCLError("failed to create publisher event");
  }

  return event_wrap_in_capsule(std::move(event), pypublisher);
}

py::object
subscription_event_create(rcl_subscription_event_type_t event_type, py::capsule pysubscription)
{
  auto wrapper = static_cast<rclpy_subscription_t *>(
    rclpy_handle_get_pointer_from_capsule(pysubscription.ptr(), "rclpy_subscription_t"));
  if (!wrapper) {
    throw py::error_already_set();
  }

  unique_cstruct_ptr<rcl_event_t> event = create_zero_initialized_event();

  rcl_ret_t ret = rcl_subscription_event_init(
    event.get(), &(wrapper->subscription), event_type);
  if (RCL_RET_OK != ret) {
    if (RCL_RET_BAD_ALLOC == ret) {
      rcl_reset_error();
      throw std::bad_alloc();
    }
    if (RCL_RET_UNSUPPORTED == ret) {
      throw UnsupportedEventTypeError("subscription event is unsupported");
    }
    throw RCLError("failed to create subscription event");
  }

  return event_wrap_in_capsule(std::move(event), pysubscription);
}

}  // namespace

py::object
create_event(py::object pyevent_type, py::capsule pyparent)
{
  if (strcmp(pyparent.name(), "rclpy_subscription_t") == 0) {
    auto event_type = pyevent_type.cast<rcl_subscription_event_type_t>();
    return subscription_event_create(event_type, pyparent);
  }
  if (strcmp(pyparent.name(), "rclpy_publisher_t") == 0) {
    auto event_type = pyevent_type.cast<rcl_publisher_event_type_t>();
    return publisher_event_create(event_type, pyparent);
  }
  throw py::type_error("event parent is neither a publisher nor a subscription");
}

py::object
take_event(py::capsule pyevent, py::capsule pyparent, py::object pyevent_type)
{
  auto event = static_cast<rcl_event_t *>(
    rclpy_handle_get_pointer_from_capsule(pyevent.ptr(), "rcl_event_t"));
  if (!event) {
    throw py::error_already_set();
  }

  qos_event_data_filler_function * event_filler =
    qos_event_data_filler_function_for(pyparent, pyevent_type);

  qos_event_callback_data_t event_data;
  rcl_ret_t ret = rcl_take_event(event, &event_data);
  if (RCL_RET_OK != ret) {
    if (RCL_RET_BAD_ALLOC == ret) {
      rcl_reset_error();
      throw std::bad_alloc();
    }
    if (RCL_RET_EVENT_TAKE_FAILED == ret) {
      return py::none();
    }
    throw RCLError("failed to take event");
  }

  return event_filler(&event_data);
}

}  // namespace rclpy
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "filetime.h"

#include <QtCore/qstring.h>

#ifdef Q_OS_WIN
#include <QtCore/qt_windows.h>
#else
#include <QtCore/qdatetime.h>
#endif

namespace qbs {
namespace Internal {

#ifdef Q_OS_WIN
template<bool> struct CompileTimeAssert;
template<> struct CompileTimeAssert<true> {};
#endif

#ifdef APPLE_CUSTOM_CLOCK_GETTIME
#include <sys/time.h>
// clk_id isn't used, only the CLOCK_REALTIME case is implemented.
int clock_gettime(int /*clk_id*/, struct timespec *t)
{
    struct timeval tv;
    // Resolution of gettimeofday is 1000nsecs = 1 microsecond.
    int ret = gettimeofday(&tv, NULL);
    t->tv_sec  = tv.tv_sec;
    t->tv_nsec = tv.tv_usec * 1000;
    return ret;
}
#endif

FileTime::FileTime()
{
#ifdef Q_OS_WIN
    static CompileTimeAssert<sizeof(FileTime::InternalType) == sizeof(FILETIME)> internal_type_has_wrong_size;
    Q_UNUSED(internal_type_has_wrong_size);
    m_fileTime = 0;
#elif HAS_CLOCK_GETTIME
    m_fileTime = {0, 0};
#else
    m_fileTime = 0;
#endif
}

FileTime::FileTime(const FileTime::InternalType &ft) : m_fileTime(ft)
{
#if HAS_CLOCK_GETTIME
    if (m_fileTime.tv_sec == 0)
        m_fileTime.tv_nsec = 0; // stat() sets only the first member to 0 for non-existing files.
#endif
}

int FileTime::compare(const FileTime &other) const
{
#ifdef Q_OS_WIN
    const FILETIME *const t1 = reinterpret_cast<const FILETIME *>(&m_fileTime);
    const FILETIME *const t2 = reinterpret_cast<const FILETIME *>(&other.m_fileTime);
    return CompareFileTime(t1, t2);
#elif HAS_CLOCK_GETTIME
    if (m_fileTime.tv_sec < other.m_fileTime.tv_sec)
        return -1;
    if (m_fileTime.tv_sec > other.m_fileTime.tv_sec)
        return 1;
    if (m_fileTime.tv_nsec < other.m_fileTime.tv_nsec)
        return -1;
    if (m_fileTime.tv_nsec > other.m_fileTime.tv_nsec)
        return 1;
    return 0;
#else
    if (m_fileTime < other.m_fileTime)
        return -1;
    if (m_fileTime > other.m_fileTime)
        return 1;
    return 0;
#endif
}

void FileTime::clear()
{
#if HAS_CLOCK_GETTIME
    m_fileTime = { 0, 0 };
#else
    m_fileTime = 0;
#endif
}

bool FileTime::isValid() const
{
    return *this != FileTime();
}

FileTime FileTime::currentTime()
{
#ifdef Q_OS_WIN
    FileTime result;
    SYSTEMTIME st;
    GetSystemTime(&st);
    FILETIME *const ft = reinterpret_cast<FILETIME *>(&result.m_fileTime);
    SystemTimeToFileTime(&st, ft);
    return result;
#elif defined APPLE_CUSTOM_CLOCK_GETTIME
    InternalType t;
    // Explicitly use our custom version, so that we don't get an additional unresolved symbol on a
    // system that actually provides one, but isn't used due to the minimium deployment target
    // being lower.
    qbs::Internal::clock_gettime(CLOCK_REALTIME, &t);
    return t;
#elif HAS_CLOCK_GETTIME
    InternalType t;
    clock_gettime(CLOCK_REALTIME, &t);
    return t;
#else
    return time(nullptr);
#endif
}

FileTime FileTime::oldestTime()
{
#ifdef Q_OS_WIN
    SYSTEMTIME st = {
        1601,
        1,
        5,
        2,
        0,
        0,
        0,
        0
    };
    FileTime result;
    FILETIME *const ft = reinterpret_cast<FILETIME *>(&result.m_fileTime);
    SystemTimeToFileTime(&st, ft);
    return result;
#elif HAS_CLOCK_GETTIME
    return FileTime({1, 0});
#else
    return 1;
#endif
}

double FileTime::asDouble() const
{
#if HAS_CLOCK_GETTIME
    return static_cast<double>(m_fileTime.tv_sec);
#else
    return static_cast<double>(m_fileTime);
#endif
}

QString FileTime::toString() const
{
#ifdef Q_OS_WIN
    const FILETIME *const ft = reinterpret_cast<const FILETIME *>(&m_fileTime);
    SYSTEMTIME stUTC, stLocal;
    FileTimeToSystemTime(ft, &stUTC);
    SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);
    const QString result = QString::fromLatin1("%1.%2.%3 %4:%5:%6")
            .arg(stLocal.wDay, 2, 10, QLatin1Char('0')).arg(stLocal.wMonth, 2, 10, QLatin1Char('0')).arg(stLocal.wYear)
            .arg(stLocal.wHour, 2, 10, QLatin1Char('0')).arg(stLocal.wMinute, 2, 10, QLatin1Char('0')).arg(stLocal.wSecond, 2, 10, QLatin1Char('0'));
    return result;
#else
    QDateTime dt;
#if HAS_CLOCK_GETTIME
   dt.setMSecsSinceEpoch(m_fileTime.tv_sec * 1000 + m_fileTime.tv_nsec / 1000000);
#else
    dt.setTime_t(m_fileTime);
#endif
    return dt.toString(Qt::ISODateWithMs);
#endif
}

} // namespace Internal
} // namespace qbs
<commit_msg>Fix CLOCK_REALTIME not being available on macOS SDK < 10.11<commit_after>/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qbs.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "filetime.h"

#include <QtCore/qstring.h>

#ifdef Q_OS_WIN
#include <QtCore/qt_windows.h>
#else
#include <QtCore/qdatetime.h>
#endif

namespace qbs {
namespace Internal {

#ifdef Q_OS_WIN
template<bool> struct CompileTimeAssert;
template<> struct CompileTimeAssert<true> {};
#endif

#ifdef APPLE_CUSTOM_CLOCK_GETTIME
#include <sys/time.h>

#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 0
#endif

// clk_id isn't used, only the CLOCK_REALTIME case is implemented.
int clock_gettime(int /*clk_id*/, struct timespec *t)
{
    struct timeval tv;
    // Resolution of gettimeofday is 1000nsecs = 1 microsecond.
    int ret = gettimeofday(&tv, NULL);
    t->tv_sec  = tv.tv_sec;
    t->tv_nsec = tv.tv_usec * 1000;
    return ret;
}
#endif

FileTime::FileTime()
{
#ifdef Q_OS_WIN
    static CompileTimeAssert<sizeof(FileTime::InternalType) == sizeof(FILETIME)> internal_type_has_wrong_size;
    Q_UNUSED(internal_type_has_wrong_size);
    m_fileTime = 0;
#elif HAS_CLOCK_GETTIME
    m_fileTime = {0, 0};
#else
    m_fileTime = 0;
#endif
}

FileTime::FileTime(const FileTime::InternalType &ft) : m_fileTime(ft)
{
#if HAS_CLOCK_GETTIME
    if (m_fileTime.tv_sec == 0)
        m_fileTime.tv_nsec = 0; // stat() sets only the first member to 0 for non-existing files.
#endif
}

int FileTime::compare(const FileTime &other) const
{
#ifdef Q_OS_WIN
    const FILETIME *const t1 = reinterpret_cast<const FILETIME *>(&m_fileTime);
    const FILETIME *const t2 = reinterpret_cast<const FILETIME *>(&other.m_fileTime);
    return CompareFileTime(t1, t2);
#elif HAS_CLOCK_GETTIME
    if (m_fileTime.tv_sec < other.m_fileTime.tv_sec)
        return -1;
    if (m_fileTime.tv_sec > other.m_fileTime.tv_sec)
        return 1;
    if (m_fileTime.tv_nsec < other.m_fileTime.tv_nsec)
        return -1;
    if (m_fileTime.tv_nsec > other.m_fileTime.tv_nsec)
        return 1;
    return 0;
#else
    if (m_fileTime < other.m_fileTime)
        return -1;
    if (m_fileTime > other.m_fileTime)
        return 1;
    return 0;
#endif
}

void FileTime::clear()
{
#if HAS_CLOCK_GETTIME
    m_fileTime = { 0, 0 };
#else
    m_fileTime = 0;
#endif
}

bool FileTime::isValid() const
{
    return *this != FileTime();
}

FileTime FileTime::currentTime()
{
#ifdef Q_OS_WIN
    FileTime result;
    SYSTEMTIME st;
    GetSystemTime(&st);
    FILETIME *const ft = reinterpret_cast<FILETIME *>(&result.m_fileTime);
    SystemTimeToFileTime(&st, ft);
    return result;
#elif defined APPLE_CUSTOM_CLOCK_GETTIME
    InternalType t;
    // Explicitly use our custom version, so that we don't get an additional unresolved symbol on a
    // system that actually provides one, but isn't used due to the minimium deployment target
    // being lower.
    qbs::Internal::clock_gettime(CLOCK_REALTIME, &t);
    return t;
#elif HAS_CLOCK_GETTIME
    InternalType t;
    clock_gettime(CLOCK_REALTIME, &t);
    return t;
#else
    return time(nullptr);
#endif
}

FileTime FileTime::oldestTime()
{
#ifdef Q_OS_WIN
    SYSTEMTIME st = {
        1601,
        1,
        5,
        2,
        0,
        0,
        0,
        0
    };
    FileTime result;
    FILETIME *const ft = reinterpret_cast<FILETIME *>(&result.m_fileTime);
    SystemTimeToFileTime(&st, ft);
    return result;
#elif HAS_CLOCK_GETTIME
    return FileTime({1, 0});
#else
    return 1;
#endif
}

double FileTime::asDouble() const
{
#if HAS_CLOCK_GETTIME
    return static_cast<double>(m_fileTime.tv_sec);
#else
    return static_cast<double>(m_fileTime);
#endif
}

QString FileTime::toString() const
{
#ifdef Q_OS_WIN
    const FILETIME *const ft = reinterpret_cast<const FILETIME *>(&m_fileTime);
    SYSTEMTIME stUTC, stLocal;
    FileTimeToSystemTime(ft, &stUTC);
    SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);
    const QString result = QString::fromLatin1("%1.%2.%3 %4:%5:%6")
            .arg(stLocal.wDay, 2, 10, QLatin1Char('0')).arg(stLocal.wMonth, 2, 10, QLatin1Char('0')).arg(stLocal.wYear)
            .arg(stLocal.wHour, 2, 10, QLatin1Char('0')).arg(stLocal.wMinute, 2, 10, QLatin1Char('0')).arg(stLocal.wSecond, 2, 10, QLatin1Char('0'));
    return result;
#else
    QDateTime dt;
#if HAS_CLOCK_GETTIME
   dt.setMSecsSinceEpoch(m_fileTime.tv_sec * 1000 + m_fileTime.tv_nsec / 1000000);
#else
    dt.setTime_t(m_fileTime);
#endif
    return dt.toString(Qt::ISODateWithMs);
#endif
}

} // namespace Internal
} // namespace qbs
<|endoftext|>


<commit_before>/* $Id$ */

/*
 * Copyright (c) 2010 SURFnet bv
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*****************************************************************************
 Directory.cpp

 Helper functions for accessing directories.
 *****************************************************************************/

#include "config.h"
#include "Directory.h"
#include "OSPathSep.h"
#include "log.h"
#include <string>
#include <vector>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

// Constructor
Directory::Directory(std::string path)
{
	this->path = path;

	valid = refresh();
}

// Check if the directory is valid
bool Directory::isValid()
{
	return valid;
}

// Return a list of all files in a directory
std::vector<std::string> Directory::getFiles()
{
	return files;
}

// Return a list of all subdirectories in a directory
std::vector<std::string> Directory::getSubDirs()
{
	return subDirs;
}

// Refresh the directory listing
bool Directory::refresh()
{
	// Reset the state
	valid = false;

	subDirs.clear();
	files.clear();

	// Enumerate the directory
	DIR* dir = opendir(path.c_str());

	if (dir == NULL)
	{
		DEBUG_MSG("Failed to open directory %s", path.c_str());

		return false;
	}

	// Enumerate the directory
	struct dirent* entry = NULL;

	while ((entry = readdir(dir)) != NULL)
	{
		// Check if this is the . or .. entry
		if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
		{
			continue;
		}

		// Convert the name of the entry to a C++ string
		std::string name(entry->d_name);

#if defined(_DIRENT_HAVE_D_TYPE) && defined(_BSD_SOURCE)
		// Determine the type of the entry
		switch(entry->d_type)
		{
		case DT_DIR:
			// This is a directory
			subDirs.push_back(name);
			break;
		case DT_REG:
			// This is a regular file
			files.push_back(name);
			break;
		default:
			DEBUG_MSG("File not used %s", name.c_str());
			break;
		}
#else
		// The entry type has to be determined using lstat
		struct stat entryStatus;

		std::string fullPath = path + OS_PATHSEP + name;

		if (!lstat(fullPath.c_str(), &entryStatus))
		{
			if (S_ISDIR(entryStatus->st_mode))
			{
				subDirs.push_back(name);
			}
			else if (S_ISREG(entryStatus->st_mode))
			{
				files.push_back(name);
			}
			else
			{
				DEBUG_MSG("File not used %s", name.c_str());
			}
		}
#endif
	}

	// Close the directory
	closedir(dir);

	valid = true;

	return true;
}

// Create a new subdirectory
bool Directory::mkdir(std::string name)
{
	std::string fullPath = path + OS_PATHSEP + name;

	return (!::mkdir(fullPath.c_str(), S_IFDIR | S_IRWXU) && refresh());
}

// Delete a file or subdirectory in the directory
bool Directory::remove(std::string name)
{
	std::string fullPath = path + OS_PATHSEP + name;

	return (!::remove(fullPath.c_str()) && refresh());
}

<commit_msg>Non-pointer<commit_after>/* $Id$ */

/*
 * Copyright (c) 2010 SURFnet bv
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*****************************************************************************
 Directory.cpp

 Helper functions for accessing directories.
 *****************************************************************************/

#include "config.h"
#include "Directory.h"
#include "OSPathSep.h"
#include "log.h"
#include <string>
#include <vector>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

// Constructor
Directory::Directory(std::string path)
{
	this->path = path;

	valid = refresh();
}

// Check if the directory is valid
bool Directory::isValid()
{
	return valid;
}

// Return a list of all files in a directory
std::vector<std::string> Directory::getFiles()
{
	return files;
}

// Return a list of all subdirectories in a directory
std::vector<std::string> Directory::getSubDirs()
{
	return subDirs;
}

// Refresh the directory listing
bool Directory::refresh()
{
	// Reset the state
	valid = false;

	subDirs.clear();
	files.clear();

	// Enumerate the directory
	DIR* dir = opendir(path.c_str());

	if (dir == NULL)
	{
		DEBUG_MSG("Failed to open directory %s", path.c_str());

		return false;
	}

	// Enumerate the directory
	struct dirent* entry = NULL;

	while ((entry = readdir(dir)) != NULL)
	{
		// Check if this is the . or .. entry
		if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
		{
			continue;
		}

		// Convert the name of the entry to a C++ string
		std::string name(entry->d_name);

#if defined(_DIRENT_HAVE_D_TYPE) && defined(_BSD_SOURCE)
		// Determine the type of the entry
		switch(entry->d_type)
		{
		case DT_DIR:
			// This is a directory
			subDirs.push_back(name);
			break;
		case DT_REG:
			// This is a regular file
			files.push_back(name);
			break;
		default:
			DEBUG_MSG("File not used %s", name.c_str());
			break;
		}
#else
		// The entry type has to be determined using lstat
		struct stat entryStatus;

		std::string fullPath = path + OS_PATHSEP + name;

		if (!lstat(fullPath.c_str(), &entryStatus))
		{
			if (S_ISDIR(entryStatus.st_mode))
			{
				subDirs.push_back(name);
			}
			else if (S_ISREG(entryStatus.st_mode))
			{
				files.push_back(name);
			}
			else
			{
				DEBUG_MSG("File not used %s", name.c_str());
			}
		}
#endif
	}

	// Close the directory
	closedir(dir);

	valid = true;

	return true;
}

// Create a new subdirectory
bool Directory::mkdir(std::string name)
{
	std::string fullPath = path + OS_PATHSEP + name;

	return (!::mkdir(fullPath.c_str(), S_IFDIR | S_IRWXU) && refresh());
}

// Delete a file or subdirectory in the directory
bool Directory::remove(std::string name)
{
	std::string fullPath = path + OS_PATHSEP + name;

	return (!::remove(fullPath.c_str()) && refresh());
}

<|endoftext|>


<commit_before>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2014 Klaus Post
    Copyright (C) 2014 Pedro Côrte-Real

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "tiff/CiffEntry.h"
#include "common/Common.h"               // for uchar8, uint32, ushort16
#include "io/Buffer.h"                   // for Buffer
#include "io/Endianness.h"               // for getU32LE, getU16LE
#include "parsers/CiffParserException.h" // for ThrowCPE
#include <cstdio>                        // for sprintf
#include <cstring>                       // for memcpy, strlen
#include <limits>                        // for numeric_limits
#include <string>                        // for string, allocator
#include <vector>                        // for vector

using std::numeric_limits;
using std::string;
using std::vector;

namespace rawspeed {

CiffEntry::CiffEntry(Buffer* f, uint32 value_data, uint32 offset) {
  own_data = nullptr;
  ushort16 p = getU16LE(f->getData(offset, 2));
  tag = static_cast<CiffTag>(p & 0x3fff);
  ushort16 datalocation = (p & 0xc000);
  type = static_cast<CiffDataType>(p & 0x3800);
  if (datalocation == 0x0000) { // Data is offset in value_data
    bytesize = getU32LE(f->getData(offset + 2, 4));

    data_offset = getU32LE(f->getData(offset + 6, 4));
    if (data_offset >= numeric_limits<uint32>::max() - value_data)
      ThrowCPE("Corrupt data offset.");

    data_offset += value_data;

    data = f->getData(data_offset, bytesize);
  } else if (datalocation == 0x4000) { // Data is stored directly in entry
    data_offset = offset + 2;
    bytesize = 8; // Maximum of 8 bytes of data (the size and offset fields)
    data = f->getData(data_offset, bytesize);
  } else
    ThrowCPE("Don't understand data location 0x%x", datalocation);

  // Set the number of items using the shift
  count = bytesize >> getElementShift();
}

CiffEntry::~CiffEntry() { delete[] own_data; }

uint32 __attribute__((pure)) CiffEntry::getElementShift() {
  switch (type) {
    case CIFF_SHORT:
      return 1;
    case CIFF_LONG:
    case CIFF_MIX:
    case CIFF_SUB1:
    case CIFF_SUB2:
      return 2;
    case CIFF_BYTE:
    case CIFF_ASCII:
    default:
      return 0;
  }
}

uint32 __attribute__((pure)) CiffEntry::getElementSize() {
  switch (type) {
    case CIFF_BYTE:
    case CIFF_ASCII:
      return 1;
    case CIFF_SHORT:
      return 2;
    case CIFF_LONG:
    case CIFF_MIX:
    case CIFF_SUB1:
    case CIFF_SUB2:
      return 4;
    default:
      return 0;
  }
}

bool __attribute__((pure)) CiffEntry::isInt() {
  return (type == CIFF_LONG || type == CIFF_SHORT || type ==  CIFF_BYTE);
}

uint32 CiffEntry::getU32(uint32 num) {
  if (!isInt()) {
    ThrowCPE(
        "Wrong type 0x%x encountered. Expected Long, Short or Byte at 0x%x",
        type, tag);
  }

  if (type == CIFF_BYTE)
    return getByte(num);
  if (type == CIFF_SHORT)
    return getU16(num);

  if (num*4+3 >= bytesize)
    ThrowCPE("Trying to read out of bounds");

  return getU32LE(data + num * 4);
}

ushort16 CiffEntry::getU16(uint32 num) {
  if (type != CIFF_SHORT && type != CIFF_BYTE)
    ThrowCPE("Wrong type 0x%x encountered. Expected Short at 0x%x", type, tag);

  if (num*2+1 >= bytesize)
    ThrowCPE("Trying to read out of bounds");

  return getU16LE(data + num * 2);
}

uchar8 CiffEntry::getByte(uint32 num) {
  if (type != CIFF_BYTE)
    ThrowCPE("Wrong type 0x%x encountered. Expected Byte at 0x%x", type, tag);

  if (num >= bytesize)
    ThrowCPE("Trying to read out of bounds");

  return data[num];
}

string CiffEntry::getString() {
  if (type != CIFF_ASCII)
    ThrowCPE("Wrong type 0x%x encountered. Expected Ascii", type);

  if (count == 0)
    return string("");

  if (!own_data) {
    own_data = new uchar8[count];
    memcpy(own_data, data, count);
    own_data[count-1] = 0;  // Ensure string is not larger than count defines
  }

  return string(reinterpret_cast<const char*>(&own_data[0]));
}

vector<string> CiffEntry::getStrings() {
  vector<string> strs;
  if (type != CIFF_ASCII)
    ThrowCPE("Wrong type 0x%x encountered. Expected Ascii", type);
  if (!own_data) {
    own_data = new uchar8[count];
    memcpy(own_data, data, count);
    own_data[count-1] = 0;  // Ensure string is not larger than count defines
  }
  uint32 start = 0;
  for (uint32 i=0; i< count; i++) {
    if (own_data[i] == 0) {
      strs.emplace_back(reinterpret_cast<const char*>(&own_data[start]));
      start = i+1;
    }
  }
  return strs;
}

bool __attribute__((pure)) CiffEntry::isString() {
  return (type == CIFF_ASCII);
}

void CiffEntry::setData( const void *in_data, uint32 byte_count )
{
  if (byte_count > bytesize)
    ThrowCPE("data set larger than entry size given");

  if (!own_data) {
    own_data = new uchar8[bytesize];
    memcpy(own_data, data, bytesize);
  }
  memcpy(own_data, in_data, byte_count);
}

#ifdef _MSC_VER
#pragma warning(disable: 4996) // this function or variable may be unsafe
#endif

std::string CiffEntry::getValueAsString()
{
  if (type == CIFF_ASCII)
    return string(reinterpret_cast<const char*>(&data[0]));
  auto *temp_string = new char[4096];
  if (count == 1) {
    switch (type) {
      case CIFF_LONG:
        sprintf(temp_string, "Long: %u (0x%x)", getU32(), getU32());
        break;
      case CIFF_SHORT:
        sprintf(temp_string, "Short: %u (0x%x)", getU32(), getU32());
        break;
      case CIFF_BYTE:
        sprintf(temp_string, "Byte: %u (0x%x)", getU32(), getU32());
        break;
      default:
        sprintf(temp_string, "Type: %x: ", type);
        for (uint32 i = 0; i < getElementSize(); i++) {
          sprintf(&temp_string[strlen(temp_string-1)], "%x", data[i]);
        }
    }
  }
  string ret(temp_string);
  delete [] temp_string;
  return ret;
}

} // namespace rawspeed
<commit_msg>CiffEntry::getElementShift(): remove redundant case<commit_after>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2014 Klaus Post
    Copyright (C) 2014 Pedro Côrte-Real

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "tiff/CiffEntry.h"
#include "common/Common.h"               // for uchar8, uint32, ushort16
#include "io/Buffer.h"                   // for Buffer
#include "io/Endianness.h"               // for getU32LE, getU16LE
#include "parsers/CiffParserException.h" // for ThrowCPE
#include <cstdio>                        // for sprintf
#include <cstring>                       // for memcpy, strlen
#include <limits>                        // for numeric_limits
#include <string>                        // for string, allocator
#include <vector>                        // for vector

using std::numeric_limits;
using std::string;
using std::vector;

namespace rawspeed {

CiffEntry::CiffEntry(Buffer* f, uint32 value_data, uint32 offset) {
  own_data = nullptr;
  ushort16 p = getU16LE(f->getData(offset, 2));
  tag = static_cast<CiffTag>(p & 0x3fff);
  ushort16 datalocation = (p & 0xc000);
  type = static_cast<CiffDataType>(p & 0x3800);
  if (datalocation == 0x0000) { // Data is offset in value_data
    bytesize = getU32LE(f->getData(offset + 2, 4));

    data_offset = getU32LE(f->getData(offset + 6, 4));
    if (data_offset >= numeric_limits<uint32>::max() - value_data)
      ThrowCPE("Corrupt data offset.");

    data_offset += value_data;

    data = f->getData(data_offset, bytesize);
  } else if (datalocation == 0x4000) { // Data is stored directly in entry
    data_offset = offset + 2;
    bytesize = 8; // Maximum of 8 bytes of data (the size and offset fields)
    data = f->getData(data_offset, bytesize);
  } else
    ThrowCPE("Don't understand data location 0x%x", datalocation);

  // Set the number of items using the shift
  count = bytesize >> getElementShift();
}

CiffEntry::~CiffEntry() { delete[] own_data; }

uint32 __attribute__((pure)) CiffEntry::getElementShift() {
  switch (type) {
    case CIFF_SHORT:
      return 1;
    case CIFF_LONG:
    case CIFF_MIX:
    case CIFF_SUB1:
    case CIFF_SUB2:
      return 2;
    default:
      // e.g. CIFF_BYTE or CIFF_ASCII
      return 0;
  }
}

uint32 __attribute__((pure)) CiffEntry::getElementSize() {
  switch (type) {
    case CIFF_BYTE:
    case CIFF_ASCII:
      return 1;
    case CIFF_SHORT:
      return 2;
    case CIFF_LONG:
    case CIFF_MIX:
    case CIFF_SUB1:
    case CIFF_SUB2:
      return 4;
    default:
      return 0;
  }
}

bool __attribute__((pure)) CiffEntry::isInt() {
  return (type == CIFF_LONG || type == CIFF_SHORT || type ==  CIFF_BYTE);
}

uint32 CiffEntry::getU32(uint32 num) {
  if (!isInt()) {
    ThrowCPE(
        "Wrong type 0x%x encountered. Expected Long, Short or Byte at 0x%x",
        type, tag);
  }

  if (type == CIFF_BYTE)
    return getByte(num);
  if (type == CIFF_SHORT)
    return getU16(num);

  if (num*4+3 >= bytesize)
    ThrowCPE("Trying to read out of bounds");

  return getU32LE(data + num * 4);
}

ushort16 CiffEntry::getU16(uint32 num) {
  if (type != CIFF_SHORT && type != CIFF_BYTE)
    ThrowCPE("Wrong type 0x%x encountered. Expected Short at 0x%x", type, tag);

  if (num*2+1 >= bytesize)
    ThrowCPE("Trying to read out of bounds");

  return getU16LE(data + num * 2);
}

uchar8 CiffEntry::getByte(uint32 num) {
  if (type != CIFF_BYTE)
    ThrowCPE("Wrong type 0x%x encountered. Expected Byte at 0x%x", type, tag);

  if (num >= bytesize)
    ThrowCPE("Trying to read out of bounds");

  return data[num];
}

string CiffEntry::getString() {
  if (type != CIFF_ASCII)
    ThrowCPE("Wrong type 0x%x encountered. Expected Ascii", type);

  if (count == 0)
    return string("");

  if (!own_data) {
    own_data = new uchar8[count];
    memcpy(own_data, data, count);
    own_data[count-1] = 0;  // Ensure string is not larger than count defines
  }

  return string(reinterpret_cast<const char*>(&own_data[0]));
}

vector<string> CiffEntry::getStrings() {
  vector<string> strs;
  if (type != CIFF_ASCII)
    ThrowCPE("Wrong type 0x%x encountered. Expected Ascii", type);
  if (!own_data) {
    own_data = new uchar8[count];
    memcpy(own_data, data, count);
    own_data[count-1] = 0;  // Ensure string is not larger than count defines
  }
  uint32 start = 0;
  for (uint32 i=0; i< count; i++) {
    if (own_data[i] == 0) {
      strs.emplace_back(reinterpret_cast<const char*>(&own_data[start]));
      start = i+1;
    }
  }
  return strs;
}

bool __attribute__((pure)) CiffEntry::isString() {
  return (type == CIFF_ASCII);
}

void CiffEntry::setData( const void *in_data, uint32 byte_count )
{
  if (byte_count > bytesize)
    ThrowCPE("data set larger than entry size given");

  if (!own_data) {
    own_data = new uchar8[bytesize];
    memcpy(own_data, data, bytesize);
  }
  memcpy(own_data, in_data, byte_count);
}

#ifdef _MSC_VER
#pragma warning(disable: 4996) // this function or variable may be unsafe
#endif

std::string CiffEntry::getValueAsString()
{
  if (type == CIFF_ASCII)
    return string(reinterpret_cast<const char*>(&data[0]));
  auto *temp_string = new char[4096];
  if (count == 1) {
    switch (type) {
      case CIFF_LONG:
        sprintf(temp_string, "Long: %u (0x%x)", getU32(), getU32());
        break;
      case CIFF_SHORT:
        sprintf(temp_string, "Short: %u (0x%x)", getU32(), getU32());
        break;
      case CIFF_BYTE:
        sprintf(temp_string, "Byte: %u (0x%x)", getU32(), getU32());
        break;
      default:
        sprintf(temp_string, "Type: %x: ", type);
        for (uint32 i = 0; i < getElementSize(); i++) {
          sprintf(&temp_string[strlen(temp_string-1)], "%x", data[i]);
        }
    }
  }
  string ret(temp_string);
  delete [] temp_string;
  return ret;
}

} // namespace rawspeed
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Sergii Pylypenko
 *
 * 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.
 */

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include "gfx.h"
#include "gui.h"
#include "input.h"
#include "scancodes.h"
#include "flash_kernel.h"

static struct supportedDevices_t
{
	const char * device;
	const char * download;
	const char * checksum;
	const char * flash;
	const char * clear_tmp;
}
supportedDevices[] =
{
	{
		"$APPDIR/busybox [ \"`getprop ro.product.device`\" = grouper -a \"`getprop ro.build.version.release`\" = 5.0.2 ] && echo Matched || $APPDIR/busybox [ \"`getprop ro.product.device`\" = nakasi -a \"`getprop ro.build.version.release`\" = 5.0.2 ] && echo Matched",
		"$APPDIR/wget --no-check-certificate -O boot.img 'https://github.com/pelya/android-keyboard-gadget/blob/e44670bdcbc8d6a6939e083fcefec067f11094a8/nexus7-2012-wifi-grouper/boot.img?raw=true' && echo Successful",
		"echo 'bb164ba3a76a6d2921414414a26c0498b7ce29de  boot.img' | $APPDIR/busybox sha1sum -c",
		"echo \"$APPDIR/busybox dd if=boot.img of=/dev/block/platform/sdhci-tegra.3/by-name/LNX && echo Successful\" | su",
		"rm boot.img"
	},
	{
		"$APPDIR/busybox [ \"`getprop ro.product.device`\" = grouper -a \"`getprop ro.build.version.release`\" = 4.4.4 ] && echo Matched || $APPDIR/busybox [ \"`getprop ro.product.device`\" = nakasi -a \"`getprop ro.build.version.release`\" = 4.4.4 ] && echo Matched",
		"$APPDIR/wget --no-check-certificate -O boot.img 'https://github.com/pelya/android-keyboard-gadget/blob/bfcefabcd60829866c23ad03ea43fd3166462468/nexus7-2012-wifi-grouper/boot.img?raw=true' && echo Successful",
		"echo '1b57049e0823f632f8c69bbde8f9dd632cad7e7b  boot.img' | $APPDIR/busybox sha1sum -c",
		"echo \"$APPDIR/busybox dd if=boot.img of=/dev/block/platform/sdhci-tegra.3/by-name/LNX && echo Successful\" | su",
		"rm boot.img"
	},
	{ NULL, NULL, NULL, NULL, NULL }
};

static int executeCommand(const char * cmd, const char *search)
{
	int success = 0;
	printf("executeCommand > %s", cmd);
	char buf[512] = "";
	FILE *ff = popen(cmd, "r");
	while( fgets(buf, sizeof(buf), ff) )
	{
		printf("executeCommand >> %s", buf);
		addDialogText(buf);
		mainLoop(true);
		if (strstr(buf, search) != NULL)
			success = 1;
	}
	pclose(ff);
	return success;
}

static int flashCustomKernelDialog(struct supportedDevices_t & dev)
{
	createDialog();
	addDialogText("You will need custom kernel to use this app.");
	addDialogText("Do you wish to download and flash custom kernel?");
	addDialogText("You will need root on your device.");
	addDialogText("If you don't have root, please follow this link:");
	addDialogText("");
	addDialogText("");
	addDialogUrlButton("https://github.com/pelya/android-keyboard-gadget");
	addDialogYesNoButtons();

	int result = 0;
	while( !getDialogResult(&result) )
		mainLoop(true);

	if( result == 0 )
		exit(0);

	createDialog();
	addDialogText("Downloading package...");
	mainLoop(true);
	if( !executeCommand(dev.download, "Successful") )
		showErrorMessage("Cannot download kernel, please check your network connectivity");

	addDialogText("Validating package...");
	mainLoop(true);
	if( !executeCommand(dev.checksum, "boot.img: OK") )
		showErrorMessage("Downloaded package was corrupted, please re-download it");

	createDialog();
	addDialogText("Custom kernel will be flashed to your device.");
	addDialogText("This kernel is EXPERIMENTAL, and comes WTIH NO WARRANTY.");
	addDialogText("Your device may become unstable, and reboot at random.");
	addDialogText("You will lose root, please root your device again.");
	addDialogText("");
	addDialogText("Do you wish to flash custom kernel to your device?");
	addDialogYesNoButtons();
	while( !getDialogResult(&result) )
		mainLoop(true);

	if( result == 0 )
		exit(0);

	result = executeCommand(dev.flash, "Successful");
	executeCommand(dev.clear_tmp, "-");
	if( result )
		showErrorMessage("Flashing kernel succeeded.\nPlease restart your device now.");
	else
		showErrorMessage("Flashing kernel failed.\nDo you have root installed on your device?");

	return 1;
}

int flashCustomKernel()
{
	int d;
	for( d = 0; supportedDevices[d].device; d++ )
		if( executeCommand(supportedDevices[d].device, "Matched") )
			return flashCustomKernelDialog(supportedDevices[d]);

	createDialog();
	addDialogText("You will need a custom kernel to use this app.");
	addDialogText("Prebuilt kernel is available only for Nexus 7 2012 WiFi");
	addDialogText("with Android 4.4.4 or 5.0.2.");
	addDialogText("You will need to compile and install the kernel yourself for other devices.");
	addDialogText("Compilation instructions are available here:");
	addDialogText("");
	addDialogUrlButton("https://github.com/pelya/android-keyboard-gadget");
	while( true )
		mainLoop(true);

	return 0;
}
<commit_msg>Updated dialog to flash boot image<commit_after>/*
 * Copyright (C) 2015 Sergii Pylypenko
 *
 * 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.
 */

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include "gfx.h"
#include "gui.h"
#include "input.h"
#include "scancodes.h"
#include "flash_kernel.h"

static struct supportedDevices_t
{
	const char * device;
	const char * download;
	const char * checksum;
	const char * flash;
	const char * clear_tmp;
}
supportedDevices[] =
{
	{
		"$APPDIR/busybox [ \"`getprop ro.product.device`\" = grouper -a \"`getprop ro.build.version.release`\" = 5.1.1 ] && echo Matched || $APPDIR/busybox [ \"`getprop ro.product.device`\" = nakasi -a \"`getprop ro.build.version.release`\" = 5.1.1 ] && echo Matched",
		"$APPDIR/wget --no-check-certificate -O boot.img 'https://github.com/pelya/android-keyboard-gadget/blob/8017463df1fc106852d2d4e2f04a0f26b6008bbe/nexus7-2012-wifi-grouper/boot.img?raw=true' && echo Successful",
		"echo '556b568734cc4c29b046a6b6b9a992ca31e09a96  boot.img' | $APPDIR/busybox sha1sum -c",
		"echo \"$APPDIR/busybox dd if=boot.img of=/dev/block/platform/sdhci-tegra.3/by-name/LNX && echo Successful\" | su",
		"rm boot.img"
	},
	{
		"$APPDIR/busybox [ \"`getprop ro.product.device`\" = grouper -a \"`getprop ro.build.version.release`\" = 5.0.2 ] && echo Matched || $APPDIR/busybox [ \"`getprop ro.product.device`\" = nakasi -a \"`getprop ro.build.version.release`\" = 5.0.2 ] && echo Matched",
		"$APPDIR/wget --no-check-certificate -O boot.img 'https://github.com/pelya/android-keyboard-gadget/blob/e44670bdcbc8d6a6939e083fcefec067f11094a8/nexus7-2012-wifi-grouper/boot.img?raw=true' && echo Successful",
		"echo 'bb164ba3a76a6d2921414414a26c0498b7ce29de  boot.img' | $APPDIR/busybox sha1sum -c",
		"echo \"$APPDIR/busybox dd if=boot.img of=/dev/block/platform/sdhci-tegra.3/by-name/LNX && echo Successful\" | su",
		"rm boot.img"
	},
	{
		"$APPDIR/busybox [ \"`getprop ro.product.device`\" = grouper -a \"`getprop ro.build.version.release`\" = 4.4.4 ] && echo Matched || $APPDIR/busybox [ \"`getprop ro.product.device`\" = nakasi -a \"`getprop ro.build.version.release`\" = 4.4.4 ] && echo Matched",
		"$APPDIR/wget --no-check-certificate -O boot.img 'https://github.com/pelya/android-keyboard-gadget/blob/bfcefabcd60829866c23ad03ea43fd3166462468/nexus7-2012-wifi-grouper/boot.img?raw=true' && echo Successful",
		"echo '1b57049e0823f632f8c69bbde8f9dd632cad7e7b  boot.img' | $APPDIR/busybox sha1sum -c",
		"echo \"$APPDIR/busybox dd if=boot.img of=/dev/block/platform/sdhci-tegra.3/by-name/LNX && echo Successful\" | su",
		"rm boot.img"
	},
	{ NULL, NULL, NULL, NULL, NULL }
};

static int executeCommand(const char * cmd, const char *search)
{
	int success = 0;
	printf("executeCommand > %s", cmd);
	char buf[512] = "";
	FILE *ff = popen(cmd, "r");
	while( fgets(buf, sizeof(buf), ff) )
	{
		printf("executeCommand >> %s", buf);
		addDialogText(buf);
		mainLoop(true);
		if (strstr(buf, search) != NULL)
			success = 1;
	}
	pclose(ff);
	return success;
}

static int flashCustomKernelDialog(struct supportedDevices_t & dev)
{
	createDialog();
	addDialogText("You will need custom kernel to use this app.");
	addDialogText("Do you wish to download and flash custom kernel?");
	addDialogText("You will need root on your device.");
	addDialogText("If you don't have root, please follow this link:");
	addDialogText("");
	addDialogText("");
	addDialogUrlButton("https://github.com/pelya/android-keyboard-gadget");
	addDialogYesNoButtons();

	int result = 0;
	while( !getDialogResult(&result) )
		mainLoop(true);

	if( result == 0 )
		exit(0);

	createDialog();
	addDialogText("Downloading package...");
	mainLoop(true);
	if( !executeCommand(dev.download, "Successful") )
		showErrorMessage("Cannot download kernel, please check your network connectivity");

	addDialogText("Validating package...");
	mainLoop(true);
	if( !executeCommand(dev.checksum, "boot.img: OK") )
		showErrorMessage("Downloaded package was corrupted, please re-download it");

	createDialog();
	addDialogText("Custom kernel will be flashed to your device.");
	addDialogText("This kernel is EXPERIMENTAL, and comes WTIH NO WARRANTY.");
	addDialogText("Your device may become unstable, and reboot at random.");
	addDialogText("You will lose root, please root your device again.");
	addDialogText("");
	addDialogText("Do you wish to flash custom kernel to your device?");
	addDialogYesNoButtons();
	while( !getDialogResult(&result) )
		mainLoop(true);

	if( result == 0 )
		exit(0);

	result = executeCommand(dev.flash, "Successful");
	executeCommand(dev.clear_tmp, "-");
	if( result )
		showErrorMessage("Flashing kernel succeeded.\nPlease restart your device now.");
	else
		showErrorMessage("Flashing kernel failed.\nDo you have root installed on your device?");

	return 1;
}

int flashCustomKernel()
{
	int d;
	for( d = 0; supportedDevices[d].device; d++ )
		if( executeCommand(supportedDevices[d].device, "Matched") )
			return flashCustomKernelDialog(supportedDevices[d]);

	createDialog();
	addDialogText("You will need a custom kernel to use this app.");
	addDialogText("Prebuilt kernel is available only for Nexus 7 2012 WiFi");
	addDialogText("with Android 4.4.4 or 5.0.2.");
	addDialogText("You will need to compile and install the kernel yourself for other devices.");
	addDialogText("Compilation instructions are available here:");
	addDialogText("");
	addDialogUrlButton("https://github.com/pelya/android-keyboard-gadget");
	while( true )
		mainLoop(true);

	return 0;
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
// Name:      managedframe.cpp
// Purpose:   Implementation of wxExManagedFrame class.
// Author:    Anton van Wezenbeek
// Created:   2010-04-11
// RCS-ID:    $Id$
// Copyright: (c) 2010 Anton van Wezenbeek
////////////////////////////////////////////////////////////////////////////////

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/extension/managedframe.h>
#include <wx/extension/stcfile.h>
#include <wx/extension/toolbar.h>

#if wxUSE_GUI

#if wxUSE_AUI
BEGIN_EVENT_TABLE(wxExManagedFrame, wxExFrame)
  EVT_MENU(wxID_PREFERENCES, wxExManagedFrame::OnCommand)
  EVT_MENU_RANGE(ID_VIEW_LOWEST, ID_VIEW_HIGHEST, wxExManagedFrame::OnCommand)
  EVT_UPDATE_UI_RANGE(ID_VIEW_LOWEST, ID_VIEW_HIGHEST, wxExManagedFrame::OnUpdateUI)
END_EVENT_TABLE()

wxExManagedFrame::wxExManagedFrame(wxWindow* parent,
  wxWindowID id,
  const wxString& title,
  long style,
  const wxString& name)
  : wxExFrame(parent, id, title, style, name)
{
  m_Manager.SetManagedWindow(this);

  CreateToolBar();
  CreateFindBar();
}

wxExManagedFrame::~wxExManagedFrame()
{
  m_Manager.UnInit();
}

void wxExManagedFrame::CreateFindBar(long style, wxWindowID id)
{
  wxExFindToolBar* findBar = new wxExFindToolBar(this,
    id,
    wxDefaultPosition,
    wxDefaultSize,
    style);

  GetManager().AddPane(findBar,
    wxAuiPaneInfo().Bottom().ToolbarPane().Name("FINDBAR").Caption(_("Find Bar")));
}

void wxExManagedFrame::CreateToolBar(long style, wxWindowID id)
{
  wxExToolBar* toolBar = new wxExToolBar(this,
    id,
    wxDefaultPosition,
    wxDefaultSize,
    style);

  toolBar->AddControls();

  DoAddControl(toolBar);

  GetManager().AddPane(toolBar,
    wxAuiPaneInfo().Top().ToolbarPane().Name("TOOLBAR").Caption(_("Tool Bar")));
}

void wxExManagedFrame::OnCommand(wxCommandEvent& event)
{
  switch (event.GetId())
  {
    case wxID_PREFERENCES:
      wxExSTCFile::ConfigDialog(this,
        _("Editor Options"),
        wxExSTCFile::STC_CONFIG_MODELESS |
        wxExSTCFile::STC_CONFIG_SIMPLE |
        wxExSTCFile::STC_CONFIG_WITH_APPLY,
        event.GetId());
    break;

    case ID_VIEW_FINDBAR: TogglePane("FINDBAR"); break;
    case ID_VIEW_TOOLBAR: TogglePane("TOOLBAR"); break;

    case ID_VIEW_MENUBAR:
      if (GetMenuBar()->IsShown())
      {
        SetMenuBar(NULL);
      }
      break;

    case ID_VIEW_STATUSBAR:
      GetStatusBar()->Show(!GetStatusBar()->IsShown());
      SendSizeEvent();
      break;

    default:
      wxFAIL;
  }
}

void wxExManagedFrame::OnUpdateUI(wxUpdateUIEvent& event)
{
  switch (event.GetId())
  {
    case ID_VIEW_FINDBAR:
      event.Check(GetManager().GetPane("FINDBAR").IsShown());
    break;

    case ID_VIEW_TOOLBAR:
      event.Check(GetManager().GetPane("TOOLBAR").IsShown());
    break;

    case ID_VIEW_MENUBAR:
      wxASSERT(GetMenuBar() != NULL);
      event.Check(GetMenuBar()->IsShown());
    break;

    case ID_VIEW_STATUSBAR:
      wxASSERT(GetStatusBar() != NULL);
      event.Check(GetStatusBar()->IsShown());
      break;

    default:
      wxFAIL;
  }
}

void wxExManagedFrame::TogglePane(const wxString& pane)
{
  wxAuiPaneInfo& info = m_Manager.GetPane(pane);

  wxASSERT(info.IsOk());

  info.IsShown() ? info.Hide(): info.Show();

  m_Manager.Update();
}
#endif // wxUSE_AUI
#endif // wxUSE_GUI
<commit_msg>fix for menubar NULL<commit_after>////////////////////////////////////////////////////////////////////////////////
// Name:      managedframe.cpp
// Purpose:   Implementation of wxExManagedFrame class.
// Author:    Anton van Wezenbeek
// Created:   2010-04-11
// RCS-ID:    $Id$
// Copyright: (c) 2010 Anton van Wezenbeek
////////////////////////////////////////////////////////////////////////////////

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/extension/managedframe.h>
#include <wx/extension/stcfile.h>
#include <wx/extension/toolbar.h>

#if wxUSE_GUI

#if wxUSE_AUI
BEGIN_EVENT_TABLE(wxExManagedFrame, wxExFrame)
  EVT_MENU(wxID_PREFERENCES, wxExManagedFrame::OnCommand)
  EVT_MENU_RANGE(ID_VIEW_LOWEST, ID_VIEW_HIGHEST, wxExManagedFrame::OnCommand)
  EVT_UPDATE_UI_RANGE(ID_VIEW_LOWEST, ID_VIEW_HIGHEST, wxExManagedFrame::OnUpdateUI)
END_EVENT_TABLE()

wxExManagedFrame::wxExManagedFrame(wxWindow* parent,
  wxWindowID id,
  const wxString& title,
  long style,
  const wxString& name)
  : wxExFrame(parent, id, title, style, name)
{
  m_Manager.SetManagedWindow(this);

  CreateToolBar();
  CreateFindBar();
}

wxExManagedFrame::~wxExManagedFrame()
{
  m_Manager.UnInit();
}

void wxExManagedFrame::CreateFindBar(long style, wxWindowID id)
{
  wxExFindToolBar* findBar = new wxExFindToolBar(this,
    id,
    wxDefaultPosition,
    wxDefaultSize,
    style);

  GetManager().AddPane(findBar,
    wxAuiPaneInfo().Bottom().ToolbarPane().Name("FINDBAR").Caption(_("Find Bar")));
}

void wxExManagedFrame::CreateToolBar(long style, wxWindowID id)
{
  wxExToolBar* toolBar = new wxExToolBar(this,
    id,
    wxDefaultPosition,
    wxDefaultSize,
    style);

  toolBar->AddControls();

  DoAddControl(toolBar);

  GetManager().AddPane(toolBar,
    wxAuiPaneInfo().Top().ToolbarPane().Name("TOOLBAR").Caption(_("Tool Bar")));
}

void wxExManagedFrame::OnCommand(wxCommandEvent& event)
{
  switch (event.GetId())
  {
    case wxID_PREFERENCES:
      wxExSTCFile::ConfigDialog(this,
        _("Editor Options"),
        wxExSTCFile::STC_CONFIG_MODELESS |
        wxExSTCFile::STC_CONFIG_SIMPLE |
        wxExSTCFile::STC_CONFIG_WITH_APPLY,
        event.GetId());
    break;

    case ID_VIEW_FINDBAR: TogglePane("FINDBAR"); break;
    case ID_VIEW_TOOLBAR: TogglePane("TOOLBAR"); break;

    case ID_VIEW_MENUBAR:
      if (GetMenuBar()->IsShown())
      {
        SetMenuBar(NULL);
      }
      break;

    case ID_VIEW_STATUSBAR:
      GetStatusBar()->Show(!GetStatusBar()->IsShown());
      SendSizeEvent();
      break;

    default:
      wxFAIL;
  }
}

void wxExManagedFrame::OnUpdateUI(wxUpdateUIEvent& event)
{
  switch (event.GetId())
  {
    case ID_VIEW_FINDBAR:
      event.Check(GetManager().GetPane("FINDBAR").IsShown());
    break;

    case ID_VIEW_TOOLBAR:
      event.Check(GetManager().GetPane("TOOLBAR").IsShown());
    break;

    case ID_VIEW_MENUBAR:
      if (GetMenuBar() != NULL)
      {
        event.Check(GetMenuBar()->IsShown());
      }
      else
      {
        event.Check(false);
      }
    break;

    case ID_VIEW_STATUSBAR:
      wxASSERT(GetStatusBar() != NULL);
      event.Check(GetStatusBar()->IsShown());
      break;

    default:
      wxFAIL;
  }
}

void wxExManagedFrame::TogglePane(const wxString& pane)
{
  wxAuiPaneInfo& info = m_Manager.GetPane(pane);

  wxASSERT(info.IsOk());

  info.IsShown() ? info.Hide(): info.Show();

  m_Manager.Update();
}
#endif // wxUSE_AUI
#endif // wxUSE_GUI
<|endoftext|>