<commit_before>// Copyright 2016 Google Inc.
//
// 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.
// 3. The name of the author may not be used to endorse or promote products
//    derived from this software without specific prior written permission.
//
// 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.

#include "third_party/pcsc-lite/naclport/server/src/public/pcsc_lite_server_web_port_service.h"

#include <stdint.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <string>
#include <thread>
#include <utility>

#include <google_smart_card_common/ipc_emulation.h>
#include <google_smart_card_common/logging/logging.h>
#include <google_smart_card_common/messaging/typed_message.h>
#include <google_smart_card_common/optional.h>
#include <google_smart_card_common/value.h>
#include <google_smart_card_common/value_conversion.h>

#include "server_sockets_manager.h"

// Include the C headers after all other includes, because the preprocessor
// definitions from them interfere with the symbols from the standard C++
// library.
extern "C" {
#include "winscard.h"
#include "debuglog.h"
#include "eventhandler.h"
#include "hotplug.h"
#include "readerfactory.h"
#include "sys_generic.h"
#include "winscard_svc.h"
}

// Old versions of Emscripten have buggy multi-threading - so bail out if the
// developer still hasn't updated their local Emscripten version.
#ifdef __EMSCRIPTEN__
#if __EMSCRIPTEN_major__ < 2 ||                                \
    (__EMSCRIPTEN_major__ == 2 && __EMSCRIPTEN_minor__ == 0 && \
     __EMSCRIPTEN_tiny__ < 31)
#error "Emscripten >=2.0.31 must be used"
#endif
#endif  // __EMSCRIPTEN__

namespace google_smart_card {

namespace {

PcscLiteServerWebPortService* g_pcsc_lite_server = nullptr;

constexpr char kLoggingPrefix[] = "[PC/SC-Lite NaCl port] ";

// Constants for message types that are sent to the JavaScript side. These
// strings must match the ones in reader-tracker.js.
constexpr char kReaderInitAddMessageType[] = "reader_init_add";
constexpr char kReaderFinishAddMessageType[] = "reader_finish_add";
constexpr char kReaderRemoveMessageType[] = "reader_remove";

// Message data for the message that notifies the JavaScript side that a reader
// is being added by the PC/SC-Lite daemon.
struct ReaderInitAddMessageData {
  std::string reader_name;
  int port;
  std::string device;
};

// Message data for the message that notifies the JavaScript side that a reader
// is completely added by the PC/SC-Lite daemon.
struct ReaderFinishAddMessageData {
  std::string reader_name;
  int port;
  std::string device;
  long return_code;
};

// Message data for the message that notifies the JavaScript side that a reader
// is removed by the PC/SC-Lite daemon.
struct ReaderRemoveMessageData {
  std::string reader_name;
  int port;
};

void PcscLiteServerDaemonThreadMain() {
  while (true) {
    GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "[daemon thread] "
                                << "Waiting for the new connected clients...";
    optional<int> server_socket_file_descriptor =
        PcscLiteServerSocketsManager::GetInstance()->WaitAndPop();
    if (!server_socket_file_descriptor) {
      // A shutdown signal received.
      GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix
                                  << "[daemon thread] Shutting down...";
      break;
    }

    GOOGLE_SMART_CARD_LOG_DEBUG
        << kLoggingPrefix << "[daemon thread] A new "
        << "client was connected, starting a handler thread...";
    // Note: even though the CreateContextThread function accepts its
    // server_socket_file_descriptor argument by pointer, it doesn't store the
    // pointer itself anywhere - so it's safe to use a local variable here.
    uint32_t server_socket_file_descriptor_unsigned =
        static_cast<uint32_t>(server_socket_file_descriptor.value());
    // FIXME(emaxx): Deal with cases when CreateContextThread returns errors.
    // Looks like it may happen legitimately when the abusive client(s) request
    // to establish too many requests. Probably, some limitation should be
    // applied to all clients.
    GOOGLE_SMART_CARD_CHECK(
        ::CreateContextThread(&server_socket_file_descriptor_unsigned) ==
        SCARD_S_SUCCESS);
  }

  // Clean up the structures and threads owned by the third-party PC/SC-Lite
  // code. This follows the code in the "if (AraKiri)" block in the
  // `SVCServiceRunLoop()` function in pcsc-lite/src/src/pcscdaemon.c.
  HPStopHotPluggables();
  SYS_Sleep(1);
  RFCleanupReaders();
  EHDeinitializeEventStructures();
  ContextsDeinitialize();
}

}  // namespace

template <>
StructValueDescriptor<ReaderInitAddMessageData>::Description
StructValueDescriptor<ReaderInitAddMessageData>::GetDescription() {
  // Note: Strings passed to WithField() below must match the property names in
  // reader-tracker.js.
  return Describe("ReaderInitAddMessageData")
      .WithField(&ReaderInitAddMessageData::reader_name, "readerName")
      .WithField(&ReaderInitAddMessageData::port, "port")
      .WithField(&ReaderInitAddMessageData::device, "device");
}

template <>
StructValueDescriptor<ReaderFinishAddMessageData>::Description
StructValueDescriptor<ReaderFinishAddMessageData>::GetDescription() {
  // Note: Strings passed to WithField() below must match the property names in
  // reader-tracker.js.
  return Describe("ReaderFinishAddMessageData")
      .WithField(&ReaderFinishAddMessageData::reader_name, "readerName")
      .WithField(&ReaderFinishAddMessageData::port, "port")
      .WithField(&ReaderFinishAddMessageData::device, "device")
      .WithField(&ReaderFinishAddMessageData::return_code, "returnCode");
}

template <>
StructValueDescriptor<ReaderRemoveMessageData>::Description
StructValueDescriptor<ReaderRemoveMessageData>::GetDescription() {
  // Note: Strings passed to WithField() below must match the property names in
  // reader-tracker.js.
  return Describe("ReaderRemoveMessageData")
      .WithField(&ReaderRemoveMessageData::reader_name, "readerName")
      .WithField(&ReaderRemoveMessageData::port, "port");
}

PcscLiteServerWebPortService::PcscLiteServerWebPortService(
    GlobalContext* global_context)
    : global_context_(global_context) {
  GOOGLE_SMART_CARD_CHECK(!g_pcsc_lite_server);
  g_pcsc_lite_server = this;
}

PcscLiteServerWebPortService::~PcscLiteServerWebPortService() {
  // If the daemon thread is joinable, it means `ShutDownAndWait()` wasn't
  // called, which is a violation of the contract.
  GOOGLE_SMART_CARD_CHECK(!daemon_thread_.joinable());

  GOOGLE_SMART_CARD_CHECK(g_pcsc_lite_server == this);
  g_pcsc_lite_server = nullptr;
}

// static
const PcscLiteServerWebPortService*
PcscLiteServerWebPortService::GetInstance() {
  GOOGLE_SMART_CARD_CHECK(g_pcsc_lite_server);
  return g_pcsc_lite_server;
}

void PcscLiteServerWebPortService::InitializeAndRunDaemonThread() {
  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "Initialization...";

  IpcEmulation::CreateGlobalInstance();
  PcscLiteServerSocketsManager::CreateGlobalInstance();

  ::SYS_InitRandom();

  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "Setting up PC/SC-Lite "
                              << "logging...";
  ::DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG);
#ifdef NDEBUG
  ::DebugLogSetLevel(PCSC_LOG_ERROR);
#else
  ::DebugLogSetLevel(PCSC_LOG_DEBUG);
  ::DebugLogSetCategory(DEBUG_CATEGORY_APDU | DEBUG_CATEGORY_SW);
#endif
  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "PC/SC-Lite logging was "
                              << "set up.";

  LONG return_code;

  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "Allocating reader "
                              << "structures...";
  return_code = ::RFAllocateReaderSpace(0);
  GOOGLE_SMART_CARD_LOG_DEBUG
      << kLoggingPrefix << "Reader structures "
      << "allocation finished with the following result: \""
      << ::pcsc_stringify_error(return_code) << "\".";
  GOOGLE_SMART_CARD_CHECK(return_code == SCARD_S_SUCCESS);

  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "Performing initial hot "
                              << "plug drivers search...";
  return_code = ::HPSearchHotPluggables();
  GOOGLE_SMART_CARD_LOG_DEBUG
      << kLoggingPrefix << "Initial hot plug "
      << "drivers search finished with the following result code: "
      << return_code << ".";
  GOOGLE_SMART_CARD_CHECK(return_code == 0);

  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "Registering for hot "
                              << "plug events...";
  // FIXME(emaxx): Currently this ends up on polling the libusb each second, as
  // it doesn't provide any way to subscribe for the device list change. But
  // it's possible to optimize this onto publisher-pattern-style implementation,
  // by handling the chrome.usb API events (see
  // <https://developer.chrome.com/apps/usb#Events>) and using them in a
  // replacement implementation of the currently used original hotplug_libusb.c
  // source file.
  return_code = ::HPRegisterForHotplugEvents();
  GOOGLE_SMART_CARD_LOG_DEBUG
      << kLoggingPrefix << "Registering for hot "
      << "plug events finished with the following result code: " << return_code
      << ".";
  GOOGLE_SMART_CARD_CHECK(return_code == 0);

  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "Allocating client "
                              << "structures...";
  return_code = ::ContextsInitialize(0, 0);
  GOOGLE_SMART_CARD_LOG_DEBUG
      << kLoggingPrefix << "Client structures "
      << "allocation finished with the following result code: " << return_code
      << "...";
  GOOGLE_SMART_CARD_CHECK(return_code == 1);

  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "Waiting for the readers "
                              << "initialization...";
  ::RFWaitForReaderInit();
  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "Waiting for the readers "
                              << "initialization finished.";

  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "Starting PC/SC-Lite "
                              << "daemon thread...";
  daemon_thread_ = std::thread(PcscLiteServerDaemonThreadMain);
  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "PC/SC-Lite daemon "
                              << "thread has started.";

  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "Initialization "
                              << "successfully finished.";
}

void PcscLiteServerWebPortService::ShutDownAndWait() {
  GOOGLE_SMART_CARD_LOG_DEBUG
      << kLoggingPrefix << "Shutting down the PC/SC-Lite daemon thread...";
  // This notifies the daemon thread to shut down.
  PcscLiteServerSocketsManager::GetInstance()->ShutDown();
  daemon_thread_.join();
  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix
                              << "The PC/SC-Lite daemon thread shut down.";

  // Shut down the global state created in `InitializeAndRunDaemonThread()`.
  PcscLiteServerSocketsManager::DestroyGlobalInstance();
  IpcEmulation::DestroyGlobalInstance();
}

void PcscLiteServerWebPortService::PostReaderInitAddMessage(
    const char* reader_name,
    int port,
    const char* device) const {
  ReaderInitAddMessageData message_data;
  message_data.reader_name = reader_name;
  message_data.port = port;
  message_data.device = device;
  PostMessage(kReaderInitAddMessageType,
              ConvertToValueOrDie(std::move(message_data)));
}

void PcscLiteServerWebPortService::PostReaderFinishAddMessage(
    const char* reader_name,
    int port,
    const char* device,
    long return_code) const {
  ReaderFinishAddMessageData message_data;
  message_data.reader_name = reader_name;
  message_data.port = port;
  message_data.device = device;
  message_data.return_code = return_code;
  PostMessage(kReaderFinishAddMessageType,
              ConvertToValueOrDie(std::move(message_data)));
}

void PcscLiteServerWebPortService::PostReaderRemoveMessage(
    const char* reader_name,
    int port) const {
  ReaderRemoveMessageData message_data;
  message_data.reader_name = reader_name;
  message_data.port = port;
  PostMessage(kReaderRemoveMessageType,
              ConvertToValueOrDie(std::move(message_data)));
}

void PcscLiteServerWebPortService::PostMessage(const char* type,
                                               Value message_data) const {
  TypedMessage typed_message;
  typed_message.type = type;
  typed_message.data = std::move(message_data);
  global_context_->PostMessageToJs(
      ConvertToValueOrDie(std::move(typed_message)));
}

}  // namespace google_smart_card
<commit_msg>Workaround PC/SC-Lite shutdown timing issues (#639)<commit_after>// Copyright 2016 Google Inc.
//
// 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.
// 3. The name of the author may not be used to endorse or promote products
//    derived from this software without specific prior written permission.
//
// 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.

#include "third_party/pcsc-lite/naclport/server/src/public/pcsc_lite_server_web_port_service.h"

#include <stdint.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <string>
#include <thread>
#include <utility>

#include <google_smart_card_common/ipc_emulation.h>
#include <google_smart_card_common/logging/logging.h>
#include <google_smart_card_common/messaging/typed_message.h>
#include <google_smart_card_common/optional.h>
#include <google_smart_card_common/value.h>
#include <google_smart_card_common/value_conversion.h>

#include "server_sockets_manager.h"

// Include the C headers after all other includes, because the preprocessor
// definitions from them interfere with the symbols from the standard C++
// library.
extern "C" {
#include "winscard.h"
#include "debuglog.h"
#include "eventhandler.h"
#include "hotplug.h"
#include "readerfactory.h"
#include "sys_generic.h"
#include "winscard_svc.h"
}

// Old versions of Emscripten have buggy multi-threading - so bail out if the
// developer still hasn't updated their local Emscripten version.
#ifdef __EMSCRIPTEN__
#if __EMSCRIPTEN_major__ < 2 ||                                \
    (__EMSCRIPTEN_major__ == 2 && __EMSCRIPTEN_minor__ == 0 && \
     __EMSCRIPTEN_tiny__ < 31)
#error "Emscripten >=2.0.31 must be used"
#endif
#endif  // __EMSCRIPTEN__

namespace google_smart_card {

namespace {

PcscLiteServerWebPortService* g_pcsc_lite_server = nullptr;

constexpr char kLoggingPrefix[] = "[PC/SC-Lite NaCl port] ";

// Constants for message types that are sent to the JavaScript side. These
// strings must match the ones in reader-tracker.js.
constexpr char kReaderInitAddMessageType[] = "reader_init_add";
constexpr char kReaderFinishAddMessageType[] = "reader_finish_add";
constexpr char kReaderRemoveMessageType[] = "reader_remove";

// Message data for the message that notifies the JavaScript side that a reader
// is being added by the PC/SC-Lite daemon.
struct ReaderInitAddMessageData {
  std::string reader_name;
  int port;
  std::string device;
};

// Message data for the message that notifies the JavaScript side that a reader
// is completely added by the PC/SC-Lite daemon.
struct ReaderFinishAddMessageData {
  std::string reader_name;
  int port;
  std::string device;
  long return_code;
};

// Message data for the message that notifies the JavaScript side that a reader
// is removed by the PC/SC-Lite daemon.
struct ReaderRemoveMessageData {
  std::string reader_name;
  int port;
};

void PcscLiteServerDaemonThreadMain() {
  while (true) {
    GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "[daemon thread] "
                                << "Waiting for the new connected clients...";
    optional<int> server_socket_file_descriptor =
        PcscLiteServerSocketsManager::GetInstance()->WaitAndPop();
    if (!server_socket_file_descriptor) {
      // A shutdown signal received.
      GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix
                                  << "[daemon thread] Shutting down...";
      break;
    }

    GOOGLE_SMART_CARD_LOG_DEBUG
        << kLoggingPrefix << "[daemon thread] A new "
        << "client was connected, starting a handler thread...";
    // Note: even though the CreateContextThread function accepts its
    // server_socket_file_descriptor argument by pointer, it doesn't store the
    // pointer itself anywhere - so it's safe to use a local variable here.
    uint32_t server_socket_file_descriptor_unsigned =
        static_cast<uint32_t>(server_socket_file_descriptor.value());
    // FIXME(emaxx): Deal with cases when CreateContextThread returns errors.
    // Looks like it may happen legitimately when the abusive client(s) request
    // to establish too many requests. Probably, some limitation should be
    // applied to all clients.
    GOOGLE_SMART_CARD_CHECK(
        ::CreateContextThread(&server_socket_file_descriptor_unsigned) ==
        SCARD_S_SUCCESS);
  }

  // Clean up the structures and threads owned by the third-party PC/SC-Lite
  // code. This follows the code in the "if (AraKiri)" block in the
  // `SVCServiceRunLoop()` function in pcsc-lite/src/src/pcscdaemon.c.
  HPStopHotPluggables();
  // TODO: Upstream's approach with a magic sleep is flaky: the background
  // thread might be still running after this point, causing crashes. Replace
  // this with a proper waiting mechanism.
  SYS_Sleep(5);
  RFCleanupReaders();
  EHDeinitializeEventStructures();
  ContextsDeinitialize();
}

}  // namespace

template <>
StructValueDescriptor<ReaderInitAddMessageData>::Description
StructValueDescriptor<ReaderInitAddMessageData>::GetDescription() {
  // Note: Strings passed to WithField() below must match the property names in
  // reader-tracker.js.
  return Describe("ReaderInitAddMessageData")
      .WithField(&ReaderInitAddMessageData::reader_name, "readerName")
      .WithField(&ReaderInitAddMessageData::port, "port")
      .WithField(&ReaderInitAddMessageData::device, "device");
}

template <>
StructValueDescriptor<ReaderFinishAddMessageData>::Description
StructValueDescriptor<ReaderFinishAddMessageData>::GetDescription() {
  // Note: Strings passed to WithField() below must match the property names in
  // reader-tracker.js.
  return Describe("ReaderFinishAddMessageData")
      .WithField(&ReaderFinishAddMessageData::reader_name, "readerName")
      .WithField(&ReaderFinishAddMessageData::port, "port")
      .WithField(&ReaderFinishAddMessageData::device, "device")
      .WithField(&ReaderFinishAddMessageData::return_code, "returnCode");
}

template <>
StructValueDescriptor<ReaderRemoveMessageData>::Description
StructValueDescriptor<ReaderRemoveMessageData>::GetDescription() {
  // Note: Strings passed to WithField() below must match the property names in
  // reader-tracker.js.
  return Describe("ReaderRemoveMessageData")
      .WithField(&ReaderRemoveMessageData::reader_name, "readerName")
      .WithField(&ReaderRemoveMessageData::port, "port");
}

PcscLiteServerWebPortService::PcscLiteServerWebPortService(
    GlobalContext* global_context)
    : global_context_(global_context) {
  GOOGLE_SMART_CARD_CHECK(!g_pcsc_lite_server);
  g_pcsc_lite_server = this;
}

PcscLiteServerWebPortService::~PcscLiteServerWebPortService() {
  // If the daemon thread is joinable, it means `ShutDownAndWait()` wasn't
  // called, which is a violation of the contract.
  GOOGLE_SMART_CARD_CHECK(!daemon_thread_.joinable());

  GOOGLE_SMART_CARD_CHECK(g_pcsc_lite_server == this);
  g_pcsc_lite_server = nullptr;
}

// static
const PcscLiteServerWebPortService*
PcscLiteServerWebPortService::GetInstance() {
  GOOGLE_SMART_CARD_CHECK(g_pcsc_lite_server);
  return g_pcsc_lite_server;
}

void PcscLiteServerWebPortService::InitializeAndRunDaemonThread() {
  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "Initialization...";

  IpcEmulation::CreateGlobalInstance();
  PcscLiteServerSocketsManager::CreateGlobalInstance();

  ::SYS_InitRandom();

  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "Setting up PC/SC-Lite "
                              << "logging...";
  ::DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG);
#ifdef NDEBUG
  ::DebugLogSetLevel(PCSC_LOG_ERROR);
#else
  ::DebugLogSetLevel(PCSC_LOG_DEBUG);
  ::DebugLogSetCategory(DEBUG_CATEGORY_APDU | DEBUG_CATEGORY_SW);
#endif
  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "PC/SC-Lite logging was "
                              << "set up.";

  LONG return_code;

  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "Allocating reader "
                              << "structures...";
  return_code = ::RFAllocateReaderSpace(0);
  GOOGLE_SMART_CARD_LOG_DEBUG
      << kLoggingPrefix << "Reader structures "
      << "allocation finished with the following result: \""
      << ::pcsc_stringify_error(return_code) << "\".";
  GOOGLE_SMART_CARD_CHECK(return_code == SCARD_S_SUCCESS);

  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "Performing initial hot "
                              << "plug drivers search...";
  return_code = ::HPSearchHotPluggables();
  GOOGLE_SMART_CARD_LOG_DEBUG
      << kLoggingPrefix << "Initial hot plug "
      << "drivers search finished with the following result code: "
      << return_code << ".";
  GOOGLE_SMART_CARD_CHECK(return_code == 0);

  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "Registering for hot "
                              << "plug events...";
  // FIXME(emaxx): Currently this ends up on polling the libusb each second, as
  // it doesn't provide any way to subscribe for the device list change. But
  // it's possible to optimize this onto publisher-pattern-style implementation,
  // by handling the chrome.usb API events (see
  // <https://developer.chrome.com/apps/usb#Events>) and using them in a
  // replacement implementation of the currently used original hotplug_libusb.c
  // source file.
  return_code = ::HPRegisterForHotplugEvents();
  GOOGLE_SMART_CARD_LOG_DEBUG
      << kLoggingPrefix << "Registering for hot "
      << "plug events finished with the following result code: " << return_code
      << ".";
  GOOGLE_SMART_CARD_CHECK(return_code == 0);

  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "Allocating client "
                              << "structures...";
  return_code = ::ContextsInitialize(0, 0);
  GOOGLE_SMART_CARD_LOG_DEBUG
      << kLoggingPrefix << "Client structures "
      << "allocation finished with the following result code: " << return_code
      << "...";
  GOOGLE_SMART_CARD_CHECK(return_code == 1);

  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "Waiting for the readers "
                              << "initialization...";
  ::RFWaitForReaderInit();
  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "Waiting for the readers "
                              << "initialization finished.";

  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "Starting PC/SC-Lite "
                              << "daemon thread...";
  daemon_thread_ = std::thread(PcscLiteServerDaemonThreadMain);
  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "PC/SC-Lite daemon "
                              << "thread has started.";

  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix << "Initialization "
                              << "successfully finished.";
}

void PcscLiteServerWebPortService::ShutDownAndWait() {
  GOOGLE_SMART_CARD_LOG_DEBUG
      << kLoggingPrefix << "Shutting down the PC/SC-Lite daemon thread...";
  // This notifies the daemon thread to shut down.
  PcscLiteServerSocketsManager::GetInstance()->ShutDown();
  daemon_thread_.join();
  GOOGLE_SMART_CARD_LOG_DEBUG << kLoggingPrefix
                              << "The PC/SC-Lite daemon thread shut down.";

  // Shut down the global state created in `InitializeAndRunDaemonThread()`.
  PcscLiteServerSocketsManager::DestroyGlobalInstance();
  IpcEmulation::DestroyGlobalInstance();
}

void PcscLiteServerWebPortService::PostReaderInitAddMessage(
    const char* reader_name,
    int port,
    const char* device) const {
  ReaderInitAddMessageData message_data;
  message_data.reader_name = reader_name;
  message_data.port = port;
  message_data.device = device;
  PostMessage(kReaderInitAddMessageType,
              ConvertToValueOrDie(std::move(message_data)));
}

void PcscLiteServerWebPortService::PostReaderFinishAddMessage(
    const char* reader_name,
    int port,
    const char* device,
    long return_code) const {
  ReaderFinishAddMessageData message_data;
  message_data.reader_name = reader_name;
  message_data.port = port;
  message_data.device = device;
  message_data.return_code = return_code;
  PostMessage(kReaderFinishAddMessageType,
              ConvertToValueOrDie(std::move(message_data)));
}

void PcscLiteServerWebPortService::PostReaderRemoveMessage(
    const char* reader_name,
    int port) const {
  ReaderRemoveMessageData message_data;
  message_data.reader_name = reader_name;
  message_data.port = port;
  PostMessage(kReaderRemoveMessageType,
              ConvertToValueOrDie(std::move(message_data)));
}

void PcscLiteServerWebPortService::PostMessage(const char* type,
                                               Value message_data) const {
  TypedMessage typed_message;
  typed_message.type = type;
  typed_message.data = std::move(message_data);
  global_context_->PostMessageToJs(
      ConvertToValueOrDie(std::move(typed_message)));
}

}  // namespace google_smart_card
<|endoftext|>


<commit_before>#include "Dealer.h"

/*
namespace Blackjack
{
	class Dealer: public Player
	{//A Blackjack dealer.
		private:
			std::vector<Player*> players;//A vector of the players. I have them stored as pointers so that it can store subclasses of Player.

		public:
			//Dealer();//Default Constructor.
			~Dealer();//Default Destructor. Frees all the player pointers.
			//void deal();//Deal cards to players.
			void startGame();//Starts the players playing.
			void addUserPlayer( std::string newName );//Registers a new user's player for the game. newName is the name of the new player.
			void addAutoPlayer( std::string newName );//Registers a new automatic player for the game. newName is the name of the new player.
			Card getRandomCard();//Returns a randomly valued card.
			void play();//Play a hand as the dealer.
	};
}
*/
namespace Blackjack
{
	Dealer::Dealer()
	{//Default Constructor.
		//Create a new hand.
		Hand newHand;//Create the hand object itself.
		newHand.addCard( myDealer->getRandomCard() );//Get the first random card of the hand.
		newHand.addCard( myDealer->getRandomCard() );//Get the second random card of the hand.
		collHands.addHand( newHand );//Add the new hand to the collection of hands.
	}

	Dealer::~Dealer()
	{//Default Destructor. Frees all the player pointers.
		for( std::vector<Player*>::iterator i = players.begin(); i != players.end(); i++ )
		{//Iterate through each element in the players vector and delete each one.
			delete *i;
		}

		players.clear();//Remove all the deleted pointers from the players vector.
	}

	void Dealer::startGame()
	{//Starts the players playing.
		while( players.size() > 0 )
		{
			std::vector<Player*>::iterator pit

			for( pit = players.begin(); pit != players.end(); pit++ )
			{//Go through the players and have each them play a hand.
				(*pit)->play();
			}

			//Play a hand as the dealer.
			play();

			pit = players.begin();
			while( pit != players.end() )
			{//Go through the players and count up the winnings/losses and ask each if they want to quit.

				std::cout << "Winnings and losses to be programmed later..." << std::endl;
				//TODO: finish the calculations of winnings and losses.

				if( (*pit)->askQuit() == playReturnValues.quitPlaying )
				{//Ask if the player wants to quit.
					pit = players.erase( pit );//Erase the plaer and get the new iterator.
				}
				else
				{//The player didn't want to quit, so just move on.
					pit++;
				}
			}
		}
	}

	void Dealer::addUserPlayer( std::string newName )
	{//Registers a new user's player for the game. newName is the name of the new player.
		players.push_back( new UserPlayer(newName) );
	}

	void Dealer::addAutoPlayer( std::string newName )
	{//Registers a new automatic player for the game. newName is the name of the new player.
		players.push_back( new AutoPlayer(newName) );
	}

	Card Dealer::getRandomCard()
	{//Returns a randomly valued card.
		Card randomCard( static_cast<Rank>(0,12), static_cast<Suit>(0,3) );
		return randomCard;
	}

	Card Dealer::getDealerCard()
	{//Returns one of the dealer's card for the player to see.
		return (*collHands.begin()).getCard(1);//Return the first card of the first hand.
	}

	void Dealer::play()
	{//Play a hand as the dealer.
		std::cout << "The dealer doesn't know how to play yet." << std::endl;
		//TODO: finish this method.
	}

	int Dealer::askQuit()
	{//Just returns keep playing every time.
		return playReturnValues.keepPlaying;
	}
}
<commit_msg>Added some code for the play method of the Dealer class.<commit_after>#include "Dealer.h"

/*
namespace Blackjack
{
	class Dealer: public Player
	{//A Blackjack dealer.
		private:
			std::vector<Player*> players;//A vector of the players. I have them stored as pointers so that it can store subclasses of Player.

		public:
			//Dealer();//Default Constructor.
			~Dealer();//Default Destructor. Frees all the player pointers.
			//void deal();//Deal cards to players.
			void startGame();//Starts the players playing.
			void addUserPlayer( std::string newName );//Registers a new user's player for the game. newName is the name of the new player.
			void addAutoPlayer( std::string newName );//Registers a new automatic player for the game. newName is the name of the new player.
			Card getRandomCard();//Returns a randomly valued card.
			void play();//Play a hand as the dealer.
	};
}
*/
namespace Blackjack
{
	Dealer::Dealer()
	{//Default Constructor.
		//Create a new hand.
		Hand newHand;//Create the hand object itself.
		newHand.addCard( myDealer->getRandomCard() );//Get the first random card of the hand.
		newHand.addCard( myDealer->getRandomCard() );//Get the second random card of the hand.
		collHands.addHand( newHand );//Add the new hand to the collection of hands.
	}

	Dealer::~Dealer()
	{//Default Destructor. Frees all the player pointers.
		for( std::vector<Player*>::iterator i = players.begin(); i != players.end(); i++ )
		{//Iterate through each element in the players vector and delete each one.
			delete *i;
		}

		players.clear();//Remove all the deleted pointers from the players vector.
	}

	void Dealer::startGame()
	{//Starts the players playing.
		while( players.size() > 0 )
		{
			std::vector<Player*>::iterator pit

			for( pit = players.begin(); pit != players.end(); pit++ )
			{//Go through the players and have each them play a hand.
				(*pit)->play();
			}

			//Play a hand as the dealer.
			play();

			pit = players.begin();
			while( pit != players.end() )
			{//Go through the players and count up the winnings/losses and ask each if they want to quit.

				std::cout << "Winnings and losses to be programmed later..." << std::endl;
				//TODO: finish the calculations of winnings and losses.

				if( (*pit)->askQuit() == playReturnValues.quitPlaying )
				{//Ask if the player wants to quit.
					pit = players.erase( pit );//Erase the plaer and get the new iterator.
				}
				else
				{//The player didn't want to quit, so just move on.
					pit++;
				}
			}
		}
	}

	void Dealer::addUserPlayer( std::string newName )
	{//Registers a new user's player for the game. newName is the name of the new player.
		players.push_back( new UserPlayer(newName) );
	}

	void Dealer::addAutoPlayer( std::string newName )
	{//Registers a new automatic player for the game. newName is the name of the new player.
		players.push_back( new AutoPlayer(newName) );
	}

	Card Dealer::getRandomCard()
	{//Returns a randomly valued card.
		Card randomCard( static_cast<Rank>(0,12), static_cast<Suit>(0,3) );
		return randomCard;
	}

	Card Dealer::getDealerCard()
	{//Returns one of the dealer's card for the player to see.
		return (*collHands.begin()).getCard(1);//Return the first card of the first hand.
	}

	void Dealer::play()
	{//Play a hand as the dealer.
		if( collHands.numHands()  == 0 )
		{//If there aren't any hands yet, create the first one so that play can start.
			Hand newHand;//Create the hand object itself.
			newHand.addCard( myDealer->getRandomCard() );//Get the first random card of the hand.
			newHand.addCard( myDealer->getRandomCard() );//Get the second random card of the hand.
			collHands.addHand( newHand );//Add the new hand to the collection of hands.
		}

		for( HandList::iterator itr = collHands.begin(); itr != collHands.end(); itr++ )
		{//Play each hand by iteration through them.
			bool doneWithThisHand = false;//Used to keep track of wether the dealer has decided to stop playing this hand.

			while( (doneWithThisHand != true) && (*itr.getMaxPointsAtOrBelow21() < 21) )
			{//While the dealer hasn't decided to stop playing this hand and the hand is below 21 points, keep playing this hand.
				std::cout << "Dealer's hand: " << *itr << std::endl;//Print out the hand.
				std::cout << "Dealer's points: " << *itr.getMaxPointsAtOrBelow21() << std::endl;//Print out the number of points.

				if( *itr.getMaxPointsAtOrBelow21() < 17 )
				{//If the points for this hand are below 17, hit.
					(*itr).addCard( myDealer->getRandomCard() );//Put in a random card.
				}
				else
				{//The dealer wants to stand, so done with this hand.
					doneWithThisHand = true;
				}
			}

			//Print out the hand at the end of the play
			std::cout << "Dealer's hand: " << std::endl;
			std::cout << *itr << std::endl;//Print out the hand.
			std::cout << "Dealer's points: " << (*itr).getMaxPointsAtOrBelow21() << std::endl;//Print out the number of points.
		}
	}

	int Dealer::askQuit()
	{//Just returns keep playing every time.
		return playReturnValues.keepPlaying;
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008-2012 The QXmpp developers
 *
 * Authors:
 *  Olivier Goffart
 *  Jeremy Lainé
 *
 * Source:
 *  http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * 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.1 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.
 *
 */

#include "QXmppPresence.h"

#include "presence.h"
#include "tests.h"

void tst_QXmppPresence::testPresence_data()
{
    QXmppPresence foo;

    QTest::addColumn<QByteArray>("xml");
    QTest::addColumn<int>("type");
    QTest::addColumn<int>("priority");
    QTest::addColumn<int>("statusType");
    QTest::addColumn<QString>("statusText");
    QTest::addColumn<int>("vcardUpdate");
    QTest::addColumn<QByteArray>("photoHash");

    QTest::newRow("empty") << QByteArray("<presence/>") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray();
    QTest::newRow("unavailable") << QByteArray("<presence type=\"unavailable\"/>") << int(QXmppPresence::Unavailable) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray();
    QTest::newRow("error") << QByteArray("<presence type=\"error\"/>") << int(QXmppPresence::Error) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray();

    QTest::newRow("full") << QByteArray("<presence><show>away</show><status>In a meeting</status><priority>5</priority></presence>") << int(QXmppPresence::Available) << 5 << int(QXmppPresence::Away) << "In a meeting" << int(QXmppPresence::VCardUpdateNone) << QByteArray();

    // status type
    QTest::newRow("away") << QByteArray("<presence><show>away</show></presence>") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::Away) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray();
    QTest::newRow("dnd") << QByteArray("<presence><show>dnd</show></presence>") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::DND) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray();
    QTest::newRow("chat") << QByteArray("<presence><show>chat</show></presence>") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::Chat) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray();
    QTest::newRow("xa") << QByteArray("<presence><show>xa</show></presence>") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::XA) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray();
    QTest::newRow("invisible") << QByteArray("<presence><show>invisible</show></presence>") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::Invisible) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray();

    QTest::newRow("vcard-photo") << QByteArray(
        "<presence>"
        "<x xmlns=\"vcard-temp:x:update\">"
        "<photo>73b908bc</photo>"
        "</x>"
        "</presence>") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateValidPhoto) << QByteArray::fromHex("73b908bc");

    QTest::newRow("vard-not-ready") << QByteArray(
        "<presence>"
        "<x xmlns=\"vcard-temp:x:update\"/>"
        "</presence>") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateNotReady) << QByteArray();
}

void tst_QXmppPresence::testPresence()
{
    QFETCH(QByteArray, xml);
    QFETCH(int, type);
    QFETCH(int, priority);
    QFETCH(int, statusType);
    QFETCH(QString, statusText);
    QFETCH(int, vcardUpdate);
    QFETCH(QByteArray, photoHash);

    QXmppPresence presence;
    parsePacket(presence, xml);
    QCOMPARE(int(presence.type()), type);
    QCOMPARE(presence.priority(), priority);
    QCOMPARE(int(presence.availableStatusType()), statusType);
    QCOMPARE(presence.statusText(), statusText);
    QCOMPARE(int(presence.vCardUpdateType()), vcardUpdate);
    QCOMPARE(presence.photoHash(), photoHash);

    // legacy
    QCOMPARE(presence.status().priority(), priority);
    QCOMPARE(int(presence.status().type()), statusType);
    QCOMPARE(presence.status().statusText(), statusText);

    serializePacket(presence, xml);
}

void tst_QXmppPresence::testPresenceWithCapability()
{
    const QByteArray xml(
        "<presence to=\"foo@example.com/QXmpp\" from=\"bar@example.com/QXmpp\">"
        "<show>away</show>"
        "<status>In a meeting</status>"
        "<priority>5</priority>"
        "<x xmlns=\"vcard-temp:x:update\">"
        "<photo>73b908bc</photo>"
        "</x>"
        "<c xmlns=\"http://jabber.org/protocol/caps\" hash=\"sha-1\" node=\"http://code.google.com/p/qxmpp\" ver=\"QgayPKawpkPSDYmwT/WM94uAlu0=\"/>"
        "</presence>");

    QXmppPresence presence;
    parsePacket(presence, xml);
    QCOMPARE(presence.to(), QString("foo@example.com/QXmpp"));
    QCOMPARE(presence.from(), QString("bar@example.com/QXmpp"));
    QCOMPARE(presence.availableStatusType(), QXmppPresence::Away);
    QCOMPARE(presence.statusText(), QString("In a meeting"));
    QCOMPARE(presence.priority(), 5);
    QCOMPARE(presence.photoHash(), QByteArray::fromHex("73b908bc"));
    QCOMPARE(presence.vCardUpdateType(), QXmppPresence::VCardUpdateValidPhoto);
    QCOMPARE(presence.capabilityHash(), QString("sha-1"));
    QCOMPARE(presence.capabilityNode(), QString("http://code.google.com/p/qxmpp"));
    QCOMPARE(presence.capabilityVer(), QByteArray::fromBase64("QgayPKawpkPSDYmwT/WM94uAlu0="));

    serializePacket(presence, xml);
}

void tst_QXmppPresence::testPresenceWithMuc()
{
    const QByteArray xml(
        "<presence "
            "to=\"pistol@shakespeare.lit/harfleur\" "
            "from=\"harfleur@henryv.shakespeare.lit/pistol\" "
            "type=\"unavailable\">"
            "<x xmlns=\"http://jabber.org/protocol/muc#user\">"
            "<item affiliation=\"none\" role=\"none\">"
                "<actor jid=\"fluellen@shakespeare.lit\"/>"
                "<reason>Avaunt, you cullion!</reason>"
            "</item>"
            "<status code=\"307\"/>"
            "</x>"
        "</presence>");

    QXmppPresence presence;
    parsePacket(presence, xml);
    QCOMPARE(presence.to(), QLatin1String("pistol@shakespeare.lit/harfleur"));
    QCOMPARE(presence.from(), QLatin1String("harfleur@henryv.shakespeare.lit/pistol"));
    QCOMPARE(presence.type(), QXmppPresence::Unavailable);
    QCOMPARE(presence.mucItem().actor(), QLatin1String("fluellen@shakespeare.lit"));
    QCOMPARE(presence.mucItem().affiliation(), QXmppMucItem::NoAffiliation);
    QCOMPARE(presence.mucItem().jid(), QString());
    QCOMPARE(presence.mucItem().reason(), QLatin1String("Avaunt, you cullion!"));
    QCOMPARE(presence.mucItem().role(), QXmppMucItem::NoRole);
    QCOMPARE(presence.mucStatusCodes(), QList<int>() << 307);
    serializePacket(presence, xml);
}

<commit_msg>improve presence test coverage<commit_after>/*
 * Copyright (C) 2008-2012 The QXmpp developers
 *
 * Authors:
 *  Olivier Goffart
 *  Jeremy Lainé
 *
 * Source:
 *  http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * 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.1 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.
 *
 */

#include "QXmppPresence.h"

#include "presence.h"
#include "tests.h"

void tst_QXmppPresence::testPresence_data()
{
    QXmppPresence foo;

    QTest::addColumn<QByteArray>("xml");
    QTest::addColumn<int>("type");
    QTest::addColumn<int>("priority");
    QTest::addColumn<int>("statusType");
    QTest::addColumn<QString>("statusText");
    QTest::addColumn<int>("vcardUpdate");
    QTest::addColumn<QByteArray>("photoHash");

    // presence type
    QTest::newRow("available") << QByteArray("<presence/>") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray();
    QTest::newRow("unavailable") << QByteArray("<presence type=\"unavailable\"/>") << int(QXmppPresence::Unavailable) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray();
    QTest::newRow("error") << QByteArray("<presence type=\"error\"/>") << int(QXmppPresence::Error) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray();
    QTest::newRow("subscribe") << QByteArray("<presence type=\"subscribe\"/>") << int(QXmppPresence::Subscribe) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray();
    QTest::newRow("unsubscribe") << QByteArray("<presence type=\"unsubscribe\"/>") << int(QXmppPresence::Unsubscribe) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray();
    QTest::newRow("subscribed") << QByteArray("<presence type=\"subscribed\"/>") << int(QXmppPresence::Subscribed) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray();
    QTest::newRow("unsubscribed") << QByteArray("<presence type=\"unsubscribed\"/>") << int(QXmppPresence::Unsubscribed) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray();
    QTest::newRow("probe") << QByteArray("<presence type=\"probe\"/>") << int(QXmppPresence::Probe) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray();

    // status text + priority
    QTest::newRow("full") << QByteArray("<presence><show>away</show><status>In a meeting</status><priority>5</priority></presence>") << int(QXmppPresence::Available) << 5 << int(QXmppPresence::Away) << "In a meeting" << int(QXmppPresence::VCardUpdateNone) << QByteArray();

    // status type
    QTest::newRow("away") << QByteArray("<presence><show>away</show></presence>") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::Away) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray();
    QTest::newRow("dnd") << QByteArray("<presence><show>dnd</show></presence>") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::DND) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray();
    QTest::newRow("chat") << QByteArray("<presence><show>chat</show></presence>") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::Chat) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray();
    QTest::newRow("xa") << QByteArray("<presence><show>xa</show></presence>") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::XA) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray();
    QTest::newRow("invisible") << QByteArray("<presence><show>invisible</show></presence>") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::Invisible) << "" << int(QXmppPresence::VCardUpdateNone) << QByteArray();

    // photo
    QTest::newRow("vcard-photo") << QByteArray(
        "<presence>"
        "<x xmlns=\"vcard-temp:x:update\">"
        "<photo>73b908bc</photo>"
        "</x>"
        "</presence>") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateValidPhoto) << QByteArray::fromHex("73b908bc");

    QTest::newRow("vard-not-ready") << QByteArray(
        "<presence>"
        "<x xmlns=\"vcard-temp:x:update\"/>"
        "</presence>") << int(QXmppPresence::Available) << 0 << int(QXmppPresence::Online) << "" << int(QXmppPresence::VCardUpdateNotReady) << QByteArray();
}

void tst_QXmppPresence::testPresence()
{
    QFETCH(QByteArray, xml);
    QFETCH(int, type);
    QFETCH(int, priority);
    QFETCH(int, statusType);
    QFETCH(QString, statusText);
    QFETCH(int, vcardUpdate);
    QFETCH(QByteArray, photoHash);

    QXmppPresence presence;
    parsePacket(presence, xml);
    QCOMPARE(int(presence.type()), type);
    QCOMPARE(presence.priority(), priority);
    QCOMPARE(int(presence.availableStatusType()), statusType);
    QCOMPARE(presence.statusText(), statusText);
    QCOMPARE(int(presence.vCardUpdateType()), vcardUpdate);
    QCOMPARE(presence.photoHash(), photoHash);

    // legacy
    QCOMPARE(presence.status().priority(), priority);
    QCOMPARE(int(presence.status().type()), statusType);
    QCOMPARE(presence.status().statusText(), statusText);

    serializePacket(presence, xml);
}

void tst_QXmppPresence::testPresenceWithCapability()
{
    const QByteArray xml(
        "<presence to=\"foo@example.com/QXmpp\" from=\"bar@example.com/QXmpp\">"
        "<show>away</show>"
        "<status>In a meeting</status>"
        "<priority>5</priority>"
        "<x xmlns=\"vcard-temp:x:update\">"
        "<photo>73b908bc</photo>"
        "</x>"
        "<c xmlns=\"http://jabber.org/protocol/caps\" hash=\"sha-1\" node=\"http://code.google.com/p/qxmpp\" ver=\"QgayPKawpkPSDYmwT/WM94uAlu0=\"/>"
        "</presence>");

    QXmppPresence presence;
    parsePacket(presence, xml);
    QCOMPARE(presence.to(), QString("foo@example.com/QXmpp"));
    QCOMPARE(presence.from(), QString("bar@example.com/QXmpp"));
    QCOMPARE(presence.availableStatusType(), QXmppPresence::Away);
    QCOMPARE(presence.statusText(), QString("In a meeting"));
    QCOMPARE(presence.priority(), 5);
    QCOMPARE(presence.photoHash(), QByteArray::fromHex("73b908bc"));
    QCOMPARE(presence.vCardUpdateType(), QXmppPresence::VCardUpdateValidPhoto);
    QCOMPARE(presence.capabilityHash(), QString("sha-1"));
    QCOMPARE(presence.capabilityNode(), QString("http://code.google.com/p/qxmpp"));
    QCOMPARE(presence.capabilityVer(), QByteArray::fromBase64("QgayPKawpkPSDYmwT/WM94uAlu0="));

    serializePacket(presence, xml);
}

void tst_QXmppPresence::testPresenceWithMuc()
{
    const QByteArray xml(
        "<presence "
            "to=\"pistol@shakespeare.lit/harfleur\" "
            "from=\"harfleur@henryv.shakespeare.lit/pistol\" "
            "type=\"unavailable\">"
            "<x xmlns=\"http://jabber.org/protocol/muc#user\">"
            "<item affiliation=\"none\" role=\"none\">"
                "<actor jid=\"fluellen@shakespeare.lit\"/>"
                "<reason>Avaunt, you cullion!</reason>"
            "</item>"
            "<status code=\"307\"/>"
            "</x>"
        "</presence>");

    QXmppPresence presence;
    parsePacket(presence, xml);
    QCOMPARE(presence.to(), QLatin1String("pistol@shakespeare.lit/harfleur"));
    QCOMPARE(presence.from(), QLatin1String("harfleur@henryv.shakespeare.lit/pistol"));
    QCOMPARE(presence.type(), QXmppPresence::Unavailable);
    QCOMPARE(presence.mucItem().actor(), QLatin1String("fluellen@shakespeare.lit"));
    QCOMPARE(presence.mucItem().affiliation(), QXmppMucItem::NoAffiliation);
    QCOMPARE(presence.mucItem().jid(), QString());
    QCOMPARE(presence.mucItem().reason(), QLatin1String("Avaunt, you cullion!"));
    QCOMPARE(presence.mucItem().role(), QXmppMucItem::NoRole);
    QCOMPARE(presence.mucStatusCodes(), QList<int>() << 307);
    serializePacket(presence, xml);
}

<|endoftext|>


<commit_before>/*
 * main.cpp -- This file is part of primesieve
 *
 * Copyright (C) 2011 Kim Walisch, <kim.walisch@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 */

/**
 * @file  main.cpp
 * @brief Command-line version of primesieve, multi-threaded (OpenMP).
 * @see   http://primesieve.googlecode.com
 *
 * primesieve is a highly optimized implementation of the sieve of
 * Eratosthenes that generates prime numbers and prime k-tuplets (twin
 * primes, prime triplets, ...) up to 2^64 maximum.
 */

#include "../soe/ParallelPrimeSieve.h"
#include "../expr/ExpressionParser.h"

/// declared in test.cpp
void test();

#include <stdint.h>
#include <exception>
#include <iostream>
#include <string>
#include <vector>
#include <cctype>  /* std::tolower(int) */
#include <iomanip> /* std::setw(int) */

namespace {
  enum {
    OPTION_ERROR,
    OPTION_HELP,
    OPTION_SIEVE,
    OPTION_TEST,
    OPTION_VERSION
  };

  std::vector<uint64_t> numbers; /* start and stop number for sieving */
  uint32_t sieveSize     = 0;    /* sieve size in KiloBytes */
  uint32_t flags         = 0;    /* settings */
  bool quietMode         = false;
  bool showParserResults = false;
  int threads            = ParallelPrimeSieve::USE_IDEAL_NUM_THREADS;
  int maxThreads         = ParallelPrimeSieve::getMaxThreads();

  // Unfortunately there is no easy way to get the CPU L1 and L2 cache
  // size, these values are close for most x86-64 CPUs in 2011
  const uint32_t L1_CACHE_SIZE = 64;
  const uint32_t L2_CACHE_SIZE = 512;
  const uint64_t L2_THRESHOLD  = static_cast<uint64_t> (1E13);
}

void help() {
  std::cout << "Usage: primesieve START STOP [OPTION]..." << std::endl
            << "Use the sieve of Eratosthenes to find the prime numbers and prime" << std::endl
            << "k-tuplets between START and STOP < 2^64" << std::endl
            << std::endl
            << "Examples:" << std::endl
            << "  primesieve 1 10000000 -p1" << std::endl
            << "  primesieve 1 1e11 -s 32" << std::endl
            << "  primesieve 1e18 1e18+2**32 -c1234567" << std::endl
            << std::endl
            << "Options:" << std::endl
            << "  -c[N]        Count prime numbers and/or prime k-tuplets," << std::endl
            << "               e.g -c1 count prime numbers, -c3 count prime triplets, ..." << std::endl
            << "               N >= 1 and N <= 7" << std::endl
            << "  -p[N]        Print prime numbers or prime k-tuplets," << std::endl
            << "               e.g -p1 print prime numbers, -p2 print twin primes, ..." << std::endl
            << "               N >= 1 and N <= 7" << std::endl
            << "  -q           Quiet mode, print less output" << std::endl
            << "  -s <SIZE>    Set the sieve size in KiloBytes, e.g. -s 256," << std::endl
            << "               set SIZE to your CPU's L1/L2 cache size for best performance" << std::endl
            << "               SIZE >= 1 and SIZE <= 8192" << std::endl
            << "  -t <THREADS> Set the number of threads for sieving, e.g. -t 4," << std::endl
            << "               THREADS >= 1 and THREADS <= " << maxThreads << " (CPU max threads)" << std::endl
            << "  -test        Run various sieving tests and exit" << std::endl
            << "  -v           Print version and license information and exit" << std::endl;
}

void version() {
  std::cout << "primesieve 2.2, <http://primesieve.googlecode.com>" << std::endl
            << "Copyright (C) 2011 Kim Walisch" << std::endl
            << "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>." << std::endl
            << "This is free software: you are free to change and redistribute it." << std::endl
            << "There is NO WARRANTY, to the extent permitted by law." << std::endl;
}

bool isDigits(const std::string &str) {
  const std::string digits("0123456789");
  if (str.size() == 0)
    return false;
  return str.find_first_not_of(digits) == std::string::npos;
}

/**
 * Process the command-line options.
 * @see help(void)
 */
int processOptions(int argc, char* argv[]) {
  std::string testOption("test");
  std::string arg;
  ExpressionParser<uint64_t> parser;
  int i = 1;

  if (argc < 2 || argc > 20)
    return OPTION_HELP;
  if (argc > 2) {
    // get the START and STOP number
    for (; i <= 2; i++) {
      if (!parser.eval(argv[i])) {
        std::cerr << "Error: \"" << argv[i]  << "\" is not a valid arithmetic expression" << std::endl
                  << "Try `primesieve -help' for more information." << std::endl;
        return OPTION_ERROR;
      }
      numbers.push_back(parser.getResult());
      if (!isDigits(argv[i]))
        showParserResults = true;
    }
  }
  // process the options ([OPTION]...)
  for (; i < argc; i++) {
    char* c = argv[i];
    if (*c != '-' && *c != '/')
      return OPTION_HELP;
    c++;
    switch (std::tolower(*c++)) {
      case 'c': do {
                  if (*c < '1' || *c > '7')
                    return OPTION_HELP;
                  flags |= ParallelPrimeSieve::COUNT_PRIMES << (*c - '1');
                } while (*(++c) != 0);
                break;
      case 'p': if (*c < '1' || *c > '7')
                  return OPTION_HELP;
                flags |= ParallelPrimeSieve::PRINT_PRIMES << (*c - '1');
                quietMode = true;
                break;
      case 'q': quietMode = true;
                break;
      case 's': if (++i >= argc || !parser.eval(argv[i]))
                  return OPTION_HELP;
                sieveSize = static_cast<uint32_t> (parser.getResult());
                break;
      case 't': arg = &argv[i][1];
                if (arg.compare(testOption) == 0)
                  return OPTION_TEST;
                if (++i >= argc || !parser.eval(argv[i]))
                  return OPTION_HELP;
                threads = static_cast<int> (parser.getResult());
                break;
      case 'v': return OPTION_VERSION;
      default : return OPTION_HELP;
    }
  }
  if (numbers.size() == 2)
    return OPTION_SIEVE;
  return OPTION_HELP;
}

/**
 * Process the command-line options and start sieving.
 */
int main(int argc, char* argv[]) {
  switch(processOptions(argc, argv)) {
    case OPTION_ERROR:              return 1;
    case OPTION_HELP:    help();    return 0;
    case OPTION_VERSION: version(); return 0;
    case OPTION_TEST:    test();    return 0;
    default: break;
  }
  // print parser results
  std::cout.setf(std::ios::left);
  if (!quietMode && showParserResults)
    std::cout << std::setw(10) << "START" << " = " << numbers[0] << std::endl
              << std::setw(10) << "STOP"  << " = " << numbers[1] << std::endl;
  try {
    ParallelPrimeSieve pps;

    // set default settings
    if ((flags & pps.COUNT_FLAGS) == 0 && (flags & pps.PRINT_FLAGS) == 0)
      flags |= pps.COUNT_PRIMES;
    if (!quietMode && (flags & pps.PRINT_FLAGS) == 0)
      flags |= pps.PRINT_STATUS;
    if (sieveSize == 0)
      sieveSize = (numbers[1] < L2_THRESHOLD) ? L1_CACHE_SIZE : L2_CACHE_SIZE;

    pps.setStartNumber(numbers[0]);
    pps.setStopNumber(numbers[1]);
    pps.setSieveSize(sieveSize);
    pps.setFlags(flags);
    pps.setNumThreads(threads);

    if (!quietMode)
      std::cout << std::setw(10) << "Sieve size" << " = " << pps.getSieveSize() << " KiloBytes" << std::endl
                << std::setw(10) << "Threads" << " = " << pps.getNumThreads() << std::endl;

    // start sieving primes
    pps.sieve();
    if ((flags & pps.PRINT_STATUS) || (
        (flags & pps.PRINT_FLAGS) &&
        (flags & pps.COUNT_FLAGS)))
      std::cout << std::endl;

    const std::string primes[7] = {
      "Prime numbers",
      "Twin primes",
      "Prime triplets",
      "Prime quadruplets",
      "Prime quintuplets",
      "Prime sextuplets",
      "Prime septuplets"};

    // get max string size
    std::size_t size = (quietMode) ? 0 : 12;
    for (int i = 0; i < 7; i++)
      if ((flags & (pps.COUNT_PRIMES << i)) && size < primes[i].size())
        size = primes[i].size();
    // print prime count results and time elapsed
    int width = static_cast<int> (size);
    for (int i = 0; i < 7; i++)
      if (flags & (pps.COUNT_PRIMES << i))
        std::cout << std::setw(width) << primes[i] << " : " << pps.getCounts(i) << std::endl;
    if (!quietMode)
      std::cout << std::setw(width) << "Time elapsed" << " : " << pps.getTimeElapsed() << " sec" << std::endl;
  }
  catch (std::exception& e) {
    std::cerr << "Error: " << e.what() << std::endl
              << "Try `primesieve -help' for more information." << std::endl;
    return 1;
  }
  return 0;
}
<commit_msg>improved code readability<commit_after>/*
 * main.cpp -- This file is part of primesieve
 *
 * Copyright (C) 2011 Kim Walisch, <kim.walisch@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 */

/**
 * @file  main.cpp
 * @brief Command-line version of primesieve, multi-threaded (OpenMP).
 * @see   http://primesieve.googlecode.com
 *
 * primesieve is a highly optimized implementation of the sieve of
 * Eratosthenes that generates prime numbers and prime k-tuplets (twin
 * primes, prime triplets, ...) up to 2^64 maximum.
 */

#include "../soe/ParallelPrimeSieve.h"
#include "../expr/ExpressionParser.h"

/// declared in test.cpp
void test();

#include <stdint.h>
#include <exception>
#include <iostream>
#include <string>
#include <vector>
#include <cctype>  /* std::tolower(int) */
#include <iomanip> /* std::setw(int) */

namespace {
  enum {
    OPTION_ERROR,
    OPTION_HELP,
    OPTION_SIEVE,
    OPTION_TEST,
    OPTION_VERSION
  };

  std::vector<uint64_t> numbers; /* start and stop number for sieving */
  uint32_t sieveSize     = 0;    /* sieve size in KiloBytes */
  uint32_t flags         = 0;    /* settings */
  bool quietMode         = false;
  bool showParserResults = false;
  int threads            = ParallelPrimeSieve::USE_IDEAL_NUM_THREADS;
  int maxThreads         = ParallelPrimeSieve::getMaxThreads();

  // Unfortunately there is no easy way to get the CPU L1 and L2 cache
  // size, these values are close for most x86-64 CPUs in 2011
  const uint32_t L1_CACHE_SIZE = 64;
  const uint32_t L2_CACHE_SIZE = 512;
  const uint64_t L2_THRESHOLD  = static_cast<uint64_t> (1E13);
}

void help() {
  std::cout << "Usage: primesieve START STOP [OPTION]..." << std::endl
            << "Use the sieve of Eratosthenes to find the prime numbers and prime" << std::endl
            << "k-tuplets between START and STOP < 2^64" << std::endl
            << std::endl
            << "Examples:" << std::endl
            << "  primesieve 1 10000000 -p1" << std::endl
            << "  primesieve 1 1e11 -s 32" << std::endl
            << "  primesieve 1e18 1e18+2**32 -c1234567" << std::endl
            << std::endl
            << "Options:" << std::endl
            << "  -c[N]        Count prime numbers and/or prime k-tuplets," << std::endl
            << "               e.g -c1 count prime numbers, -c3 count prime triplets, ..." << std::endl
            << "               N >= 1 and N <= 7" << std::endl
            << "  -p[N]        Print prime numbers or prime k-tuplets," << std::endl
            << "               e.g -p1 print prime numbers, -p2 print twin primes, ..." << std::endl
            << "               N >= 1 and N <= 7" << std::endl
            << "  -q           Quiet mode, print less output" << std::endl
            << "  -s <SIZE>    Set the sieve size in KiloBytes, e.g. -s 256," << std::endl
            << "               set SIZE to your CPU's L1/L2 cache size for best performance" << std::endl
            << "               SIZE >= 1 and SIZE <= 8192" << std::endl
            << "  -t <THREADS> Set the number of threads for sieving, e.g. -t 4," << std::endl
            << "               THREADS >= 1 and THREADS <= " << maxThreads << " (CPU max threads)" << std::endl
            << "  -test        Run various sieving tests and exit" << std::endl
            << "  -v           Print version and license information and exit" << std::endl;
}

void version() {
  std::cout << "primesieve 2.2, <http://primesieve.googlecode.com>" << std::endl
            << "Copyright (C) 2011 Kim Walisch" << std::endl
            << "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>." << std::endl
            << "This is free software: you are free to change and redistribute it." << std::endl
            << "There is NO WARRANTY, to the extent permitted by law." << std::endl;
}

bool isDigits(const std::string &str) {
  const std::string digits("0123456789");
  if (str.size() == 0)
    return false;
  return str.find_first_not_of(digits) == std::string::npos;
}

/**
 * Process the command-line options.
 * @see help(void)
 */
int processOptions(int argc, char* argv[]) {
  std::string testOption("test");
  std::string arg;
  ExpressionParser<uint64_t> parser;
  int i = 1;

  if (argc < 2 || argc > 20)
    return OPTION_HELP;
  if (argc > 2) {
    // get the START and STOP number
    for (; i <= 2; i++) {
      if (!parser.eval(argv[i])) {
        std::cerr << "Error: \"" << argv[i]  << "\" is not a valid arithmetic expression" << std::endl
                  << "Try `primesieve -help' for more information." << std::endl;
        return OPTION_ERROR;
      }
      numbers.push_back(parser.getResult());
      if (!isDigits(argv[i]))
        showParserResults = true;
    }
  }
  // process the options ([OPTION]...)
  for (; i < argc; i++) {
    char* c = argv[i];
    if (*c != '-' && *c != '/')
      return OPTION_HELP;
    c++;
    switch (std::tolower(*c++)) {
      case 'c': do {
                  if (*c < '1' || *c > '7')
                    return OPTION_HELP;
                  flags |= ParallelPrimeSieve::COUNT_PRIMES << (*c - '1');
                } while (*(++c) != 0);
                break;
      case 'p': if (*c < '1' || *c > '7')
                  return OPTION_HELP;
                flags |= ParallelPrimeSieve::PRINT_PRIMES << (*c - '1');
                quietMode = true;
                break;
      case 'q': quietMode = true;
                break;
      case 's': if (++i >= argc || !parser.eval(argv[i]))
                  return OPTION_HELP;
                sieveSize = static_cast<uint32_t> (parser.getResult());
                break;
      case 't': arg = &argv[i][1];
                if (arg.compare(testOption) == 0)
                  return OPTION_TEST;
                if (++i >= argc || !parser.eval(argv[i]))
                  return OPTION_HELP;
                threads = static_cast<int> (parser.getResult());
                break;
      case 'v': return OPTION_VERSION;
      default : return OPTION_HELP;
    }
  }
  if (numbers.size() == 2)
    return OPTION_SIEVE;
  return OPTION_HELP;
}

/**
 * Process the command-line options and start sieving.
 */
int main(int argc, char* argv[]) {
  switch(processOptions(argc, argv)) {
    case OPTION_ERROR:              return 1;
    case OPTION_HELP:    help();    return 0;
    case OPTION_VERSION: version(); return 0;
    case OPTION_TEST:    test();    return 0;
    default: break;
  }
  // print parser results
  std::cout.setf(std::ios::left);
  if (!quietMode && showParserResults)
    std::cout << std::setw(10) << "START" << " = " << numbers[0] << std::endl
              << std::setw(10) << "STOP"  << " = " << numbers[1] << std::endl;
  try {
    ParallelPrimeSieve pps;

    // set default settings
    if ((flags & pps.COUNT_FLAGS) == 0 && (flags & pps.PRINT_FLAGS) == 0)
      flags |= pps.COUNT_PRIMES;
    if (!quietMode && (flags & pps.PRINT_FLAGS) == 0)
      flags |= pps.PRINT_STATUS;
    if (sieveSize == 0)
      sieveSize = (numbers[1] < L2_THRESHOLD) ? L1_CACHE_SIZE : L2_CACHE_SIZE;

    pps.setStartNumber(numbers[0]);
    pps.setStopNumber(numbers[1]);
    pps.setSieveSize(sieveSize);
    pps.setFlags(flags);
    pps.setNumThreads(threads);

    if (!quietMode)
      std::cout << std::setw(10) << "Sieve size" << " = " << pps.getSieveSize() << " KiloBytes" << std::endl
                << std::setw(10) << "Threads" << " = " << pps.getNumThreads() << std::endl;

    // start sieving primes
    pps.sieve();
    if ((flags & pps.PRINT_STATUS) || (
        (flags & pps.PRINT_FLAGS) &&
        (flags & pps.COUNT_FLAGS)))
      std::cout << std::endl;

    const std::string primes[7] = {
        "Prime numbers",
        "Twin primes",
        "Prime triplets",
        "Prime quadruplets",
        "Prime quintuplets",
        "Prime sextuplets",
        "Prime septuplets"};

    // get max string size
    std::size_t size = (quietMode) ? 0 : 12;
    for (int i = 0; i < 7; i++)
      if ((flags & (pps.COUNT_PRIMES << i)) && size < primes[i].size())
        size = primes[i].size();
    // print prime count results and time elapsed
    int width = static_cast<int> (size);
    for (int i = 0; i < 7; i++)
      if (flags & (pps.COUNT_PRIMES << i))
        std::cout << std::setw(width) << primes[i] << " : " << pps.getCounts(i) << std::endl;
    if (!quietMode)
      std::cout << std::setw(width) << "Time elapsed" << " : " << pps.getTimeElapsed() << " sec" << std::endl;
  }
  catch (std::exception& e) {
    std::cerr << "Error: " << e.what() << std::endl
              << "Try `primesieve -help' for more information." << std::endl;
    return 1;
  }
  return 0;
}
<|endoftext|>


<commit_before><commit_msg>VclPtr: no dialog loaded from a .ui ever actually destructed<commit_after><|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkWindowToImageFilter.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkWindowToImageFilter.h"

#include "vtkCamera.h"
#include "vtkImageData.h"
#include "vtkObjectFactory.h"
#include "vtkRenderWindow.h"
#include "vtkRendererCollection.h"

vtkCxxRevisionMacro(vtkWindowToImageFilter, "1.16");
vtkStandardNewMacro(vtkWindowToImageFilter);

//----------------------------------------------------------------------------
vtkWindowToImageFilter::vtkWindowToImageFilter()
{
  this->Input = NULL;
  this->Magnification = 1;
  this->ReadFrontBuffer = 1;
}

//----------------------------------------------------------------------------
vtkWindowToImageFilter::~vtkWindowToImageFilter()
{
  if (this->Input)
    {
    this->Input->UnRegister(this);
    this->Input = NULL;
    }
}

//----------------------------------------------------------------------------
void vtkWindowToImageFilter::SetInput(vtkWindow *input)
{
  if (input != this->Input)
    {
    if (this->Input) {this->Input->UnRegister(this);}
    this->Input = input;
    if (this->Input) {this->Input->Register(this);}
    this->Modified();
    }
}

//----------------------------------------------------------------------------
void vtkWindowToImageFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkImageSource::PrintSelf(os,indent);

  if ( this->Input )
    {
    os << indent << "Input:\n";
    this->Input->PrintSelf(os,indent.GetNextIndent());
    }
  else
    {
    os << indent << "Input: (none)\n";
    }
  os << indent << "ReadFrontBuffer: " << this->ReadFrontBuffer << "\n";
  os << indent << "Magnification: " << this->Magnification << "\n";
}

//----------------------------------------------------------------------------
// This method returns the largest region that can be generated.
void vtkWindowToImageFilter::ExecuteInformation()
{
  if (this->Input == NULL )
    {
    vtkErrorMacro(<<"Please specify a renderer as input!");
    return;
    }
  vtkImageData *out = this->GetOutput();

  // set the extent
  out->SetWholeExtent(0,
                      this->Input->GetSize()[0]*this->Magnification - 1,
                      0,
                      this->Input->GetSize()[1]*this->Magnification - 1,
                      0, 0);

  // set the spacing
  out->SetSpacing(1.0, 1.0, 1.0);

  // set the origin.
  out->SetOrigin(0.0, 0.0, 0.0);

  // set the scalar components
  out->SetNumberOfScalarComponents(3);
  out->SetScalarType(VTK_UNSIGNED_CHAR);
}

//----------------------------------------------------------------------------
// This function reads a region from a file.  The regions extent/axes
// are assumed to be the same as the file extent/order.
void vtkWindowToImageFilter::ExecuteData(vtkDataObject *vtkNotUsed(data))
{
  vtkImageData *out = this->GetOutput();
  out->SetExtent(out->GetWholeExtent());
  out->AllocateScalars();

  int outIncrY;
  int size[2];
  unsigned char *pixels, *outPtr;
  int idxY, rowSize;
  int i;

  if (out->GetScalarType() != VTK_UNSIGNED_CHAR)
    {
    vtkErrorMacro("mismatch in scalar types!");
    return;
    }

  // get the size of the render window
  size[0] = this->Input->GetSize()[0];
  size[1] = this->Input->GetSize()[1];
  rowSize = size[0]*3;
  outIncrY = size[0]*this->Magnification*3;

  float *viewAngles;
  double *windowCenters;
  vtkRenderWindow *renWin = vtkRenderWindow::SafeDownCast(this->Input);
  if (!renWin)
    {
    vtkWarningMacro("The window passed to window to image should be a RenderWIndow or one of its subclasses");
    return;
    }

  vtkRendererCollection *rc = renWin->GetRenderers();
  vtkRenderer *aren;
  vtkCamera *cam;
  int numRenderers = rc->GetNumberOfItems();

  // for each renderer
  vtkCamera **cams = new vtkCamera *[numRenderers];
  viewAngles = new float [numRenderers];
  windowCenters = new double [numRenderers*2];
  double *parallelScale = new double [numRenderers];
  rc->InitTraversal();
  for (i = 0; i < numRenderers; ++i)
    {
    aren = rc->GetNextItem();
    cams[i] = aren->GetActiveCamera();
    cams[i]->Register(this);
    cams[i]->GetWindowCenter(windowCenters+i*2);
    viewAngles[i] = cams[i]->GetViewAngle();
    parallelScale[i] = cams[i]->GetParallelScale();
    cam = cams[i]->NewInstance();
    cam->SetPosition(cams[i]->GetPosition());
    cam->SetFocalPoint(cams[i]->GetFocalPoint());
    cam->SetViewUp(cams[i]->GetViewUp());
    cam->SetClippingRange(cams[i]->GetClippingRange());
    cam->SetParallelProjection(cams[i]->GetParallelProjection());
    cam->SetFocalDisk(cams[i]->GetFocalDisk());
    aren->SetActiveCamera(cam);
    }

  // render each of the tiles required to fill this request
  this->Input->SetTileScale(this->Magnification);
  this->Input->GetSize();

  int x, y;
  for (y = 0; y < this->Magnification; y++)
    {
    for (x = 0; x < this->Magnification; x++)
      {
      // setup the Window ivars
      this->Input->SetTileViewport((float)x/this->Magnification,
                                   (float)y/this->Magnification,
                                   (x+1.0)/this->Magnification,
                                   (y+1.0)/this->Magnification);
      float *tvp = this->Input->GetTileViewport();

      // for each renderer, setup camera
      rc->InitTraversal();
      for (i = 0; i < numRenderers; ++i)
        {
        aren = rc->GetNextItem();
        cam = aren->GetActiveCamera();
        float *vp = aren->GetViewport();
        float visVP[4];
        visVP[0] = (vp[0] >= tvp[0]) ? vp[0] : tvp[0];
        visVP[1] = (vp[1] >= tvp[1]) ? vp[1] : tvp[1];
        visVP[2] = (vp[2] <= tvp[2]) ? vp[2] : tvp[2];
        visVP[3] = (vp[3] <= tvp[3]) ? vp[3] : tvp[3];
        // compute magnification
        float mag = (visVP[3] - visVP[1])/(vp[3] - vp[1]);
        // compute the delta
        float deltax = (visVP[2] + visVP[0])/2.0 - (vp[2] + vp[0])/2.0;
        float deltay = (visVP[3] + visVP[1])/2.0 - (vp[3] + vp[1])/2.0;
        // scale by original window size
        if (visVP[2] - visVP[0] > 0)
          {
          deltax = 2.0*deltax/(visVP[2] - visVP[0]);
          }
        if (visVP[3] - visVP[1] > 0)
          {
          deltay = 2.0*deltay/(visVP[3] - visVP[1]);
          }
        cam->SetWindowCenter(deltax,deltay);
        cam->SetViewAngle(asin(sin(viewAngles[i]*3.1415926/360.0)*mag)
                          * 360.0 / 3.1415926);
        cam->SetParallelScale(parallelScale[i]*mag);
        }

      // now render the tile and get the data
      this->Input->Render();
      int buffer = this->ReadFrontBuffer;
      if(!this->Input->GetDoubleBuffer())
        {
        buffer = 1;
        }

      pixels = this->Input->GetPixelData(0,0,size[0] - 1,
                                         size[1] - 1, buffer);
      unsigned char *pixels1 = pixels;

      // now write the data to the output image
      outPtr =
        (unsigned char *)out->GetScalarPointer(x*size[0],y*size[1], 0);

      // Loop through ouput pixels
      for (idxY = 0; idxY < size[1]; idxY++)
        {
        memcpy(outPtr,pixels1,rowSize);
        outPtr += outIncrY;
        pixels1 += rowSize;
        }

      // free the memory
      delete [] pixels;
      }
    }

  // restore settings
  // for each renderer
  rc->InitTraversal();
  for (i = 0; i < numRenderers; ++i)
    {
    aren = rc->GetNextItem();
    // store the old view angle & set the new
    cam = aren->GetActiveCamera();
    aren->SetActiveCamera(cams[i]);
    cams[i]->UnRegister(this);
    cam->Delete();
    }
  delete [] viewAngles;
  delete [] windowCenters;
  delete [] parallelScale;
  delete [] cams;

  // render each of the tiles required to fill this request
  this->Input->SetTileScale(1);
  this->Input->SetTileViewport(0.0,0.0,1.0,1.0);
  this->Input->GetSize();
}

<commit_msg>bug fix for some cases from volview branch<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkWindowToImageFilter.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkWindowToImageFilter.h"

#include "vtkCamera.h"
#include "vtkImageData.h"
#include "vtkObjectFactory.h"
#include "vtkRenderWindow.h"
#include "vtkRendererCollection.h"

vtkCxxRevisionMacro(vtkWindowToImageFilter, "1.17");
vtkStandardNewMacro(vtkWindowToImageFilter);

//----------------------------------------------------------------------------
vtkWindowToImageFilter::vtkWindowToImageFilter()
{
  this->Input = NULL;
  this->Magnification = 1;
  this->ReadFrontBuffer = 1;
}

//----------------------------------------------------------------------------
vtkWindowToImageFilter::~vtkWindowToImageFilter()
{
  if (this->Input)
    {
    this->Input->UnRegister(this);
    this->Input = NULL;
    }
}

//----------------------------------------------------------------------------
void vtkWindowToImageFilter::SetInput(vtkWindow *input)
{
  if (input != this->Input)
    {
    if (this->Input) {this->Input->UnRegister(this);}
    this->Input = input;
    if (this->Input) {this->Input->Register(this);}
    this->Modified();
    }
}

//----------------------------------------------------------------------------
void vtkWindowToImageFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkImageSource::PrintSelf(os,indent);

  if ( this->Input )
    {
    os << indent << "Input:\n";
    this->Input->PrintSelf(os,indent.GetNextIndent());
    }
  else
    {
    os << indent << "Input: (none)\n";
    }
  os << indent << "ReadFrontBuffer: " << this->ReadFrontBuffer << "\n";
  os << indent << "Magnification: " << this->Magnification << "\n";
}

//----------------------------------------------------------------------------
// This method returns the largest region that can be generated.
void vtkWindowToImageFilter::ExecuteInformation()
{
  if (this->Input == NULL )
    {
    vtkErrorMacro(<<"Please specify a renderer as input!");
    return;
    }
  vtkImageData *out = this->GetOutput();

  // set the extent
  out->SetWholeExtent(0,
                      this->Input->GetSize()[0]*this->Magnification - 1,
                      0,
                      this->Input->GetSize()[1]*this->Magnification - 1,
                      0, 0);

  // set the spacing
  out->SetSpacing(1.0, 1.0, 1.0);

  // set the origin.
  out->SetOrigin(0.0, 0.0, 0.0);

  // set the scalar components
  out->SetNumberOfScalarComponents(3);
  out->SetScalarType(VTK_UNSIGNED_CHAR);
}

//----------------------------------------------------------------------------
// This function reads a region from a file.  The regions extent/axes
// are assumed to be the same as the file extent/order.
void vtkWindowToImageFilter::ExecuteData(vtkDataObject *vtkNotUsed(data))
{
  vtkImageData *out = this->GetOutput();
  out->SetExtent(out->GetWholeExtent());
  out->AllocateScalars();

  int outIncrY;
  int size[2];
  unsigned char *pixels, *outPtr;
  int idxY, rowSize;
  int i;

  if (out->GetScalarType() != VTK_UNSIGNED_CHAR)
    {
    vtkErrorMacro("mismatch in scalar types!");
    return;
    }

  // get the size of the render window
  size[0] = this->Input->GetSize()[0];
  size[1] = this->Input->GetSize()[1];
  rowSize = size[0]*3;
  outIncrY = size[0]*this->Magnification*3;

  float *viewAngles;
  double *windowCenters;
  vtkRenderWindow *renWin = vtkRenderWindow::SafeDownCast(this->Input);
  if (!renWin)
    {
    vtkWarningMacro("The window passed to window to image should be a RenderWIndow or one of its subclasses");
    return;
    }

  vtkRendererCollection *rc = renWin->GetRenderers();
  vtkRenderer *aren;
  vtkCamera *cam;
  int numRenderers = rc->GetNumberOfItems();

  // for each renderer
  vtkCamera **cams = new vtkCamera *[numRenderers];
  viewAngles = new float [numRenderers];
  windowCenters = new double [numRenderers*2];
  double *parallelScale = new double [numRenderers];
  rc->InitTraversal();
  for (i = 0; i < numRenderers; ++i)
    {
    aren = rc->GetNextItem();
    cams[i] = aren->GetActiveCamera();
    cams[i]->Register(this);
    cams[i]->GetWindowCenter(windowCenters+i*2);
    viewAngles[i] = cams[i]->GetViewAngle();
    parallelScale[i] = cams[i]->GetParallelScale();
    cam = cams[i]->NewInstance();
    cam->SetPosition(cams[i]->GetPosition());
    cam->SetFocalPoint(cams[i]->GetFocalPoint());
    cam->SetViewUp(cams[i]->GetViewUp());
    cam->SetClippingRange(cams[i]->GetClippingRange());
    cam->SetParallelProjection(cams[i]->GetParallelProjection());
    cam->SetFocalDisk(cams[i]->GetFocalDisk());
    aren->SetActiveCamera(cam);
    }

  // render each of the tiles required to fill this request
  this->Input->SetTileScale(this->Magnification);
  this->Input->GetSize();

  int x, y;
  for (y = 0; y < this->Magnification; y++)
    {
    for (x = 0; x < this->Magnification; x++)
      {
      // setup the Window ivars
      this->Input->SetTileViewport((float)x/this->Magnification,
                                   (float)y/this->Magnification,
                                   (x+1.0)/this->Magnification,
                                   (y+1.0)/this->Magnification);
      float *tvp = this->Input->GetTileViewport();

      // for each renderer, setup camera
      rc->InitTraversal();
      for (i = 0; i < numRenderers; ++i)
        {
        aren = rc->GetNextItem();
        cam = aren->GetActiveCamera();
        float *vp = aren->GetViewport();
        float visVP[4];
        visVP[0] = (vp[0] < tvp[0]) ? tvp[0] : vp[0];
        visVP[0] = (visVP[0] > tvp[2]) ? tvp[2] : visVP[0];
        visVP[1] = (vp[1] < tvp[1]) ? tvp[1] : vp[1];
        visVP[1] = (visVP[1] > tvp[3]) ? tvp[3] : visVP[1];
        visVP[2] = (vp[2] > tvp[2]) ? tvp[2] : vp[2];
        visVP[2] = (visVP[2] < tvp[0]) ? tvp[0] : visVP[2];
        visVP[3] = (vp[3] > tvp[3]) ? tvp[3] : vp[3];
        visVP[3] = (visVP[3] < tvp[1]) ? tvp[1] : visVP[3];

        // compute magnification
        float mag = (visVP[3] - visVP[1])/(vp[3] - vp[1]);
        // compute the delta
        float deltax = (visVP[2] + visVP[0])/2.0 - (vp[2] + vp[0])/2.0;
        float deltay = (visVP[3] + visVP[1])/2.0 - (vp[3] + vp[1])/2.0;
        // scale by original window size
        if (visVP[2] - visVP[0] > 0)
          {
          deltax = 2.0*deltax/(visVP[2] - visVP[0]);
          }
        if (visVP[3] - visVP[1] > 0)
          {
          deltay = 2.0*deltay/(visVP[3] - visVP[1]);
          }
        cam->SetWindowCenter(deltax,deltay);
        cam->SetViewAngle(asin(sin(viewAngles[i]*3.1415926/360.0)*mag)
                          * 360.0 / 3.1415926);
        cam->SetParallelScale(parallelScale[i]*mag);
        }

      // now render the tile and get the data
      this->Input->Render();
      int buffer = this->ReadFrontBuffer;
      if(!this->Input->GetDoubleBuffer())
        {
        buffer = 1;
        }

      pixels = this->Input->GetPixelData(0,0,size[0] - 1,
                                         size[1] - 1, buffer);
      unsigned char *pixels1 = pixels;

      // now write the data to the output image
      outPtr =
        (unsigned char *)out->GetScalarPointer(x*size[0],y*size[1], 0);

      // Loop through ouput pixels
      for (idxY = 0; idxY < size[1]; idxY++)
        {
        memcpy(outPtr,pixels1,rowSize);
        outPtr += outIncrY;
        pixels1 += rowSize;
        }

      // free the memory
      delete [] pixels;
      }
    }

  // restore settings
  // for each renderer
  rc->InitTraversal();
  for (i = 0; i < numRenderers; ++i)
    {
    aren = rc->GetNextItem();
    // store the old view angle & set the new
    cam = aren->GetActiveCamera();
    aren->SetActiveCamera(cams[i]);
    cams[i]->UnRegister(this);
    cam->Delete();
    }
  delete [] viewAngles;
  delete [] windowCenters;
  delete [] parallelScale;
  delete [] cams;

  // render each of the tiles required to fill this request
  this->Input->SetTileScale(1);
  this->Input->SetTileViewport(0.0,0.0,1.0,1.0);
  this->Input->GetSize();
}

<|endoftext|>