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

  This source file is part of the TEM tomography project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  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 "RecentFilesMenu.h"

#include "ActiveObjects.h"
#include "DataSource.h"
#include "LoadDataReaction.h"
#include "pqPipelineSource.h"
#include "pqSettings.h"
#include "SaveLoadStateReaction.h"
#include "Utilities.h"
#include "vtkNew.h"
#include "vtkSmartPointer.h"
#include "vtkSMCoreUtilities.h"
#include "vtkSMParaViewPipelineController.h"
#include "vtkSMPropertyHelper.h"
#include "vtkSMSessionProxyManager.h"
#include "vtkSMSourceProxy.h"

#include <QMenu>
#include <sstream>
#include <string>

namespace TEM
{

static const int MAX_ITEMS = 10;

void get_settings(pugi::xml_document& doc)
  {
  QSettings* settings = pqApplicationCore::instance()->settings();
  QString recent = settings->value("recentFiles").toString();
  if (recent.isEmpty() || !doc.load(recent.toUtf8().data()) || !doc.child("TEMRecentFilesMenu"))
    {
    doc.append_child("TEMRecentFilesMenu");
    }
  }

void save_settings(pugi::xml_document &doc)
  {
  // trim the list.
  pugi::xml_node root = doc.root();
  std::vector<pugi::xml_node> to_remove;
  int counter=0;
  for (pugi::xml_node node = root.child("DataReader"); node;
       node = node.next_sibling("DataReader"), counter++)
    {
    if (counter >= MAX_ITEMS)
      {
      to_remove.push_back(node);
      }
    }
  counter=0;
  for (pugi::xml_node node = root.child("State"); node;
       node = node.next_sibling("State"), counter++)
    {
    if (counter >= MAX_ITEMS)
      {
      to_remove.push_back(node);
      }
    }
  for (size_t cc = 0; cc < to_remove.size(); cc++)
    {
    root.remove_child(to_remove[cc]);
    }

  std::ostringstream stream;
  doc.save(stream);
  QSettings* settings = pqApplicationCore::instance()->settings();
  settings->setValue("recentFiles", stream.str().c_str());
  }

//-------------------------------------------------------------------------
RecentFilesMenu::RecentFilesMenu(QMenu& menu, QObject* parentObject)
  : Superclass(parentObject)
{
  this->connect(&menu, SIGNAL(aboutToShow()), SLOT(aboutToShowMenu()));
}

//-------------------------------------------------------------------------
RecentFilesMenu::~RecentFilesMenu()
{
}

//-------------------------------------------------------------------------
void RecentFilesMenu::pushDataReader(vtkSMProxy* readerProxy)
{
  pugi::xml_document settings;
  get_settings(settings);

  pugi::xml_node root = settings.root();
  const char* pname = vtkSMCoreUtilities::GetFileNameProperty(readerProxy);
  if (pname)
    {
    const char* filename = vtkSMPropertyHelper(readerProxy,
                                               pname).GetAsString(0);
    for (pugi::xml_node node = root.child("DataReader"); node;
         node = node.next_sibling("DataReader"))
      {
      if (strcmp(node.attribute("filename0").as_string(""), filename) == 0)
        {
        root.remove_child(node);
        break;
        }
      }
    pugi::xml_node node = root.prepend_child("DataReader");
    node.append_attribute("filename0").set_value(filename);
    node.append_attribute("xmlgroup").set_value(readerProxy->GetXMLGroup());
    node.append_attribute("xmlname").set_value(readerProxy->GetXMLName());
    TEM::serialize(readerProxy, node);

    save_settings(settings);
    }
}

//-------------------------------------------------------------------------
void RecentFilesMenu::pushStateFile(const QString& filename)
{
  pugi::xml_document settings;
  get_settings(settings);

  pugi::xml_node root = settings.root();
  for (pugi::xml_node node = root.child("State"); node;
       node = node.next_sibling("State"))
    {
    if (filename == node.attribute("filename").as_string(""))
      {
      root.remove_child(node);
      break;
      }
    }

  pugi::xml_node node = root.prepend_child("State");
  node.append_attribute("filename").set_value(filename.toLatin1().data());
  save_settings(settings);
}

//-------------------------------------------------------------------------
void RecentFilesMenu::aboutToShowMenu()
{
  QMenu* menu = qobject_cast<QMenu*>(this->sender());
  Q_ASSERT(menu);
  menu->clear();

  pugi::xml_document settings;
  get_settings(settings);

  pugi::xml_node root = settings.root();
  if (!root.child("DataReader") && !root.child("State"))
    {
    QAction* actn = menu->addAction("Empty");
    actn->setEnabled(false);
    return;
    }

  bool header_added = false;
  int index=0;
  for (pugi::xml_node node = root.child("DataReader"); node;
       node = node.next_sibling("DataReader"))
    {
    if (header_added == false)
      {
      QAction* actn = menu->addAction("Datasets");
      actn->setEnabled(false);
      header_added = true;
      }
    QAction* actn = menu->addAction(QIcon(":/pqWidgets/Icons/pqInspect22.png"),
      node.attribute("filename0").as_string("<bug>"));
    actn->setData(index);
    this->connect(actn, SIGNAL(triggered()), SLOT(dataSourceTriggered()));
    index++;
    }

  header_added = false;
  for (pugi::xml_node node = root.child("State"); node;
       node = node.next_sibling("State"))
    {
    if (header_added == false)
      {
      QAction* actn = menu->addAction("State files");
      actn->setEnabled(false);
      header_added = true;
      }
    QAction* actn = menu->addAction(QIcon(":/icons/tomviz.png"),
      node.attribute("filename").as_string("<bug>"));
    actn->setData(node.attribute("filename").as_string("<bug>"));
    this->connect(actn, SIGNAL(triggered()), SLOT(stateTriggered()));
    index++;
    }
}

//-------------------------------------------------------------------------
void RecentFilesMenu::dataSourceTriggered()
{
  QAction* actn = qobject_cast<QAction*>(this->sender());
  Q_ASSERT(actn);

  int index = actn->data().toInt();
  pugi::xml_document settings;
  get_settings(settings);
  pugi::xml_node root = settings.root();

  for (pugi::xml_node node = root.child("DataReader"); node;
       node = node.next_sibling("DataReader"), --index)
    {
    if (index == 0)
      {
      vtkSMSessionProxyManager* pxm = ActiveObjects::instance().proxyManager();
      vtkSmartPointer<vtkSMProxy> reader;
      reader.TakeReference(pxm->NewProxy(node.attribute("xmlgroup").as_string(),
                                         node.attribute("xmlname").as_string()));
      if (TEM::deserialize(reader, node))
        {
        reader->UpdateVTKObjects();
        vtkSMSourceProxy::SafeDownCast(reader)->UpdatePipelineInformation();
        if (LoadDataReaction::createDataSource(reader))
          {
          // reorder the nodes to move the recently opened file to the top.
          root.prepend_copy(node);
          root.remove_child(node);
          save_settings(settings);
          return;
          }
        }
      // failed to create reader, remove the node.
      root.remove_child(node);
      save_settings(settings);
      return;
      }
    }
}

//-------------------------------------------------------------------------
void RecentFilesMenu::stateTriggered()
{
  QAction* actn = qobject_cast<QAction*>(this->sender());
  Q_ASSERT(actn);

  QString filename = actn->data().toString();
  if (SaveLoadStateReaction::loadState(filename))
    {
    // the above call will ensure that the file name moves to top of the list
    // since it calls pushStateFile() on success.
    return;
    }

  // remove the item from the recent state files list.
  pugi::xml_document settings;
  get_settings(settings);
  pugi::xml_node root = settings.root();
  for (pugi::xml_node node = root.child("State"); node;
       node = node.next_sibling("State"))
    {
    if (filename == node.attribute("filename").as_string())
      {
      root.remove_child(node);
      save_settings(settings);
      break;
      }
    }
}

}
<commit_msg>Check if recent file still exists before loading it<commit_after>/******************************************************************************

  This source file is part of the TEM tomography project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  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 "RecentFilesMenu.h"

#include "ActiveObjects.h"
#include "DataSource.h"
#include "LoadDataReaction.h"
#include "pqPipelineSource.h"
#include "pqSettings.h"
#include "SaveLoadStateReaction.h"
#include "Utilities.h"
#include "vtkNew.h"
#include "vtkSmartPointer.h"
#include "vtkSMCoreUtilities.h"
#include "vtkSMParaViewPipelineController.h"
#include "vtkSMPropertyHelper.h"
#include "vtkSMSessionProxyManager.h"
#include "vtkSMSourceProxy.h"

#include <QMenu>
#include <QDebug>
#include <sstream>
#include <string>

namespace TEM
{

static const int MAX_ITEMS = 10;

void get_settings(pugi::xml_document& doc)
  {
  QSettings* settings = pqApplicationCore::instance()->settings();
  QString recent = settings->value("recentFiles").toString();
  if (recent.isEmpty() || !doc.load(recent.toUtf8().data()) || !doc.child("TEMRecentFilesMenu"))
    {
    doc.append_child("TEMRecentFilesMenu");
    }
  }

void save_settings(pugi::xml_document &doc)
  {
  // trim the list.
  pugi::xml_node root = doc.root();
  std::vector<pugi::xml_node> to_remove;
  int counter=0;
  for (pugi::xml_node node = root.child("DataReader"); node;
       node = node.next_sibling("DataReader"), counter++)
    {
    if (counter >= MAX_ITEMS)
      {
      to_remove.push_back(node);
      }
    }
  counter=0;
  for (pugi::xml_node node = root.child("State"); node;
       node = node.next_sibling("State"), counter++)
    {
    if (counter >= MAX_ITEMS)
      {
      to_remove.push_back(node);
      }
    }
  for (size_t cc = 0; cc < to_remove.size(); cc++)
    {
    root.remove_child(to_remove[cc]);
    }

  std::ostringstream stream;
  doc.save(stream);
  QSettings* settings = pqApplicationCore::instance()->settings();
  settings->setValue("recentFiles", stream.str().c_str());
  }

//-------------------------------------------------------------------------
RecentFilesMenu::RecentFilesMenu(QMenu& menu, QObject* parentObject)
  : Superclass(parentObject)
{
  this->connect(&menu, SIGNAL(aboutToShow()), SLOT(aboutToShowMenu()));
}

//-------------------------------------------------------------------------
RecentFilesMenu::~RecentFilesMenu()
{
}

//-------------------------------------------------------------------------
void RecentFilesMenu::pushDataReader(vtkSMProxy* readerProxy)
{
  pugi::xml_document settings;
  get_settings(settings);

  pugi::xml_node root = settings.root();
  const char* pname = vtkSMCoreUtilities::GetFileNameProperty(readerProxy);
  if (pname)
    {
    const char* filename = vtkSMPropertyHelper(readerProxy,
                                               pname).GetAsString(0);
    for (pugi::xml_node node = root.child("DataReader"); node;
         node = node.next_sibling("DataReader"))
      {
      if (strcmp(node.attribute("filename0").as_string(""), filename) == 0)
        {
        root.remove_child(node);
        break;
        }
      }
    pugi::xml_node node = root.prepend_child("DataReader");
    node.append_attribute("filename0").set_value(filename);
    node.append_attribute("xmlgroup").set_value(readerProxy->GetXMLGroup());
    node.append_attribute("xmlname").set_value(readerProxy->GetXMLName());
    TEM::serialize(readerProxy, node);

    save_settings(settings);
    }
}

//-------------------------------------------------------------------------
void RecentFilesMenu::pushStateFile(const QString& filename)
{
  pugi::xml_document settings;
  get_settings(settings);

  pugi::xml_node root = settings.root();
  for (pugi::xml_node node = root.child("State"); node;
       node = node.next_sibling("State"))
    {
    if (filename == node.attribute("filename").as_string(""))
      {
      root.remove_child(node);
      break;
      }
    }

  pugi::xml_node node = root.prepend_child("State");
  node.append_attribute("filename").set_value(filename.toLatin1().data());
  save_settings(settings);
}

//-------------------------------------------------------------------------
void RecentFilesMenu::aboutToShowMenu()
{
  QMenu* menu = qobject_cast<QMenu*>(this->sender());
  Q_ASSERT(menu);
  menu->clear();

  pugi::xml_document settings;
  get_settings(settings);

  pugi::xml_node root = settings.root();
  if (!root.child("DataReader") && !root.child("State"))
    {
    QAction* actn = menu->addAction("Empty");
    actn->setEnabled(false);
    return;
    }

  bool header_added = false;
  int index=0;
  for (pugi::xml_node node = root.child("DataReader"); node;
       node = node.next_sibling("DataReader"))
    {
    if (header_added == false)
      {
      QAction* actn = menu->addAction("Datasets");
      actn->setEnabled(false);
      header_added = true;
      }
    QFileInfo checkFile(node.attribute("filename0").as_string("<bug>"));
    if (checkFile.exists())
      {
      QAction* actn = menu->addAction(QIcon(":/pqWidgets/Icons/pqInspect22.png"),
        node.attribute("filename0").as_string("<bug>"));
      actn->setData(index);
      this->connect(actn, SIGNAL(triggered()), SLOT(dataSourceTriggered()));
      }
    index++;
    }

  header_added = false;
  for (pugi::xml_node node = root.child("State"); node;
       node = node.next_sibling("State"))
    {
    if (header_added == false)
      {
      QAction* actn = menu->addAction("State files");
      actn->setEnabled(false);
      header_added = true;
      }
    QFileInfo checkFile(node.attribute("filename").as_string("<bug>"));
    if (checkFile.exists())
      {
      QAction* actn = menu->addAction(QIcon(":/icons/tomviz.png"),
        node.attribute("filename").as_string("<bug>"));
      actn->setData(node.attribute("filename").as_string("<bug>"));
      this->connect(actn, SIGNAL(triggered()), SLOT(stateTriggered()));
      }
    index++;
    }
}

//-------------------------------------------------------------------------
void RecentFilesMenu::dataSourceTriggered()
{
  QAction* actn = qobject_cast<QAction*>(this->sender());
  Q_ASSERT(actn);

  QFileInfo checkFile(actn->iconText());
  if (!checkFile.exists())
    {
    // This should never happen since the checks in aboutToShowMenu should
    // prevent it, but just in case...
    qWarning() << "Error: file '" << actn->iconText()
               << "' does not exist.";
    return;
    }

  int index = actn->data().toInt();
  pugi::xml_document settings;
  get_settings(settings);
  pugi::xml_node root = settings.root();

  for (pugi::xml_node node = root.child("DataReader"); node;
       node = node.next_sibling("DataReader"), --index)
    {
    if (index == 0)
      {
      vtkSMSessionProxyManager* pxm = ActiveObjects::instance().proxyManager();
      vtkSmartPointer<vtkSMProxy> reader;
      reader.TakeReference(pxm->NewProxy(node.attribute("xmlgroup").as_string(),
                                         node.attribute("xmlname").as_string()));
      if (TEM::deserialize(reader, node))
        {
        reader->UpdateVTKObjects();
        vtkSMSourceProxy::SafeDownCast(reader)->UpdatePipelineInformation();
        if (LoadDataReaction::createDataSource(reader))
          {
          // reorder the nodes to move the recently opened file to the top.
          root.prepend_copy(node);
          root.remove_child(node);
          save_settings(settings);
          return;
          }
        }
      // failed to create reader, remove the node.
      root.remove_child(node);
      save_settings(settings);
      return;
      }
    }
}

//-------------------------------------------------------------------------
void RecentFilesMenu::stateTriggered()
{
  QAction* actn = qobject_cast<QAction*>(this->sender());
  Q_ASSERT(actn);

  QFileInfo checkFile(actn->iconText());
  if (!checkFile.exists())
    {
    // This should never happen since the checks in aboutToShowMenu should
    // prevent it, but just in case...
    qWarning() << "Error: file '" << actn->iconText()
               << "' does not exist.";
    return;
    }

  QString filename = actn->data().toString();
  if (SaveLoadStateReaction::loadState(filename))
    {
    // the above call will ensure that the file name moves to top of the list
    // since it calls pushStateFile() on success.
    return;
    }

  // remove the item from the recent state files list.
  pugi::xml_document settings;
  get_settings(settings);
  pugi::xml_node root = settings.root();
  for (pugi::xml_node node = root.child("State"); node;
       node = node.next_sibling("State"))
    {
    if (filename == node.attribute("filename").as_string())
      {
      root.remove_child(node);
      save_settings(settings);
      break;
      }
    }
}

}
<|endoftext|>


<commit_before>#include "conf.hpp"
#include <cstdlib>
#include <sys/stat.h>
#include <unistd.h>
#ifndef NDEBUG
#include <spdlog/sinks/stdout_color_sinks.h>
#endif  //NDEBUG

namespace derecho {

static const char* default_conf_file = "derecho.cfg";

std::unique_ptr<Conf> Conf::singleton = nullptr;

std::atomic<uint32_t> Conf::singleton_initialized_flag = 0;
#define CONF_UNINITIALIZED (0)
#define CONF_INITIALIZING (1)
#define CONF_INITIALIZED (2)

#define MAKE_LONG_OPT_ENTRY(x) \
    { x, required_argument, 0, 0 }
struct option Conf::long_options[] = {
        // [DERECHO]
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_LEADER_IP),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_LEADER_GMS_PORT),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_LOCAL_ID),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_LOCAL_IP),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_GMS_PORT),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_RPC_PORT),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_SST_PORT),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_RDMC_PORT),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_MAX_PAYLOAD_SIZE),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_MAX_SMC_PAYLOAD_SIZE),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_BLOCK_SIZE),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_WINDOW_SIZE),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_TIMEOUT_MS),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_RDMC_SEND_ALGORITHM),
        // [RDMA]
        MAKE_LONG_OPT_ENTRY(CONF_RDMA_PROVIDER),
        MAKE_LONG_OPT_ENTRY(CONF_RDMA_DOMAIN),
        MAKE_LONG_OPT_ENTRY(CONF_RDMA_TX_DEPTH),
        MAKE_LONG_OPT_ENTRY(CONF_RDMA_RX_DEPTH),
        // [PERS]
        MAKE_LONG_OPT_ENTRY(CONF_PERS_FILE_PATH),
        MAKE_LONG_OPT_ENTRY(CONF_PERS_RAMDISK_PATH),
        MAKE_LONG_OPT_ENTRY(CONF_PERS_RESET),
        {0, 0, 0, 0}};

void Conf::initialize(int argc, char* argv[], const char* conf_file) {
    uint32_t expected = CONF_UNINITIALIZED;
    // if not initialized(0), set the flag to under initialization ...
    if(Conf::singleton_initialized_flag.compare_exchange_strong(
               expected, CONF_INITIALIZING, std::memory_order_acq_rel)) {
        // 1 - get configuration file path
        std::string real_conf_file;
        struct stat buffer;
        if(conf_file)
            real_conf_file = conf_file;
        else if(std::getenv("DERECHO_CONF_FILE"))
            // try environment variable: DERECHO_CONF_FILE
            real_conf_file = std::getenv("DERECHO_CONF_FILE");
        else if(stat(default_conf_file, &buffer) == 0) {
            if(S_ISREG(buffer.st_mode) && (S_IRUSR | buffer.st_mode)) {
                real_conf_file = default_conf_file;
            }
        } else
            real_conf_file.clear();

        // 2 - load configuration
        GetPot* cfg = nullptr;
        if(!real_conf_file.empty()) {
            cfg = new GetPot(real_conf_file);
        }
        Conf::singleton = std::make_unique<Conf>(argc, argv, cfg);
        delete cfg;

        // 3 - set the flag to initialized
        Conf::singleton_initialized_flag.store(CONF_INITIALIZED, std::memory_order_acq_rel);
    }
}

// should we force the user to call Conf::initialize() by throw an expcetion
// for uninitialized configuration?
const Conf* Conf::get() noexcept {
    while(Conf::singleton_initialized_flag.load(std::memory_order_acquire) != CONF_INITIALIZED)
        Conf::initialize(1, nullptr, nullptr);
    return Conf::singleton.get();
}

const std::string& getConfString(const std::string& key) {
    return Conf::get()->getString(key);
}

const int32_t getConfInt32(const std::string& key) {
    return Conf::get()->getInt32(key);
}

const uint32_t getConfUInt32(const std::string& key) {
    return Conf::get()->getUInt32(key);
}

const int16_t getConfInt16(const std::string& key) {
    return Conf::get()->getInt16(key);
}

const uint16_t getConfUInt16(const std::string& key) {
    return Conf::get()->getUInt16(key);
}

const int64_t getConfInt64(const std::string& key) {
    return Conf::get()->getInt64(key);
}

const uint64_t getConfUInt64(const std::string& key) {
    return Conf::get()->getUInt64(key);
}

const float getConfFloat(const std::string& key) {
    return Conf::get()->getFloat(key);
}

const double getConfDouble(const std::string& key) {
    return Conf::get()->getDouble(key);
}

const bool getConfBoolean(const std::string& key) {
    return Conf::get()->getBoolean(key);
}

const bool hasCustomizedConfKey(const std::string& key) {
    return Conf::get()->hasCustomizedKey(key);
}
}
<commit_msg>minor fix: allowing PERS/max_log_entry and PERS/max_data_size as command line argument.<commit_after>#include "conf.hpp"
#include <cstdlib>
#include <sys/stat.h>
#include <unistd.h>
#ifndef NDEBUG
#include <spdlog/sinks/stdout_color_sinks.h>
#endif  //NDEBUG

namespace derecho {

static const char* default_conf_file = "derecho.cfg";

std::unique_ptr<Conf> Conf::singleton = nullptr;

std::atomic<uint32_t> Conf::singleton_initialized_flag = 0;
#define CONF_UNINITIALIZED (0)
#define CONF_INITIALIZING (1)
#define CONF_INITIALIZED (2)

#define MAKE_LONG_OPT_ENTRY(x) \
    { x, required_argument, 0, 0 }
struct option Conf::long_options[] = {
        // [DERECHO]
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_LEADER_IP),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_LEADER_GMS_PORT),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_LOCAL_ID),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_LOCAL_IP),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_GMS_PORT),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_RPC_PORT),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_SST_PORT),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_RDMC_PORT),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_MAX_PAYLOAD_SIZE),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_MAX_SMC_PAYLOAD_SIZE),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_BLOCK_SIZE),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_WINDOW_SIZE),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_TIMEOUT_MS),
        MAKE_LONG_OPT_ENTRY(CONF_DERECHO_RDMC_SEND_ALGORITHM),
        // [RDMA]
        MAKE_LONG_OPT_ENTRY(CONF_RDMA_PROVIDER),
        MAKE_LONG_OPT_ENTRY(CONF_RDMA_DOMAIN),
        MAKE_LONG_OPT_ENTRY(CONF_RDMA_TX_DEPTH),
        MAKE_LONG_OPT_ENTRY(CONF_RDMA_RX_DEPTH),
        // [PERS]
        MAKE_LONG_OPT_ENTRY(CONF_PERS_FILE_PATH),
        MAKE_LONG_OPT_ENTRY(CONF_PERS_RAMDISK_PATH),
        MAKE_LONG_OPT_ENTRY(CONF_PERS_RESET),
        MAKE_LONG_OPT_ENTRY(CONF_PERS_MAX_LOG_ENTRY),
        MAKE_LONG_OPT_ENTRY(CONF_PERS_MAX_DATA_SIZE),
        {0, 0, 0, 0}};

void Conf::initialize(int argc, char* argv[], const char* conf_file) {
    uint32_t expected = CONF_UNINITIALIZED;
    // if not initialized(0), set the flag to under initialization ...
    if(Conf::singleton_initialized_flag.compare_exchange_strong(
               expected, CONF_INITIALIZING, std::memory_order_acq_rel)) {
        // 1 - get configuration file path
        std::string real_conf_file;
        struct stat buffer;
        if(conf_file)
            real_conf_file = conf_file;
        else if(std::getenv("DERECHO_CONF_FILE"))
            // try environment variable: DERECHO_CONF_FILE
            real_conf_file = std::getenv("DERECHO_CONF_FILE");
        else if(stat(default_conf_file, &buffer) == 0) {
            if(S_ISREG(buffer.st_mode) && (S_IRUSR | buffer.st_mode)) {
                real_conf_file = default_conf_file;
            }
        } else
            real_conf_file.clear();

        // 2 - load configuration
        GetPot* cfg = nullptr;
        if(!real_conf_file.empty()) {
            cfg = new GetPot(real_conf_file);
        }
        Conf::singleton = std::make_unique<Conf>(argc, argv, cfg);
        delete cfg;

        // 3 - set the flag to initialized
        Conf::singleton_initialized_flag.store(CONF_INITIALIZED, std::memory_order_acq_rel);
    }
}

// should we force the user to call Conf::initialize() by throw an expcetion
// for uninitialized configuration?
const Conf* Conf::get() noexcept {
    while(Conf::singleton_initialized_flag.load(std::memory_order_acquire) != CONF_INITIALIZED)
        Conf::initialize(1, nullptr, nullptr);
    return Conf::singleton.get();
}

const std::string& getConfString(const std::string& key) {
    return Conf::get()->getString(key);
}

const int32_t getConfInt32(const std::string& key) {
    return Conf::get()->getInt32(key);
}

const uint32_t getConfUInt32(const std::string& key) {
    return Conf::get()->getUInt32(key);
}

const int16_t getConfInt16(const std::string& key) {
    return Conf::get()->getInt16(key);
}

const uint16_t getConfUInt16(const std::string& key) {
    return Conf::get()->getUInt16(key);
}

const int64_t getConfInt64(const std::string& key) {
    return Conf::get()->getInt64(key);
}

const uint64_t getConfUInt64(const std::string& key) {
    return Conf::get()->getUInt64(key);
}

const float getConfFloat(const std::string& key) {
    return Conf::get()->getFloat(key);
}

const double getConfDouble(const std::string& key) {
    return Conf::get()->getDouble(key);
}

const bool getConfBoolean(const std::string& key) {
    return Conf::get()->getBoolean(key);
}

const bool hasCustomizedConfKey(const std::string& key) {
    return Conf::get()->hasCustomizedKey(key);
}
}
<|endoftext|>


<commit_before>/*
 * This file is part of TelepathyQt4
 *
 * Copyright (C) 2008 Collabora Ltd. <http://www.collabora.co.uk/>
 * Copyright (C) 2008 Nokia Corporation
 *
 * 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.
 *
 * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "cli-channel.h"

#include "_gen/cli-channel-body.hpp"
#include "_gen/cli-channel.moc.hpp"
#include "cli-channel.moc.hpp"

#include <QQueue>

#include "cli-dbus.h"
#include "constants.h"
#include "debug-internal.hpp"

namespace Telepathy
{
namespace Client
{

struct Channel::Private
{
    // Public object
    Channel& parent;

    // Optional interface proxies
    DBus::PropertiesInterface* properties;

    // Introspection
    Readiness readiness;
    QStringList interfaces;
    QQueue<void (Private::*)()> introspectQueue;

    // Introspected properties
    QString channelType;
    uint targetHandleType;
    uint targetHandle;

    Private(Channel& parent)
        : parent(parent)
    {
        debug() << "Creating new Channel";

        properties = 0;
        readiness = ReadinessJustCreated;

        debug() << "Connecting to Channel::Closed()";
        parent.connect(&parent,
                       SIGNAL(Closed()),
                       SLOT(onClosed()));

        introspectQueue.enqueue(&Private::introspectMain);
        continueIntrospection();
    }

    void introspectMain()
    {
        if (!properties) {
            properties = parent.propertiesInterface();
            Q_ASSERT(properties != 0);
        }

        debug() << "Calling Properties::GetAll(Channel)";
        QDBusPendingCallWatcher* watcher =
            new QDBusPendingCallWatcher(
                    properties->GetAll(TELEPATHY_INTERFACE_CHANNEL), &parent);
        parent.connect(watcher,
                       SIGNAL(finished(QDBusPendingCallWatcher*)),
                       SLOT(gotMainProperties(QDBusPendingCallWatcher*)));
    }

    void introspectMainFallbackChannelType()
    {
        debug() << "Calling Channel::GetChannelType()";
        QDBusPendingCallWatcher* watcher =
            new QDBusPendingCallWatcher(parent.GetChannelType(), &parent);
        parent.connect(watcher,
                       SIGNAL(finished(QDBusPendingCallWatcher*)),
                       SLOT(gotChannelType(QDBusPendingCallWatcher*)));
    }

    void introspectMainFallbackHandle()
    {
        debug() << "Calling Channel::GetHandle()";
        QDBusPendingCallWatcher* watcher =
            new QDBusPendingCallWatcher(parent.GetHandle(), &parent);
        parent.connect(watcher,
                       SIGNAL(finished(QDBusPendingCallWatcher*)),
                       SLOT(gotHandle(QDBusPendingCallWatcher*)));
    }

    void introspectMainFallbackInterfaces()
    {
        debug() << "Calling Channel::GetInterfaces()";
        QDBusPendingCallWatcher* watcher =
            new QDBusPendingCallWatcher(parent.GetInterfaces(), &parent);
        parent.connect(watcher,
                       SIGNAL(finished(QDBusPendingCallWatcher*)),
                       SLOT(gotInterfaces(QDBusPendingCallWatcher*)));
    }

    void continueIntrospection()
    {
        if (introspectQueue.isEmpty()) {
            if (readiness < ReadinessFull)
                changeReadiness(ReadinessFull);
        } else {
            (this->*introspectQueue.dequeue())();
        }
    }

    void extract01777MainProps(const QVariantMap& props)
    {
        bool haveProps = props.size() >= 4
                      && props.contains("ChannelType") && !qdbus_cast<QString>(props["ChannelType"]).isEmpty()
                      && props.contains("Interfaces")
                      && props.contains("TargetHandle")
                      && props.contains("TargetHandleType");

        if (!haveProps) {
            warning() << "No properties expected from a post-0.17.7 spec service in reply to Properties::GetAll(Channel), falling back to serial inspection";

            introspectQueue.enqueue(&Private::introspectMainFallbackChannelType);
            introspectQueue.enqueue(&Private::introspectMainFallbackHandle);
            introspectQueue.enqueue(&Private::introspectMainFallbackInterfaces);
        } else {
            debug() << " Found properties specified in 0.17.7";

            channelType = qdbus_cast<QString>(props["ChannelType"]);
            interfaces = qdbus_cast<QStringList>(props["Interfaces"]);
            targetHandle = qdbus_cast<uint>(props["TargetHandle"]);
            targetHandleType = qdbus_cast<uint>(props["TargetHandleType"]);

            nowHaveInterfaces();
        }
    }

    void nowHaveInterfaces()
    {
        debug() << "Channel has" << interfaces.size() << "optional interfaces:" << interfaces;

        for (QStringList::const_iterator i = interfaces.begin();
                                         i != interfaces.end();
                                         ++i) {
            // Enqueue introspection of any optional interfaces here
        }
    }

    void changeReadiness(Readiness newReadiness)
    {
        Q_ASSERT(newReadiness != readiness);

        switch (readiness) {
            case ReadinessJustCreated:
                break;
            case ReadinessFull:
                Q_ASSERT(newReadiness == ReadinessDead);
                break;
            case ReadinessDead:
            default:
                Q_ASSERT(false);
                break;
        }

        debug() << "Channel readiness changed from" << readiness << "to" << newReadiness;

        if (newReadiness == ReadinessFull) {
            debug() << "Channel fully ready";
            debug() << " Channel type" << channelType;
            debug() << " Target handle" << targetHandle;
            debug() << " Target handle type" << targetHandleType;
        } else {
            debug() << "R.I.P. Channel.";
        }

        readiness = newReadiness;
        emit parent.readinessChanged(newReadiness);
    }
};

Channel::Channel(const QString& serviceName,
                 const QString& objectPath,
                 QObject* parent)
    : ChannelInterface(serviceName, objectPath, parent),
      mPriv(new Private(*this))
{
}

Channel::Channel(const QDBusConnection& connection,
                 const QString& serviceName,
                 const QString& objectPath,
                 QObject* parent)
    : ChannelInterface(connection, serviceName, objectPath, parent),
      mPriv(new Private(*this))
{
}

Channel::~Channel()
{
    delete mPriv;
}

Channel::Readiness Channel::readiness() const
{
    return mPriv->readiness;
}

QStringList Channel::interfaces() const
{
    return mPriv->interfaces;
}

QString Channel::channelType() const
{
    return mPriv->channelType;
}

uint Channel::targetHandleType() const
{
    return mPriv->targetHandleType;
}

uint Channel::targetHandle() const
{
    return mPriv->targetHandle;
}

void Channel::gotMainProperties(QDBusPendingCallWatcher* watcher)
{
    QDBusPendingReply<QVariantMap> reply = *watcher;
    QVariantMap props;

    if (!reply.isError()) {
        debug() << "Got reply to Properties::GetAll(Channel)";
        props = reply.value();
    } else {
        warning().nospace() << "Properties::GetAll(Channel) failed with " << reply.error().name() << ": " << reply.error().message();
    }

    mPriv->extract01777MainProps(props);
    // Add extraction (and possible fallbacks) in similar functions, called from here

    mPriv->continueIntrospection();
}

void Channel::gotChannelType(QDBusPendingCallWatcher* watcher)
{
    QDBusPendingReply<QString> reply = *watcher;

    if (reply.isError()) {
        warning().nospace() << "Channel::GetChannelType() failed with " << reply.error().name() << ": " << reply.error().message() << ", Channel officially dead";
        if (mPriv->readiness != ReadinessDead)
            mPriv->changeReadiness(ReadinessDead);
        return;
    }

    debug() << "Got reply to fallback Channel::GetChannelType()";
    mPriv->channelType = reply.value();
    mPriv->continueIntrospection();
}

void Channel::gotHandle(QDBusPendingCallWatcher* watcher)
{
    QDBusPendingReply<uint, uint> reply = *watcher;

    if (reply.isError()) {
        warning().nospace() << "Channel::GetHandle() failed with " << reply.error().name() << ": " << reply.error().message() << ", Channel officially dead";
        if (mPriv->readiness != ReadinessDead)
            mPriv->changeReadiness(ReadinessDead);
        return;
    }

    debug() << "Got reply to fallback Channel::GetHandle()";
    mPriv->targetHandleType = reply.argumentAt<0>();
    mPriv->targetHandle = reply.argumentAt<1>();
    mPriv->continueIntrospection();
}

void Channel::gotInterfaces(QDBusPendingCallWatcher* watcher)
{
    QDBusPendingReply<QStringList> reply = *watcher;

    if (reply.isError()) {
        warning().nospace() << "Channel::GetInterfaces() failed with " << reply.error().name() << ": " << reply.error().message() << ", Channel officially dead";
        if (mPriv->readiness != ReadinessDead)
            mPriv->changeReadiness(ReadinessDead);
        return;
    }

    debug() << "Got reply to fallback Channel::GetInterfaces()";
    mPriv->interfaces = reply.value();
    mPriv->nowHaveInterfaces();
    mPriv->continueIntrospection();
}

void Channel::onClosed()
{
    debug() << "Got Channel::Closed";

    if (mPriv->readiness != ReadinessDead)
        mPriv->changeReadiness(ReadinessDead);
}

}
}
<commit_msg>Move initial continueIntrospection to Channel constructor, otherwise the priv pointer won't have been initialized<commit_after>/*
 * This file is part of TelepathyQt4
 *
 * Copyright (C) 2008 Collabora Ltd. <http://www.collabora.co.uk/>
 * Copyright (C) 2008 Nokia Corporation
 *
 * 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.
 *
 * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "cli-channel.h"

#include "_gen/cli-channel-body.hpp"
#include "_gen/cli-channel.moc.hpp"
#include "cli-channel.moc.hpp"

#include <QQueue>

#include "cli-dbus.h"
#include "constants.h"
#include "debug-internal.hpp"

namespace Telepathy
{
namespace Client
{

struct Channel::Private
{
    // Public object
    Channel& parent;

    // Optional interface proxies
    DBus::PropertiesInterface* properties;

    // Introspection
    Readiness readiness;
    QStringList interfaces;
    QQueue<void (Private::*)()> introspectQueue;

    // Introspected properties
    QString channelType;
    uint targetHandleType;
    uint targetHandle;

    Private(Channel& parent)
        : parent(parent)
    {
        debug() << "Creating new Channel";

        properties = 0;
        readiness = ReadinessJustCreated;

        debug() << "Connecting to Channel::Closed()";
        parent.connect(&parent,
                       SIGNAL(Closed()),
                       SLOT(onClosed()));

        introspectQueue.enqueue(&Private::introspectMain);
    }

    void introspectMain()
    {
        if (!properties) {
            properties = parent.propertiesInterface();
            Q_ASSERT(properties != 0);
        }

        debug() << "Calling Properties::GetAll(Channel)";
        QDBusPendingCallWatcher* watcher =
            new QDBusPendingCallWatcher(
                    properties->GetAll(TELEPATHY_INTERFACE_CHANNEL), &parent);
        parent.connect(watcher,
                       SIGNAL(finished(QDBusPendingCallWatcher*)),
                       SLOT(gotMainProperties(QDBusPendingCallWatcher*)));
    }

    void introspectMainFallbackChannelType()
    {
        debug() << "Calling Channel::GetChannelType()";
        QDBusPendingCallWatcher* watcher =
            new QDBusPendingCallWatcher(parent.GetChannelType(), &parent);
        parent.connect(watcher,
                       SIGNAL(finished(QDBusPendingCallWatcher*)),
                       SLOT(gotChannelType(QDBusPendingCallWatcher*)));
    }

    void introspectMainFallbackHandle()
    {
        debug() << "Calling Channel::GetHandle()";
        QDBusPendingCallWatcher* watcher =
            new QDBusPendingCallWatcher(parent.GetHandle(), &parent);
        parent.connect(watcher,
                       SIGNAL(finished(QDBusPendingCallWatcher*)),
                       SLOT(gotHandle(QDBusPendingCallWatcher*)));
    }

    void introspectMainFallbackInterfaces()
    {
        debug() << "Calling Channel::GetInterfaces()";
        QDBusPendingCallWatcher* watcher =
            new QDBusPendingCallWatcher(parent.GetInterfaces(), &parent);
        parent.connect(watcher,
                       SIGNAL(finished(QDBusPendingCallWatcher*)),
                       SLOT(gotInterfaces(QDBusPendingCallWatcher*)));
    }

    void continueIntrospection()
    {
        if (introspectQueue.isEmpty()) {
            if (readiness < ReadinessFull)
                changeReadiness(ReadinessFull);
        } else {
            (this->*introspectQueue.dequeue())();
        }
    }

    void extract01777MainProps(const QVariantMap& props)
    {
        bool haveProps = props.size() >= 4
                      && props.contains("ChannelType") && !qdbus_cast<QString>(props["ChannelType"]).isEmpty()
                      && props.contains("Interfaces")
                      && props.contains("TargetHandle")
                      && props.contains("TargetHandleType");

        if (!haveProps) {
            warning() << "No properties expected from a post-0.17.7 spec service in reply to Properties::GetAll(Channel), falling back to serial inspection";

            introspectQueue.enqueue(&Private::introspectMainFallbackChannelType);
            introspectQueue.enqueue(&Private::introspectMainFallbackHandle);
            introspectQueue.enqueue(&Private::introspectMainFallbackInterfaces);
        } else {
            debug() << " Found properties specified in 0.17.7";

            channelType = qdbus_cast<QString>(props["ChannelType"]);
            interfaces = qdbus_cast<QStringList>(props["Interfaces"]);
            targetHandle = qdbus_cast<uint>(props["TargetHandle"]);
            targetHandleType = qdbus_cast<uint>(props["TargetHandleType"]);

            nowHaveInterfaces();
        }
    }

    void nowHaveInterfaces()
    {
        debug() << "Channel has" << interfaces.size() << "optional interfaces:" << interfaces;

        for (QStringList::const_iterator i = interfaces.begin();
                                         i != interfaces.end();
                                         ++i) {
            // Enqueue introspection of any optional interfaces here
        }
    }

    void changeReadiness(Readiness newReadiness)
    {
        Q_ASSERT(newReadiness != readiness);

        switch (readiness) {
            case ReadinessJustCreated:
                break;
            case ReadinessFull:
                Q_ASSERT(newReadiness == ReadinessDead);
                break;
            case ReadinessDead:
            default:
                Q_ASSERT(false);
                break;
        }

        debug() << "Channel readiness changed from" << readiness << "to" << newReadiness;

        if (newReadiness == ReadinessFull) {
            debug() << "Channel fully ready";
            debug() << " Channel type" << channelType;
            debug() << " Target handle" << targetHandle;
            debug() << " Target handle type" << targetHandleType;
        } else {
            debug() << "R.I.P. Channel.";
        }

        readiness = newReadiness;
        emit parent.readinessChanged(newReadiness);
    }
};

Channel::Channel(const QString& serviceName,
                 const QString& objectPath,
                 QObject* parent)
    : ChannelInterface(serviceName, objectPath, parent),
      mPriv(new Private(*this))
{
    mPriv->continueIntrospection();
}

Channel::Channel(const QDBusConnection& connection,
                 const QString& serviceName,
                 const QString& objectPath,
                 QObject* parent)
    : ChannelInterface(connection, serviceName, objectPath, parent),
      mPriv(new Private(*this))
{
    mPriv->continueIntrospection();
}

Channel::~Channel()
{
    delete mPriv;
}

Channel::Readiness Channel::readiness() const
{
    return mPriv->readiness;
}

QStringList Channel::interfaces() const
{
    return mPriv->interfaces;
}

QString Channel::channelType() const
{
    return mPriv->channelType;
}

uint Channel::targetHandleType() const
{
    return mPriv->targetHandleType;
}

uint Channel::targetHandle() const
{
    return mPriv->targetHandle;
}

void Channel::gotMainProperties(QDBusPendingCallWatcher* watcher)
{
    QDBusPendingReply<QVariantMap> reply = *watcher;
    QVariantMap props;

    if (!reply.isError()) {
        debug() << "Got reply to Properties::GetAll(Channel)";
        props = reply.value();
    } else {
        warning().nospace() << "Properties::GetAll(Channel) failed with " << reply.error().name() << ": " << reply.error().message();
    }

    mPriv->extract01777MainProps(props);
    // Add extraction (and possible fallbacks) in similar functions, called from here

    mPriv->continueIntrospection();
}

void Channel::gotChannelType(QDBusPendingCallWatcher* watcher)
{
    QDBusPendingReply<QString> reply = *watcher;

    if (reply.isError()) {
        warning().nospace() << "Channel::GetChannelType() failed with " << reply.error().name() << ": " << reply.error().message() << ", Channel officially dead";
        if (mPriv->readiness != ReadinessDead)
            mPriv->changeReadiness(ReadinessDead);
        return;
    }

    debug() << "Got reply to fallback Channel::GetChannelType()";
    mPriv->channelType = reply.value();
    mPriv->continueIntrospection();
}

void Channel::gotHandle(QDBusPendingCallWatcher* watcher)
{
    QDBusPendingReply<uint, uint> reply = *watcher;

    if (reply.isError()) {
        warning().nospace() << "Channel::GetHandle() failed with " << reply.error().name() << ": " << reply.error().message() << ", Channel officially dead";
        if (mPriv->readiness != ReadinessDead)
            mPriv->changeReadiness(ReadinessDead);
        return;
    }

    debug() << "Got reply to fallback Channel::GetHandle()";
    mPriv->targetHandleType = reply.argumentAt<0>();
    mPriv->targetHandle = reply.argumentAt<1>();
    mPriv->continueIntrospection();
}

void Channel::gotInterfaces(QDBusPendingCallWatcher* watcher)
{
    QDBusPendingReply<QStringList> reply = *watcher;

    if (reply.isError()) {
        warning().nospace() << "Channel::GetInterfaces() failed with " << reply.error().name() << ": " << reply.error().message() << ", Channel officially dead";
        if (mPriv->readiness != ReadinessDead)
            mPriv->changeReadiness(ReadinessDead);
        return;
    }

    debug() << "Got reply to fallback Channel::GetInterfaces()";
    mPriv->interfaces = reply.value();
    mPriv->nowHaveInterfaces();
    mPriv->continueIntrospection();
}

void Channel::onClosed()
{
    debug() << "Got Channel::Closed";

    if (mPriv->readiness != ReadinessDead)
        mPriv->changeReadiness(ReadinessDead);
}

}
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <unotest/filters-test.hxx>
#include <osl/file.hxx>
#include <osl/thread.h>
#include <rtl/cipher.h>

#include "cppunit/TestAssert.h"

namespace test {

void decode(const OUString& rIn, const OUString &rOut)
{
    rtlCipher cipher = rtl_cipher_create(rtl_Cipher_AlgorithmARCFOUR, rtl_Cipher_ModeStream);
    CPPUNIT_ASSERT_MESSAGE("cipher creation failed", cipher != 0);

    //mcrypt --bare -a arcfour -o hex -k 435645 -s 3
    const sal_uInt8 aKey[3] = {'C', 'V', 'E'};

    rtlCipherError result = rtl_cipher_init(cipher, rtl_Cipher_DirectionDecode, aKey, SAL_N_ELEMENTS(aKey), 0, 0);

    CPPUNIT_ASSERT_MESSAGE("cipher init failed", result == rtl_Cipher_E_None);

    osl::File aIn(rIn);
    CPPUNIT_ASSERT(osl::FileBase::E_None == aIn.open(osl_File_OpenFlag_Read));

    osl::File aOut(rOut);
    CPPUNIT_ASSERT(osl::FileBase::E_None == aOut.open(osl_File_OpenFlag_Write));

    sal_uInt8 in[8192];
    sal_uInt8 out[8192];
    sal_uInt64 nBytesRead, nBytesWritten;
    while(true)
    {
        CPPUNIT_ASSERT(osl::FileBase::E_None == aIn.read(in, sizeof(in), nBytesRead));
        if (!nBytesRead)
            break;
        CPPUNIT_ASSERT(rtl_Cipher_E_None == rtl_cipher_decode(cipher, in, nBytesRead, out, sizeof(out)));
        CPPUNIT_ASSERT(osl::FileBase::E_None == aOut.write(out, nBytesRead, nBytesWritten));
        CPPUNIT_ASSERT(nBytesRead == nBytesWritten);
    }

    rtl_cipher_destroy(cipher);
}

void FiltersTest::recursiveScan(filterStatus nExpected,
    const OUString &rFilter, const OUString &rURL,
    const OUString &rUserData, unsigned int nFilterFlags,
    unsigned int nClipboardID, unsigned int nFilterVersion, bool bExport)
{
    osl::Directory aDir(rURL);

    CPPUNIT_ASSERT(osl::FileBase::E_None == aDir.open());
    osl::DirectoryItem aItem;
    osl::FileStatus aFileStatus(osl_FileStatus_Mask_FileURL|osl_FileStatus_Mask_Type);
    while (aDir.getNextItem(aItem) == osl::FileBase::E_None)
    {
        aItem.getFileStatus(aFileStatus);
        OUString sURL = aFileStatus.getFileURL();
        if (aFileStatus.getFileType() == osl::FileStatus::Directory)
        {
            recursiveScan(nExpected, rFilter, sURL, rUserData,
                nFilterFlags, nClipboardID, nFilterVersion, bExport);
        }
        else
        {
            OUString sTmpFile;
            bool bEncrypted = false;

            sal_Int32 nLastSlash = sURL.lastIndexOf('/');

            if ((nLastSlash != -1) && (nLastSlash+1 < sURL.getLength()))
            {
                //ignore .files
                if (sURL[nLastSlash+1] == '.')
                    continue;

                if (
                    (sURL.match("BID", nLastSlash+1)) ||
                    (sURL.match("CVE", nLastSlash+1)) ||
                    (sURL.match("EDB", nLastSlash+1))
                   )
                {
                    bEncrypted = true;
                }
            }

            OString aRes(OUStringToOString(sURL,
                osl_getThreadTextEncoding()));

            if (bEncrypted)
            {
                CPPUNIT_ASSERT(osl::FileBase::E_None == osl::FileBase::createTempFile(NULL, NULL, &sTmpFile));
                decode(sURL, sTmpFile);
                sURL = sTmpFile;
            }

            //output name early, so in the case of a hang, the name of
            //the hanging input file is visible
            fprintf(stderr, "%s,", aRes.getStr());
            sal_uInt32 nStartTime = osl_getGlobalTimer();
            bool bRes;
            if (!bExport)
                bRes = load(rFilter, sURL, rUserData, nFilterFlags,
                            nClipboardID, nFilterVersion);
            else
                bRes = save(rFilter, sURL, rUserData, nFilterFlags,
                            nClipboardID, nFilterVersion);
            sal_uInt32 nEndTime = osl_getGlobalTimer();

            if (bEncrypted)
                CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, osl::File::remove(sTmpFile));

            fprintf(stderr, "%s,%" SAL_PRIuUINT32"\n",
                bRes?"Pass":"Fail",nEndTime-nStartTime);
            if (nExpected == test::indeterminate)
                continue;
            CPPUNIT_ASSERT_MESSAGE(aRes.getStr(), bRes == (nExpected == test::pass));
        }
    }
    CPPUNIT_ASSERT(osl::FileBase::E_None == aDir.close());
}

void FiltersTest::testDir(const OUString &rFilter,
    const OUString &rURL, const OUString &rUserData,
    unsigned int nFilterFlags, unsigned int nClipboardID,
    unsigned int nFilterVersion, bool bExport)
{
    fprintf(stderr, "File tested,Test Result,Execution tools::Time (ms)\n");
    recursiveScan(test::pass, rFilter,
        rURL + "pass",
        rUserData, nFilterFlags, nClipboardID, nFilterVersion, bExport);
    recursiveScan(test::fail, rFilter,
        rURL + "fail",
        rUserData, nFilterFlags, nClipboardID, nFilterVersion, bExport);
    recursiveScan(test::indeterminate, rFilter,
        rURL + "indeterminate",
        rUserData, nFilterFlags, nClipboardID, nFilterVersion, bExport);
}

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>tweak the assert message so its readable when an errors happens<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <unotest/filters-test.hxx>
#include <osl/file.hxx>
#include <osl/thread.h>
#include <rtl/cipher.h>

#include "cppunit/TestAssert.h"

namespace test {

void decode(const OUString& rIn, const OUString &rOut)
{
    rtlCipher cipher = rtl_cipher_create(rtl_Cipher_AlgorithmARCFOUR, rtl_Cipher_ModeStream);
    CPPUNIT_ASSERT_MESSAGE("cipher creation failed", cipher != 0);

    //mcrypt --bare -a arcfour -o hex -k 435645 -s 3
    const sal_uInt8 aKey[3] = {'C', 'V', 'E'};

    rtlCipherError result = rtl_cipher_init(cipher, rtl_Cipher_DirectionDecode, aKey, SAL_N_ELEMENTS(aKey), 0, 0);

    CPPUNIT_ASSERT_MESSAGE("cipher init failed", result == rtl_Cipher_E_None);

    osl::File aIn(rIn);
    CPPUNIT_ASSERT(osl::FileBase::E_None == aIn.open(osl_File_OpenFlag_Read));

    osl::File aOut(rOut);
    CPPUNIT_ASSERT(osl::FileBase::E_None == aOut.open(osl_File_OpenFlag_Write));

    sal_uInt8 in[8192];
    sal_uInt8 out[8192];
    sal_uInt64 nBytesRead, nBytesWritten;
    while(true)
    {
        CPPUNIT_ASSERT(osl::FileBase::E_None == aIn.read(in, sizeof(in), nBytesRead));
        if (!nBytesRead)
            break;
        CPPUNIT_ASSERT(rtl_Cipher_E_None == rtl_cipher_decode(cipher, in, nBytesRead, out, sizeof(out)));
        CPPUNIT_ASSERT(osl::FileBase::E_None == aOut.write(out, nBytesRead, nBytesWritten));
        CPPUNIT_ASSERT(nBytesRead == nBytesWritten);
    }

    rtl_cipher_destroy(cipher);
}

void FiltersTest::recursiveScan(filterStatus nExpected,
    const OUString &rFilter, const OUString &rURL,
    const OUString &rUserData, unsigned int nFilterFlags,
    unsigned int nClipboardID, unsigned int nFilterVersion, bool bExport)
{
    osl::Directory aDir(rURL);

    CPPUNIT_ASSERT(osl::FileBase::E_None == aDir.open());
    osl::DirectoryItem aItem;
    osl::FileStatus aFileStatus(osl_FileStatus_Mask_FileURL|osl_FileStatus_Mask_Type);
    while (aDir.getNextItem(aItem) == osl::FileBase::E_None)
    {
        aItem.getFileStatus(aFileStatus);
        OUString sURL = aFileStatus.getFileURL();
        if (aFileStatus.getFileType() == osl::FileStatus::Directory)
        {
            recursiveScan(nExpected, rFilter, sURL, rUserData,
                nFilterFlags, nClipboardID, nFilterVersion, bExport);
        }
        else
        {
            OUString sTmpFile;
            bool bEncrypted = false;

            sal_Int32 nLastSlash = sURL.lastIndexOf('/');

            if ((nLastSlash != -1) && (nLastSlash+1 < sURL.getLength()))
            {
                //ignore .files
                if (sURL[nLastSlash+1] == '.')
                    continue;

                if (
                    (sURL.match("BID", nLastSlash+1)) ||
                    (sURL.match("CVE", nLastSlash+1)) ||
                    (sURL.match("EDB", nLastSlash+1))
                   )
                {
                    bEncrypted = true;
                }
            }

            OString aRes(OUStringToOString(sURL,
                osl_getThreadTextEncoding()));

            if (bEncrypted)
            {
                CPPUNIT_ASSERT(osl::FileBase::E_None == osl::FileBase::createTempFile(NULL, NULL, &sTmpFile));
                decode(sURL, sTmpFile);
                sURL = sTmpFile;
            }

            //output name early, so in the case of a hang, the name of
            //the hanging input file is visible
            fprintf(stderr, "%s,", aRes.getStr());
            sal_uInt32 nStartTime = osl_getGlobalTimer();
            bool bRes;
            if (!bExport)
                bRes = load(rFilter, sURL, rUserData, nFilterFlags,
                            nClipboardID, nFilterVersion);
            else
                bRes = save(rFilter, sURL, rUserData, nFilterFlags,
                            nClipboardID, nFilterVersion);
            sal_uInt32 nEndTime = osl_getGlobalTimer();

            if (bEncrypted)
                CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, osl::File::remove(sTmpFile));

            fprintf(stderr, "%s,%" SAL_PRIuUINT32"\n",
                bRes?"Pass":"Fail",nEndTime-nStartTime);
            if (nExpected == test::indeterminate)
                continue;
            filterStatus nResult = bRes ? test::pass : test::fail;
            CPPUNIT_ASSERT_MESSAGE(aRes.getStr(), nResult == nExpected);
        }
    }
    CPPUNIT_ASSERT(osl::FileBase::E_None == aDir.close());
}

void FiltersTest::testDir(const OUString &rFilter,
    const OUString &rURL, const OUString &rUserData,
    unsigned int nFilterFlags, unsigned int nClipboardID,
    unsigned int nFilterVersion, bool bExport)
{
    fprintf(stderr, "File tested,Test Result,Execution tools::Time (ms)\n");
    recursiveScan(test::pass, rFilter,
        rURL + "pass",
        rUserData, nFilterFlags, nClipboardID, nFilterVersion, bExport);
    recursiveScan(test::fail, rFilter,
        rURL + "fail",
        rUserData, nFilterFlags, nClipboardID, nFilterVersion, bExport);
    recursiveScan(test::indeterminate, rFilter,
        rURL + "indeterminate",
        rUserData, nFilterFlags, nClipboardID, nFilterVersion, bExport);
}

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: configmgr.hxx,v $
 *
 *  $Revision: 1.18 $
 *
 *  last change: $Author: kz $ $Date: 2005-07-12 14:22:42 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  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., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _UTL_CONFIGMGR_HXX_
#define _UTL_CONFIGMGR_HXX_

#ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
#include <com/sun/star/uno/Reference.h>
#endif
#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif
#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif
#ifndef INCLUDED_UNOTOOLSDLLAPI_H
#include "unotools/unotoolsdllapi.h"
#endif

//-----------------------------------------------------------------------------
namespace com{ namespace sun{ namespace star{
    namespace lang{
        class XMultiServiceFactory;
    }
    namespace container{
        class XHierarchicalNameAccess;
    }
}}}

//-----------------------------------------------------------------------------
namespace utl
{
    struct ConfigMgr_Impl;
    class ConfigItem;
    class UNOTOOLS_DLLPUBLIC ConfigManager
    {
            ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >
                                xConfigurationProvider;
            ConfigMgr_Impl*     pMgrImpl;

            static  ConfigManager*  pConfigManager;
        public:
            ConfigManager();
            ConfigManager(com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory > xConfigProvider);
            ~ConfigManager();

            ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >
                GetConfigurationProvider();

            ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >
                GetLocalConfigurationProvider();

            com::sun::star::uno::Reference< com::sun::star::container::XHierarchicalNameAccess>
                AddConfigItem(utl::ConfigItem& rCfgItem);

            void RegisterConfigItem(utl::ConfigItem& rCfgItem);
            com::sun::star::uno::Reference< com::sun::star::container::XHierarchicalNameAccess>
                AcquireTree(utl::ConfigItem& rCfgItem);

            void RemoveConfigItem(utl::ConfigItem& rCfgItem);

            void StoreConfigItems();

            static ConfigManager*           GetConfigManager();
            static void                     RemoveConfigManager();
            static rtl::OUString            GetConfigBaseURL();

            enum ConfigProperty
            {
                INSTALLPATH,        // deprecated. don't use
                LOCALE,
                OFFICEINSTALL,      // deprecated. don't use
                USERINSTALLURL,     // deprecated. don't use
                OFFICEINSTALLURL,   // deprecated. don't use
                PRODUCTNAME,
                PRODUCTVERSION,
                PRODUCTEXTENSION,
                DEFAULTCURRENCY,
                PRODUCTXMLFILEFORMATNAME,
                PRODUCTXMLFILEFORMATVERSION,
                WRITERCOMPATIBILITYVERSIONOOO11
            };
            //direct readonly access to some special configuration elements
            static com::sun::star::uno::Any GetDirectConfigProperty(ConfigProperty eProp);

            sal_Bool        IsLocalConfigProvider();
            com::sun::star::uno::Reference< com::sun::star::container::XHierarchicalNameAccess>
                GetHierarchyAccess(const rtl::OUString& rFullPath);
            com::sun::star::uno::Any GetLocalProperty(const rtl::OUString& rProperty);
            void PutLocalProperty(const rtl::OUString& , const com::sun::star::uno::Any& rValue);

    };
}//namespace utl
#endif //_UTL_CONFIGMGR_HXX_
<commit_msg>INTEGRATION: CWS ooo19126 (1.18.20); FILE MERGED 2005/09/05 14:00:50 rt 1.18.20.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: configmgr.hxx,v $
 *
 *  $Revision: 1.19 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 09:28:42 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _UTL_CONFIGMGR_HXX_
#define _UTL_CONFIGMGR_HXX_

#ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
#include <com/sun/star/uno/Reference.h>
#endif
#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif
#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif
#ifndef INCLUDED_UNOTOOLSDLLAPI_H
#include "unotools/unotoolsdllapi.h"
#endif

//-----------------------------------------------------------------------------
namespace com{ namespace sun{ namespace star{
    namespace lang{
        class XMultiServiceFactory;
    }
    namespace container{
        class XHierarchicalNameAccess;
    }
}}}

//-----------------------------------------------------------------------------
namespace utl
{
    struct ConfigMgr_Impl;
    class ConfigItem;
    class UNOTOOLS_DLLPUBLIC ConfigManager
    {
            ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >
                                xConfigurationProvider;
            ConfigMgr_Impl*     pMgrImpl;

            static  ConfigManager*  pConfigManager;
        public:
            ConfigManager();
            ConfigManager(com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory > xConfigProvider);
            ~ConfigManager();

            ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >
                GetConfigurationProvider();

            ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >
                GetLocalConfigurationProvider();

            com::sun::star::uno::Reference< com::sun::star::container::XHierarchicalNameAccess>
                AddConfigItem(utl::ConfigItem& rCfgItem);

            void RegisterConfigItem(utl::ConfigItem& rCfgItem);
            com::sun::star::uno::Reference< com::sun::star::container::XHierarchicalNameAccess>
                AcquireTree(utl::ConfigItem& rCfgItem);

            void RemoveConfigItem(utl::ConfigItem& rCfgItem);

            void StoreConfigItems();

            static ConfigManager*           GetConfigManager();
            static void                     RemoveConfigManager();
            static rtl::OUString            GetConfigBaseURL();

            enum ConfigProperty
            {
                INSTALLPATH,        // deprecated. don't use
                LOCALE,
                OFFICEINSTALL,      // deprecated. don't use
                USERINSTALLURL,     // deprecated. don't use
                OFFICEINSTALLURL,   // deprecated. don't use
                PRODUCTNAME,
                PRODUCTVERSION,
                PRODUCTEXTENSION,
                DEFAULTCURRENCY,
                PRODUCTXMLFILEFORMATNAME,
                PRODUCTXMLFILEFORMATVERSION,
                WRITERCOMPATIBILITYVERSIONOOO11
            };
            //direct readonly access to some special configuration elements
            static com::sun::star::uno::Any GetDirectConfigProperty(ConfigProperty eProp);

            sal_Bool        IsLocalConfigProvider();
            com::sun::star::uno::Reference< com::sun::star::container::XHierarchicalNameAccess>
                GetHierarchyAccess(const rtl::OUString& rFullPath);
            com::sun::star::uno::Any GetLocalProperty(const rtl::OUString& rProperty);
            void PutLocalProperty(const rtl::OUString& , const com::sun::star::uno::Any& rValue);

    };
}//namespace utl
#endif //_UTL_CONFIGMGR_HXX_
<|endoftext|>


<commit_before>/**
 * @file
 *
 * @brief deserialization implementation for xerces plugin
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

#include "deserializer.hpp"
#include "util.hpp"

#include <xercesc/dom/DOM.hpp>
#include <xercesc/dom/DOMAttr.hpp>
#include <xercesc/dom/DOMDocument.hpp>
#include <xercesc/dom/DOMImplementation.hpp>
#include <xercesc/dom/DOMNode.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>

#include <algorithm>
#include <iostream>
#include <locale>
#include <map>

#include <kdbease.h>
#include <kdblogger.h>
#include <key.hpp>

XERCES_CPP_NAMESPACE_USE
using namespace std;
using namespace kdb;
using namespace xerces;

namespace
{

XercesPtr<DOMDocument> doc2dom (std::string const & src)
{
	XercesDOMParser parser;
	parser.setValidationScheme (XercesDOMParser::Val_Auto);

	parser.parse (asXMLCh (src));
	return XercesPtr<DOMDocument> (parser.adoptDocument ());
}

string trim (string const & str)
{
	stringstream ss (str);
	string to;
	string trimmed;

	while (getline (ss, to, '\n'))
	{
		// Remove whitespace lines, most likely caused by pretty printing
		if (!all_of (to.begin (), to.end (), [](char c) { return isspace (c, locale ()); })) trimmed += to;
	}

	return trimmed;
}

string getElementText (DOMNode const * parent)
{
	string str;

	for (auto child = parent->getFirstChild (); child != NULL; child = child->getNextSibling ())
	{
		if (DOMNode::NodeType::TEXT_NODE == child->getNodeType () || DOMNode::NodeType::CDATA_SECTION_NODE == child->getNodeType ())
		{
			DOMText * data = dynamic_cast<DOMText *> (child);
			if (!data->getIsElementContentWhitespace ()) str += toStr (data->getData ());
		}
	}

	// Trim whitespace that is most likely due to pretty printing
	return trim (str);
}

Key newNodeKey (Key const & parent, DOMNode const * node)
{
	Key childKey (parent.getFullName (), KEY_END);
	const string keyName = toStr (node->getNodeName ());
	childKey.addBaseName (keyName);
	return childKey;
}

void node2key (DOMNode const * n, Key const & parent, KeySet const & ks, Key & current)
{
	const string keyName = toStr (n->getNodeName ());
	ELEKTRA_LOG_DEBUG ("Encountered Element: %s with parent %s", keyName.c_str (), current.getFullName ().c_str ());

	if (!ks.size ())
	{ // we map the parent key to the xml root element
		// preserve the original name if it is different
		auto parentName = parent.rbegin ();
		if (parentName != parent.rend () && (*parentName) != keyName)
		{
			ELEKTRA_LOG_DEBUG ("parent name %s differs from root element name %s", (*parentName).c_str (), keyName.c_str ());
			current.setMeta (ELEKTRA_XERCES_ORIGINAL_ROOT_NAME, keyName);
		}
	}
	else
		current.addBaseName (keyName);

	const string text = getElementText (n);
	current.set<string> (text);

	if (!current.isValid ()) throw XercesPluginException ("Given keyset contains invalid keys to serialize");

	ELEKTRA_LOG_DEBUG ("new parent is %s with value %s", current.getFullName ().c_str (), current.get<string> ().c_str ());

	if (n->hasAttributes ())
	{
		// get all the attributes of the node
		DOMNamedNodeMap * pAttributes = n->getAttributes ();
		const XMLSize_t nSize = pAttributes->getLength ();
		ELEKTRA_LOG_DEBUG ("\tAttributes");
		for (XMLSize_t i = 0; i < nSize; ++i)
		{
			DOMAttr * pAttributeNode = dynamic_cast<DOMAttr *> (pAttributes->item (i));
			ELEKTRA_LOG_DEBUG ("\t%s=%s", asCStr (pAttributeNode->getName ()), asCStr (pAttributeNode->getValue ()));
			current.setMeta (toStr (pAttributeNode->getName ()), toStr (pAttributeNode->getValue ()));
		}
	}
}

void analyzeMultipleElements (DOMNode const * n, Key const & current, map<Key, bool> & arrays)
{
	for (auto child = n->getFirstChild (); child != 0; child = child->getNextSibling ())
	{
		Key childKey = newNodeKey (current, child);

		auto it = arrays.find (childKey);
		if (it != arrays.end ())
		{
			if (!it->second)
			{
				ELEKTRA_LOG_DEBUG ("There are multiple elements of %s, mapping this as an array",
						   childKey.getFullName ().c_str ());
				arrays[childKey] = true;
			}
		}
		else
			arrays[childKey] = false;
	}
}

Key newArrayKey (Key const & arrayKey, KeySet & ks)
{
	KeySet result (elektraArrayGet (arrayKey.getKey (), ks.getKeySet ()));
	if (!result.size ())
	{
		Key arrayBaseKey = arrayKey.dup ();
		arrayBaseKey.addBaseName ("#");
		result.append (arrayBaseKey);
	}
	return elektraArrayGetNextKey (result.getKeySet ());
}

void dom2keyset (DOMNode const * n, Key const & parent, KeySet & ks, map<Key, bool> & arrays)
{
	if (n)
	{
		Key current (parent.getFullName (), KEY_END);

		if (n->getNodeType () == DOMNode::ELEMENT_NODE)
		{
			node2key (n, parent, ks, current);

			auto it = arrays.find (current);
			const bool array = it != arrays.end () && it->second;
			// Multiple elements with that name, map as an array
			if (array) current.addBaseName (newArrayKey (current, ks).getBaseName ());

			// Only add keys with a value, attributes or leafs or the root to preserve the original name or array keys
			if (n->hasAttributes () || !current.getString ().empty () || !n->getFirstChild () || !ks.size () || array)
			{
				ELEKTRA_LOG_DEBUG ("adding %s", current.getFullName ().c_str ());
				ks.append (current);
			}
			else
				ELEKTRA_LOG_DEBUG ("skipping %s", current.getFullName ().c_str ());
		}
		// the first level cannot have more children so its enough to check that here
		analyzeMultipleElements (n, current, arrays);
		for (auto child = n->getFirstChild (); child != 0; child = child->getNextSibling ())
			dom2keyset (child, current, ks, arrays);
	}
}

} // namespace

void xerces::deserialize (Key const & parentKey, KeySet & ks)
{
	if (!parentKey.isValid ()) throw XercesPluginException ("Parent key is invalid");
	if (parentKey.get<string> ().empty ()) throw XercesPluginException ("No source file specified as key value");

	ELEKTRA_LOG_DEBUG ("deserializing relative to %s from file %s", parentKey.getFullName ().c_str (),
			   parentKey.get<string> ().c_str ());
	auto document = doc2dom (parentKey.get<string> ());
	map<Key, bool> arrays;
	if (document) dom2keyset (document->getDocumentElement (), parentKey, ks, arrays);
}
<commit_msg>Xerces: Fix warning reported by GCC<commit_after>/**
 * @file
 *
 * @brief deserialization implementation for xerces plugin
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

#include "deserializer.hpp"
#include "util.hpp"

#include <xercesc/dom/DOM.hpp>
#include <xercesc/dom/DOMAttr.hpp>
#include <xercesc/dom/DOMDocument.hpp>
#include <xercesc/dom/DOMImplementation.hpp>
#include <xercesc/dom/DOMNode.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>

#include <algorithm>
#include <iostream>
#include <locale>
#include <map>

#include <kdbease.h>
#include <kdblogger.h>
#include <key.hpp>

XERCES_CPP_NAMESPACE_USE
using namespace std;
using namespace kdb;
using namespace xerces;

namespace
{

XercesPtr<DOMDocument> doc2dom (std::string const & src)
{
	XercesDOMParser parser;
	parser.setValidationScheme (XercesDOMParser::Val_Auto);

	parser.parse (asXMLCh (src));
	return XercesPtr<DOMDocument> (parser.adoptDocument ());
}

string trim (string const & str)
{
	stringstream ss (str);
	string to;
	string trimmed;

	while (getline (ss, to, '\n'))
	{
		// Remove whitespace lines, most likely caused by pretty printing
		if (!all_of (to.begin (), to.end (), [](char c) { return isspace (c, locale ()); })) trimmed += to;
	}

	return trimmed;
}

string getElementText (DOMNode const * parent)
{
	string str;

	for (auto child = parent->getFirstChild (); child != NULL; child = child->getNextSibling ())
	{
		if (DOMNode::NodeType::TEXT_NODE == child->getNodeType () || DOMNode::NodeType::CDATA_SECTION_NODE == child->getNodeType ())
		{
			DOMText * data = dynamic_cast<DOMText *> (child);
			if (!data->getIsElementContentWhitespace ()) str += toStr (data->getData ());
		}
	}

	// Trim whitespace that is most likely due to pretty printing
	return trim (str);
}

Key newNodeKey (Key const & parent, DOMNode const * node)
{
	Key childKey (parent.getFullName (), KEY_END);
	const string keyName = toStr (node->getNodeName ());
	childKey.addBaseName (keyName);
	return childKey;
}

void node2key (DOMNode const * n, Key const & parent, KeySet const & ks, Key & current)
{
	const string keyName = toStr (n->getNodeName ());
	ELEKTRA_LOG_DEBUG ("Encountered Element: %s with parent %s", keyName.c_str (), current.getFullName ().c_str ());

	if (!ks.size ())
	{ // we map the parent key to the xml root element
		// preserve the original name if it is different
		auto parentName = parent.rbegin ();
		if (parentName != parent.rend () && (*parentName) != keyName)
		{
			ELEKTRA_LOG_DEBUG ("parent name %s differs from root element name %s", (*parentName).c_str (), keyName.c_str ());
			current.setMeta (ELEKTRA_XERCES_ORIGINAL_ROOT_NAME, keyName);
		}
	}
	else
		current.addBaseName (keyName);

	const string text = getElementText (n);
	current.set<string> (text);

	if (!current.isValid ()) throw XercesPluginException ("Given keyset contains invalid keys to serialize");

	ELEKTRA_LOG_DEBUG ("new parent is %s with value %s", current.getFullName ().c_str (), current.get<string> ().c_str ());

	if (n->hasAttributes ())
	{
		// get all the attributes of the node
		DOMNamedNodeMap * pAttributes = n->getAttributes ();
		const XMLSize_t nSize = pAttributes->getLength ();
		ELEKTRA_LOG_DEBUG ("\tAttributes");
		for (XMLSize_t i = 0; i < nSize; ++i)
		{
			DOMAttr * pAttributeNode = dynamic_cast<DOMAttr *> (pAttributes->item (i));
			ELEKTRA_LOG_DEBUG ("\t%s=%s", asCStr (pAttributeNode->getName ()), asCStr (pAttributeNode->getValue ()));
			current.setMeta (toStr (pAttributeNode->getName ()), toStr (pAttributeNode->getValue ()));
		}
	}
}

void analyzeMultipleElements (DOMNode const * n, Key const & current, map<Key, bool> & arrays)
{
	for (auto child = n->getFirstChild (); child != 0; child = child->getNextSibling ())
	{
		Key childKey = newNodeKey (current, child);

		auto it = arrays.find (childKey);
		if (it != arrays.end ())
		{
			if (!it->second)
			{
				ELEKTRA_LOG_DEBUG ("There are multiple elements of %s, mapping this as an array",
						   childKey.getFullName ().c_str ());
				arrays[childKey] = true;
			}
		}
		else
			arrays[childKey] = false;
	}
}

Key newArrayKey (Key const & arrayKey, KeySet & ks)
{
	KeySet result (elektraArrayGet (arrayKey.getKey (), ks.getKeySet ()));
	if (!result.size ())
	{
		Key arrayBaseKey = arrayKey.dup ();
		arrayBaseKey.addBaseName ("#");
		result.append (arrayBaseKey);
	}
	return elektraArrayGetNextKey (result.getKeySet ());
}

void dom2keyset (DOMNode const * n, Key const & parent, KeySet & ks, map<Key, bool> & arrays)
{
	if (n)
	{
		Key current (parent.getFullName (), KEY_END);

		if (n->getNodeType () == DOMNode::ELEMENT_NODE)
		{
			node2key (n, parent, ks, current);

			auto it = arrays.find (current);
			const bool array = it != arrays.end () && it->second;
			// Multiple elements with that name, map as an array
			if (array) current.addBaseName (newArrayKey (current, ks).getBaseName ());

			// Only add keys with a value, attributes or leafs or the root to preserve the original name or array keys
			if (n->hasAttributes () || !current.getString ().empty () || !n->getFirstChild () || !ks.size () || array)
			{
				ELEKTRA_LOG_DEBUG ("adding %s", current.getFullName ().c_str ());
				ks.append (current);
			}
			else
			{
				ELEKTRA_LOG_DEBUG ("skipping %s", current.getFullName ().c_str ());
			}
		}
		// the first level cannot have more children so its enough to check that here
		analyzeMultipleElements (n, current, arrays);
		for (auto child = n->getFirstChild (); child != 0; child = child->getNextSibling ())
			dom2keyset (child, current, ks, arrays);
	}
}

} // namespace

void xerces::deserialize (Key const & parentKey, KeySet & ks)
{
	if (!parentKey.isValid ()) throw XercesPluginException ("Parent key is invalid");
	if (parentKey.get<string> ().empty ()) throw XercesPluginException ("No source file specified as key value");

	ELEKTRA_LOG_DEBUG ("deserializing relative to %s from file %s", parentKey.getFullName ().c_str (),
			   parentKey.get<string> ().c_str ());
	auto document = doc2dom (parentKey.get<string> ());
	map<Key, bool> arrays;
	if (document) dom2keyset (document->getDocumentElement (), parentKey, ks, arrays);
}
<|endoftext|>


<commit_before>/*
 * Super Entity Game Server Project
 * http://segs.sf.net/
 * Copyright (c) 2006 - 2016 Super Entity Game Server Team (see Authors.txt)
 * This software is licensed! (See License.txt for details)
 *
 */

// segs includes

#include "CharacterDatabase.h"
#include "AccountInfo.h"
#include "AdminServer.h"
#include "Character.h"
#include "Costume.h"

#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlDriver>
#include <QtCore/QDebug>
#include <QtSql/QSqlError>
#include <cstdlib>
#include <cstdio>
using namespace std;

CharacterDatabase::~CharacterDatabase()
{
    if(m_db)
        m_db->close();
}
static bool prepQuery(QSqlQuery &qr,const QString &txt) {
    if(!qr.prepare(txt)) {
        qDebug() << "SQL_ERROR:"<<qr.lastError();
        return false;
    }
    return true;
}
static bool doIt(QSqlQuery &qr) {
    if(!qr.exec()) {
        qDebug() << "SQL_ERROR:"<<qr.lastError();
        return false;
    }
    return true;
}
void CharacterDatabase::on_connected(QSqlDatabase *db)
{
    m_db = db;
    if(!db)
        return;

    m_prepared_fill = QSqlQuery(*db);
    m_prepared_account_insert = QSqlQuery(*db);
    m_prepared_char_insert = QSqlQuery(*db);
    m_prepared_costume_insert = QSqlQuery(*db);
    m_prepared_char_select = QSqlQuery(*db);
    m_prepared_account_select = QSqlQuery(*db);
    m_prepared_char_exists = QSqlQuery(*db);
    m_prepared_char_delete = QSqlQuery(*db);

    prepQuery(m_prepared_fill,"SELECT * FROM costume WHERE character_id=? AND costume_index=?");
    prepQuery(m_prepared_account_insert,"INSERT INTO accounts  (account_id,max_slots) VALUES (?,?)");
    prepQuery(m_prepared_char_insert,
                "INSERT INTO characters  "
                "(char_level,slot_index,account_id,char_name,archetype,origin,bodytype,current_map) "
                "VALUES "
                "(?,?,?,?,?,?,?,?)");
    prepQuery(m_prepared_costume_insert,
                "INSERT INTO costume (character_id,costume_index,skin_color,parts) VALUES "
                "(?,?,?,?)");
    prepQuery(m_prepared_char_select,"SELECT * FROM characters WHERE account_id=? AND slot_index=?");
    prepQuery(m_prepared_account_select,"SELECT * FROM accounts WHERE account_id=?");
    prepQuery(m_prepared_char_exists,"SELECT exists (SELECT 1 FROM characters WHERE char_name = $1 LIMIT 1)");
    prepQuery(m_prepared_char_delete,"DELETE FROM characters WHERE account_id=? AND slot_index=?");
}

// UserToken,
bool CharacterDatabase::remove_character(AccountInfo *c,int8_t slot_idx)
{
    assert(c!=nullptr);
    m_prepared_char_delete.bindValue(0,quint64(c->account_server_id()));
    m_prepared_char_delete.bindValue(1,(uint32_t)slot_idx);
    if(!doIt(m_prepared_char_delete))
        return false;
    return true;
}
bool CharacterDatabase::named_character_exists(const QString &name)
{
    m_prepared_char_exists.bindValue(0,name);
    if(!doIt(m_prepared_char_exists))
        return false;

    if(!m_prepared_char_exists.next())
        return false;
    // TODO: handle case of multiple accounts with same name ?
    return m_prepared_char_exists.value(0).toBool();
}
bool CharacterDatabase::fill( AccountInfo *c )
{
    assert(c&&c->account_server_id());

    m_prepared_account_select.bindValue(0,quint64(c->account_server_id()));
    if(!doIt(m_prepared_account_select))
        return false;

    if(!m_prepared_account_select.next())
        return false;
    // TODO: handle case of multiple accounts with same name ?

    c->max_slots(m_prepared_account_select.value("max_slots").toUInt());
    c->game_server_id(m_prepared_account_select.value("id").toULongLong());

    ACE_DEBUG((LM_INFO,"CharacterClient id: %i\n",c->account_server_id()));
    ACE_DEBUG((LM_INFO,"CharacterClient slots: %i\n",c->max_slots()));
    return true;
}
#define STR_OR_EMPTY(c) ((!c.isEmpty()) ? c:"EMPTY")
#define STR_OR_VERY_EMPTY(c) ((c!=0) ? c:"")
bool CharacterDatabase::fill( Character *c)
{
    assert(c&&c->getAccountId());

    m_prepared_char_select.bindValue(0,quint64(c->getAccountId()));
    m_prepared_char_select.bindValue(1,(uint16_t)c->getIndex());
    if(!doIt(m_prepared_char_select))
        return false;

    if(!m_prepared_char_select.next())
    {
        c->reset(); // empty slot
        return true;
    }
//    else if (results.num_rows()>1)
//        ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT ("(%P|%t) CharacterDatabase::fill query returned wrong number of results. %s failed.\n"), query.str().c_str()),false);

    c->setLevel((uint8_t)m_prepared_char_select.value("char_level").toUInt());
    c->setName(STR_OR_EMPTY(m_prepared_char_select.value("char_name").toString()));
    c->m_class_name = (STR_OR_EMPTY(m_prepared_char_select.value("archetype").toString()));
    c->m_origin_name= (STR_OR_EMPTY(m_prepared_char_select.value("origin").toString()));

    CharacterCostume *main_costume = new CharacterCostume;
    // appearance related.
    main_costume->m_body_type = m_prepared_char_select.value("bodytype").toUInt(); // 0
    c->setMapName(STR_OR_EMPTY(m_prepared_char_select.value("current_map").toString()));
    c->setLastCostumeId(m_prepared_char_select.value("last_costume_id").toUInt());
    main_costume->setSlotIndex(0);
    main_costume->setCharacterId(m_prepared_char_select.value("id").toULongLong());
    c->m_costumes.push_back(main_costume);
    return fill(main_costume);
}
#ifndef ARRAYSIZE
#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[1]))
#define DEFINED_ARRAYSIZE
#endif
bool CharacterDatabase::fill( CharacterCostume *c)
{
    assert(c&&c->getCharacterId());

    m_prepared_fill.bindValue(0,quint64(c->getCharacterId()));
    m_prepared_fill.bindValue(1,(uint16_t)c->getSlotIndex());
    if(!doIt(m_prepared_fill))
        return false;

    if(!m_prepared_fill.next()) // retry with the first one
    {
        m_prepared_fill.bindValue(0,quint64(c->getCharacterId()));
        m_prepared_fill.bindValue(1,0); // get first costume

        if(!doIt(m_prepared_fill))
            return false;
        if(!m_prepared_fill.next()) {
            ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT ("(%P|%t) CharacterDatabase::fill no costumes.\n")),false);
            return false;
        }
    }
    c->skin_color = m_prepared_fill.value("skin_color").toUInt();
    QString serialized_parts= m_prepared_fill.value("parts").toString();
    c->serializeFromDb(serialized_parts);
    c->m_non_default_costme_p = false;
    return true;
}

bool CharacterDatabase::CreateLinkedAccount( uint64_t auth_account_id,const std::string &username,int max_account_slots )
{
    //assert(auth_account_id>0);  sqlite3 autogenerated values start from 0
    assert(username.size()>2);
    m_prepared_account_insert.bindValue(0,quint64(auth_account_id));
    m_prepared_account_insert.bindValue(1,max_account_slots);

    if(!doIt(m_prepared_account_insert))
        return false;
    return true;
}

int CharacterDatabase::remove_account( uint64_t /*acc_serv_id*/ )
{
    return 0;
}
//TODO: SQL String sanitization
bool CharacterDatabase::create( uint64_t gid,uint8_t slot,Character *c )
{
    assert(m_db->driver()->hasFeature(QSqlDriver::LastInsertId));
    assert(gid>0);
    assert(c);
    assert(slot<8);
    Costume *cst = c->getCurrentCostume();
    if(!cst) {
        ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("(%P|%t) CharacterDatabase::create cannot insert char without costume.\n"))
                         ,false);
    }
    m_prepared_char_insert.bindValue(0, c->m_level);
    m_prepared_char_insert.bindValue(1, uint32_t(slot));
    m_prepared_char_insert.bindValue(2, quint64(gid));
    m_prepared_char_insert.bindValue(3, c->m_name);
    m_prepared_char_insert.bindValue(4, c->m_class_name);
    m_prepared_char_insert.bindValue(5, c->m_origin_name);
    m_prepared_char_insert.bindValue(6, c->getCurrentCostume()->m_body_type);
    m_prepared_char_insert.bindValue(7, c->m_mapName);
    if(!doIt(m_prepared_char_insert))
        return false;
    int64_t char_id = m_prepared_char_insert.lastInsertId().toLongLong();

    // create costume

    QString costume_parts;
    cst->serializeToDb(costume_parts);
    m_prepared_costume_insert.bindValue(0,quint64(char_id));
    m_prepared_costume_insert.bindValue(1,uint32_t(0));
    m_prepared_costume_insert.bindValue(2,uint32_t(cst->skin_color));
    m_prepared_costume_insert.bindValue(3,costume_parts);

    if(!doIt(m_prepared_costume_insert))
        return false;
    return true;
}
#ifdef DEFINED_ARRAYSIZE
#undef DEFINED_ARRAYSIZE
#undef ARRAYSIZE
#endif
<commit_msg>Change max_account_slots to max_character_slots<commit_after>/*
 * Super Entity Game Server Project
 * http://segs.sf.net/
 * Copyright (c) 2006 - 2016 Super Entity Game Server Team (see Authors.txt)
 * This software is licensed! (See License.txt for details)
 *
 */

// segs includes

#include "CharacterDatabase.h"
#include "AccountInfo.h"
#include "AdminServer.h"
#include "Character.h"
#include "Costume.h"

#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlDriver>
#include <QtCore/QDebug>
#include <QtSql/QSqlError>
#include <cstdlib>
#include <cstdio>
using namespace std;

CharacterDatabase::~CharacterDatabase()
{
    if(m_db)
        m_db->close();
}
static bool prepQuery(QSqlQuery &qr,const QString &txt) {
    if(!qr.prepare(txt)) {
        qDebug() << "SQL_ERROR:"<<qr.lastError();
        return false;
    }
    return true;
}
static bool doIt(QSqlQuery &qr) {
    if(!qr.exec()) {
        qDebug() << "SQL_ERROR:"<<qr.lastError();
        return false;
    }
    return true;
}
void CharacterDatabase::on_connected(QSqlDatabase *db)
{
    m_db = db;
    if(!db)
        return;

    m_prepared_fill = QSqlQuery(*db);
    m_prepared_account_insert = QSqlQuery(*db);
    m_prepared_char_insert = QSqlQuery(*db);
    m_prepared_costume_insert = QSqlQuery(*db);
    m_prepared_char_select = QSqlQuery(*db);
    m_prepared_account_select = QSqlQuery(*db);
    m_prepared_char_exists = QSqlQuery(*db);
    m_prepared_char_delete = QSqlQuery(*db);

    prepQuery(m_prepared_fill,"SELECT * FROM costume WHERE character_id=? AND costume_index=?");
    prepQuery(m_prepared_account_insert,"INSERT INTO accounts  (account_id,max_slots) VALUES (?,?)");
    prepQuery(m_prepared_char_insert,
                "INSERT INTO characters  "
                "(char_level,slot_index,account_id,char_name,archetype,origin,bodytype,current_map) "
                "VALUES "
                "(?,?,?,?,?,?,?,?)");
    prepQuery(m_prepared_costume_insert,
                "INSERT INTO costume (character_id,costume_index,skin_color,parts) VALUES "
                "(?,?,?,?)");
    prepQuery(m_prepared_char_select,"SELECT * FROM characters WHERE account_id=? AND slot_index=?");
    prepQuery(m_prepared_account_select,"SELECT * FROM accounts WHERE account_id=?");
    prepQuery(m_prepared_char_exists,"SELECT exists (SELECT 1 FROM characters WHERE char_name = $1 LIMIT 1)");
    prepQuery(m_prepared_char_delete,"DELETE FROM characters WHERE account_id=? AND slot_index=?");
}

// UserToken,
bool CharacterDatabase::remove_character(AccountInfo *c,int8_t slot_idx)
{
    assert(c!=nullptr);
    m_prepared_char_delete.bindValue(0,quint64(c->account_server_id()));
    m_prepared_char_delete.bindValue(1,(uint32_t)slot_idx);
    if(!doIt(m_prepared_char_delete))
        return false;
    return true;
}
bool CharacterDatabase::named_character_exists(const QString &name)
{
    m_prepared_char_exists.bindValue(0,name);
    if(!doIt(m_prepared_char_exists))
        return false;

    if(!m_prepared_char_exists.next())
        return false;
    // TODO: handle case of multiple accounts with same name ?
    return m_prepared_char_exists.value(0).toBool();
}
bool CharacterDatabase::fill( AccountInfo *c )
{
    assert(c&&c->account_server_id());

    m_prepared_account_select.bindValue(0,quint64(c->account_server_id()));
    if(!doIt(m_prepared_account_select))
        return false;

    if(!m_prepared_account_select.next())
        return false;
    // TODO: handle case of multiple accounts with same name ?

    c->max_slots(m_prepared_account_select.value("max_slots").toUInt());
    c->game_server_id(m_prepared_account_select.value("id").toULongLong());

    ACE_DEBUG((LM_INFO,"CharacterClient id: %i\n",c->account_server_id()));
    ACE_DEBUG((LM_INFO,"CharacterClient slots: %i\n",c->max_slots()));
    return true;
}
#define STR_OR_EMPTY(c) ((!c.isEmpty()) ? c:"EMPTY")
#define STR_OR_VERY_EMPTY(c) ((c!=0) ? c:"")
bool CharacterDatabase::fill( Character *c)
{
    assert(c&&c->getAccountId());

    m_prepared_char_select.bindValue(0,quint64(c->getAccountId()));
    m_prepared_char_select.bindValue(1,(uint16_t)c->getIndex());
    if(!doIt(m_prepared_char_select))
        return false;

    if(!m_prepared_char_select.next())
    {
        c->reset(); // empty slot
        return true;
    }
//    else if (results.num_rows()>1)
//        ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT ("(%P|%t) CharacterDatabase::fill query returned wrong number of results. %s failed.\n"), query.str().c_str()),false);

    c->setLevel((uint8_t)m_prepared_char_select.value("char_level").toUInt());
    c->setName(STR_OR_EMPTY(m_prepared_char_select.value("char_name").toString()));
    c->m_class_name = (STR_OR_EMPTY(m_prepared_char_select.value("archetype").toString()));
    c->m_origin_name= (STR_OR_EMPTY(m_prepared_char_select.value("origin").toString()));

    CharacterCostume *main_costume = new CharacterCostume;
    // appearance related.
    main_costume->m_body_type = m_prepared_char_select.value("bodytype").toUInt(); // 0
    c->setMapName(STR_OR_EMPTY(m_prepared_char_select.value("current_map").toString()));
    c->setLastCostumeId(m_prepared_char_select.value("last_costume_id").toUInt());
    main_costume->setSlotIndex(0);
    main_costume->setCharacterId(m_prepared_char_select.value("id").toULongLong());
    c->m_costumes.push_back(main_costume);
    return fill(main_costume);
}
#ifndef ARRAYSIZE
#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[1]))
#define DEFINED_ARRAYSIZE
#endif
bool CharacterDatabase::fill( CharacterCostume *c)
{
    assert(c&&c->getCharacterId());

    m_prepared_fill.bindValue(0,quint64(c->getCharacterId()));
    m_prepared_fill.bindValue(1,(uint16_t)c->getSlotIndex());
    if(!doIt(m_prepared_fill))
        return false;

    if(!m_prepared_fill.next()) // retry with the first one
    {
        m_prepared_fill.bindValue(0,quint64(c->getCharacterId()));
        m_prepared_fill.bindValue(1,0); // get first costume

        if(!doIt(m_prepared_fill))
            return false;
        if(!m_prepared_fill.next()) {
            ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT ("(%P|%t) CharacterDatabase::fill no costumes.\n")),false);
            return false;
        }
    }
    c->skin_color = m_prepared_fill.value("skin_color").toUInt();
    QString serialized_parts= m_prepared_fill.value("parts").toString();
    c->serializeFromDb(serialized_parts);
    c->m_non_default_costme_p = false;
    return true;
}

bool CharacterDatabase::CreateLinkedAccount( uint64_t auth_account_id,const std::string &username,int max_character_slots )
{
    //assert(auth_account_id>0);  sqlite3 autogenerated values start from 0
    assert(username.size()>2);
    m_prepared_account_insert.bindValue(0,quint64(auth_account_id));
    m_prepared_account_insert.bindValue(1,max_character_slots);

    if(!doIt(m_prepared_account_insert))
        return false;
    return true;
}

int CharacterDatabase::remove_account( uint64_t /*acc_serv_id*/ )
{
    return 0;
}
//TODO: SQL String sanitization
bool CharacterDatabase::create( uint64_t gid,uint8_t slot,Character *c )
{
    assert(m_db->driver()->hasFeature(QSqlDriver::LastInsertId));
    assert(gid>0);
    assert(c);
    assert(slot<8);
    Costume *cst = c->getCurrentCostume();
    if(!cst) {
        ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("(%P|%t) CharacterDatabase::create cannot insert char without costume.\n"))
                         ,false);
    }
    m_prepared_char_insert.bindValue(0, c->m_level);
    m_prepared_char_insert.bindValue(1, uint32_t(slot));
    m_prepared_char_insert.bindValue(2, quint64(gid));
    m_prepared_char_insert.bindValue(3, c->m_name);
    m_prepared_char_insert.bindValue(4, c->m_class_name);
    m_prepared_char_insert.bindValue(5, c->m_origin_name);
    m_prepared_char_insert.bindValue(6, c->getCurrentCostume()->m_body_type);
    m_prepared_char_insert.bindValue(7, c->m_mapName);
    if(!doIt(m_prepared_char_insert))
        return false;
    int64_t char_id = m_prepared_char_insert.lastInsertId().toLongLong();

    // create costume

    QString costume_parts;
    cst->serializeToDb(costume_parts);
    m_prepared_costume_insert.bindValue(0,quint64(char_id));
    m_prepared_costume_insert.bindValue(1,uint32_t(0));
    m_prepared_costume_insert.bindValue(2,uint32_t(cst->skin_color));
    m_prepared_costume_insert.bindValue(3,costume_parts);

    if(!doIt(m_prepared_costume_insert))
        return false;
    return true;
}
#ifdef DEFINED_ARRAYSIZE
#undef DEFINED_ARRAYSIZE
#undef ARRAYSIZE
#endif
<|endoftext|>