<commit_before>#include <QtGui>
#include <QApplication>
#include <QDesktopServices>
#include <QFile>
#include <QTextStream>
#include <QDir>
#include <QCoreApplication>
#include <QMessageBox>
#include <QTimer>

#include <glib.h>

#include "utils/utils.h"
#include "utils/log.h"
#include "account-mgr.h"
#include "configurator.h"
#include "daemon-mgr.h"
#include "message-listener.h"
#include "settings-mgr.h"
#include "certs-mgr.h"
#include "rpc/rpc-client.h"
#include "ui/main-window.h"
#include "ui/tray-icon.h"
#include "ui/settings-dialog.h"
#include "ui/init-vdrive-dialog.h"
#include "ui/login-dialog.h"
#include "open-local-helper.h"
#include "avatar-service.h"
#include "seahub-notifications-monitor.h"
#include "filebrowser/data-cache.h"
#include "rpc/local-repo.h"
#include "server-status-service.h"

#include "seafile-applet.h"

namespace {

void myLogHandler(QtMsgType type, const char *msg)
{
    switch (type) {
    case QtDebugMsg:
        g_debug("%s", msg);
        break;
    case QtWarningMsg:
        g_warning("%s", msg);
        break;
    case QtCriticalMsg:
        g_critical("%s", msg);
        break;
    case QtFatalMsg:
        g_critical("%s", msg);
        abort();
    }
}

/**
 * s1 > s2 --> *ret = 1
 *    = s2 --> *ret = 0
 *    < s2 --> *ret = -1
 *
 * If any of the vesion strings is invalid, return -1; else return 0
 */
int compareVersions(const QString& s1, const QString& s2, int *ret)
{
    QStringList v1 = s1.split(".");
    QStringList v2 = s2.split(".");

    int i = 0;
    while (i < v1.size() && i < v2.size()) {
        bool ok;
        int a = v1[i].toInt(&ok);
        if (!ok) {
            return -1;
        }
        int b = v2[i].toInt(&ok);
        if (!ok) {
            return -1;
        }

        if (a > b) {
            *ret = 1;
            return 0;
        } else if (a < b) {
            *ret = -1;
            return 0;
        }

        i++;
    }

    *ret = v1.size() - v2.size();

    return 0;
}

const int kIntervalBeforeShowInitVirtualDialog = 3000;
const int kIntervalForUpdateRepoProperty = 1000;

const char *kSeafileClientDownloadUrl = "http://seafile.com/en/download/";
const char *kSeafileClientDownloadUrlChinese = "http://seafile.com/download/";

const char *kRepoServerUrlProperty = "server-url";
const char *kRepoRelayAddrProperty = "relay-address";

} // namespace

SeafileApplet *seafApplet;

SeafileApplet::SeafileApplet()
    : configurator_(new Configurator),
      account_mgr_(new AccountManager),
      daemon_mgr_(new DaemonManager),
      main_win_(NULL),
      rpc_client_(new SeafileRpcClient),
      message_listener_(new MessageListener),
      settings_dialog_(new SettingsDialog),
      settings_mgr_(new SettingsManager),
      certs_mgr_(new CertsManager),
      started_(false),
      in_exit_(false),
      is_pro_(false)
{
    tray_icon_ = new SeafileTrayIcon(this);
}

void SeafileApplet::start()
{
    refreshQss();

    configurator_->checkInit();

    initLog();

    account_mgr_->start();

    certs_mgr_->start();

    FileCacheDB::instance()->start();

    AvatarService::instance()->start();
    SeahubNotificationsMonitor::instance()->start();
    ServerStatusService::instance()->start();

#if defined(Q_WS_WIN)
    QString crash_rpt_path = QDir(configurator_->ccnetDir()).filePath("logs/seafile-crash-report.txt");
    if (!g_setenv ("CRASH_RPT_PATH", toCStr(crash_rpt_path), FALSE))
        qDebug("Failed to set CRASH_RPT_PATH env variable.\n");
#endif

    daemon_mgr_->startCcnetDaemon();

    connect(daemon_mgr_, SIGNAL(daemonStarted()),
            this, SLOT(onDaemonStarted()));
}

void SeafileApplet::onDaemonStarted()
{
    main_win_ = new MainWindow;

    rpc_client_->connectDaemon();
    message_listener_->connectDaemon();
    seafApplet->settingsManager()->loadSettings();

#if defined(Q_WS_MAC)
    seafApplet->settingsManager()->setHideDockIcon(seafApplet->settingsManager()->hideDockIcon());
#endif

    if (configurator_->firstUse() || account_mgr_->accounts().size() == 0) {
        LoginDialog login_dialog;
        login_dialog.exec();
    }

    started_ = true;

    if (configurator_->firstUse() || !settings_mgr_->hideMainWindowWhenStarted()) {
        main_win_->showWindow();
    }

    tray_icon_->start();
    tray_icon_->setState(SeafileTrayIcon::STATE_DAEMON_UP);

#if defined(Q_WS_WIN)
    QTimer::singleShot(kIntervalBeforeShowInitVirtualDialog, this, SLOT(checkInitVDrive()));
    configurator_->installCustomUrlHandler();
#endif

    if (settings_mgr_->isCheckLatestVersionEnabled()) {
        checkLatestVersionInfo();
    }

    OpenLocalHelper::instance()->checkPendingOpenLocalRequest();

    QTimer::singleShot(kIntervalForUpdateRepoProperty,
                       this, SLOT(updateReposPropertyForHttpSync()));
}

void SeafileApplet::checkInitVDrive()
{
    if (configurator_->firstUse() && account_mgr_->accounts().size() > 0) {
        const Account& account = account_mgr_->accounts()[0];
        InitVirtualDriveDialog *dialog = new InitVirtualDriveDialog(account);
        // Move the dialog to the left of the main window
        int x = main_win_->pos().x() - dialog->rect().width() - 30;
        int y = (QApplication::desktop()->screenGeometry().center() - dialog->rect().center()).y();
        dialog->move(qMax(0, x), y);
        dialog->show();
        dialog->raise();
        dialog->activateWindow();
    }
}

// cleanup before exit
void SeafileApplet::exit(int code)
{
    daemon_mgr_->stopAll();
    // Remove tray icon from system tray
    delete tray_icon_;
    if (main_win_) {
        main_win_->writeSettings();
    }
}

// stop the main event loop and return to the main function
void SeafileApplet::errorAndExit(const QString& error)
{
    if (in_exit_) {
        return;
    }

    in_exit_ = true;

    warningBox(error);
    // stop eventloop before exit and return to the main function
    QCoreApplication::exit(1);
}

void SeafileApplet::initLog()
{
    if (applet_log_init(toCStr(configurator_->ccnetDir())) < 0) {
        errorAndExit(tr("Failed to initialize log"));
    } else {
        qInstallMsgHandler(myLogHandler);
    }
}

bool SeafileApplet::loadQss(const QString& path)
{
    QFile file(path);
    if (!QFileInfo(file).exists()) {
        return false;
    }
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        return false;
    }

    QTextStream input(&file);
    style_ += "\n";
    style_ += input.readAll();
    qApp->setStyleSheet(style_);

    return true;
}

void SeafileApplet::refreshQss()
{
    style_.clear();
    loadQss("qt.css") || loadQss(":/qt.css");

#if defined(Q_WS_WIN)
    loadQss("qt-win.css") || loadQss(":/qt-win.css");
#elif defined(Q_WS_X11)
    loadQss("qt-linux.css") || loadQss(":/qt-linux.css");
#else
    loadQss("qt-mac.css") || loadQss(":/qt-mac.css");
#endif
}

void SeafileApplet::warningBox(const QString& msg, QWidget *parent)
{
    QMessageBox::warning(parent != 0 ? parent : main_win_,
                         getBrand(), msg, QMessageBox::Ok);
}

void SeafileApplet::messageBox(const QString& msg, QWidget *parent)
{
    QMessageBox::information(parent != 0 ? parent : main_win_,
                             getBrand(), msg, QMessageBox::Ok);
}

bool SeafileApplet::yesOrNoBox(const QString& msg, QWidget *parent, bool default_val)
{
    QMessageBox::StandardButton default_btn = default_val ? QMessageBox::Yes : QMessageBox::No;

    return QMessageBox::question(parent != 0 ? parent : main_win_,
                                 getBrand(),
                                 msg,
                                 QMessageBox::Yes | QMessageBox::No,
                                 default_btn) == QMessageBox::Yes;
}

bool SeafileApplet::detailedYesOrNoBox(const QString& msg, const QString& detailed_text, QWidget *parent, bool default_val)
{
    QMessageBox *msgBox = new QMessageBox(QMessageBox::Question,
                       getBrand(),
                       msg,
                       QMessageBox::Yes | QMessageBox::No,
                       parent != 0 ? parent : main_win_);
    msgBox->setDetailedText(detailed_text);
    // Turns out the layout box in the QMessageBox is a grid
    // You can force the resize using a spacer this way:
    QSpacerItem* horizontalSpacer = new QSpacerItem(400, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
    QGridLayout* layout = (QGridLayout*)msgBox->layout();
layout->addItem(horizontalSpacer, layout->rowCount(), 0, 1, layout->columnCount());
    msgBox->setDefaultButton(default_val ? QMessageBox::Yes : QMessageBox::No);
    return msgBox->exec() == QMessageBox::Yes;
}

void SeafileApplet::checkLatestVersionInfo()
{
    QString id = rpc_client_->getCcnetPeerId();
    QString version = STRINGIZE(SEAFILE_CLIENT_VERSION);

    GetLatestVersionRequest *req = new GetLatestVersionRequest(id, version);
    req->send();

    connect(req, SIGNAL(success(const QString&)),
            this, SLOT(onGetLatestVersionInfoSuccess(const QString&)));
}

void SeafileApplet::onGetLatestVersionInfoSuccess(const QString& latest_version)
{
    QString current_version = STRINGIZE(SEAFILE_CLIENT_VERSION);

    int ret;
    if (compareVersions(current_version, latest_version, &ret) < 0) {
        return;
    }

    if (ret >= 0) {
        return;
    }

    QString msg = tr("A new version of %1 client (%2) is available.\n"
                     "Do you want to visit the download page?").arg(getBrand()).arg(latest_version);

    if (!yesOrNoBox(msg, NULL, true)) {
        return;
    }

    QString url;
    if (QLocale::system().name() == "zh_CN") {
        url = kSeafileClientDownloadUrlChinese;
    } else {
        url = kSeafileClientDownloadUrl;
    }

    QDesktopServices::openUrl(url);
}

/**
 * For each repo, add the "server-url" property (inferred from account url),
 * which would be used for http sync.
 */
void SeafileApplet::updateReposPropertyForHttpSync()
{
    std::vector<LocalRepo> repos;
    if (rpc_client_->listLocalRepos(&repos) < 0) {
        QTimer::singleShot(kIntervalForUpdateRepoProperty,
                           this, SLOT(updateReposPropertyForHttpSync()));
        return;
    }

    const std::vector<Account>& accounts = account_mgr_->accounts();
    for (int i = 0; i < repos.size(); i++) {
        const LocalRepo& repo = repos[i];
        QString repo_server_url;
        QString relay_addr;
        if (rpc_client_->getRepoProperty(repo.id, kRepoServerUrlProperty, &repo_server_url) < 0) {
            continue;
        }
        if (!repo_server_url.isEmpty()) {
            continue;
        }
        if (rpc_client_->getRepoProperty(repo.id, kRepoRelayAddrProperty, &relay_addr) < 0) {
            continue;
        }
        for (int i = 0; i < accounts.size(); i++) {
            const Account& account = accounts[i];
            if (account.serverUrl.host() == relay_addr) {
                QUrl url(account.serverUrl);
                url.setPath("/");
                rpc_client_->setRepoProperty(repo.id, kRepoServerUrlProperty, url.toString());
                break;
            }
        }
    }
}
<commit_msg>don't print qDebug information when it is a release build<commit_after>#include <QtGui>
#include <QApplication>
#include <QDesktopServices>
#include <QFile>
#include <QTextStream>
#include <QDir>
#include <QCoreApplication>
#include <QMessageBox>
#include <QTimer>

#include <glib.h>

#include "utils/utils.h"
#include "utils/log.h"
#include "account-mgr.h"
#include "configurator.h"
#include "daemon-mgr.h"
#include "message-listener.h"
#include "settings-mgr.h"
#include "certs-mgr.h"
#include "rpc/rpc-client.h"
#include "ui/main-window.h"
#include "ui/tray-icon.h"
#include "ui/settings-dialog.h"
#include "ui/init-vdrive-dialog.h"
#include "ui/login-dialog.h"
#include "open-local-helper.h"
#include "avatar-service.h"
#include "seahub-notifications-monitor.h"
#include "filebrowser/data-cache.h"
#include "rpc/local-repo.h"
#include "server-status-service.h"

#include "seafile-applet.h"

namespace {
enum DEBUG_LEVEL {
  DEBUG = 0,
  WARNING
};

// -DQT_NO_DEBUG is used with cmake and qmake if it is a release build
// if it is debug build, use DEBUG level as default
#if !defined(QT_NO_DEBUG) || !defined(NDEBUG)
DEBUG_LEVEL seafile_client_debug_level = DEBUG;
#else
// if it is release build, use WARNING level as default
DEBUG_LEVEL seafile_client_debug_level = WARNING;
#endif

void myLogHandlerDebug(QtMsgType type, const char *msg)
{
    switch (type) {
    case QtDebugMsg:
        g_debug("%s", msg);
        break;
    case QtWarningMsg:
        g_warning("%s", msg);
        break;
    case QtCriticalMsg:
        g_critical("%s", msg);
        break;
    case QtFatalMsg:
        g_critical("%s", msg);
        abort();
    }
}

void myLogHandler(QtMsgType type, const char *msg)
{
    switch (type) {
    case QtWarningMsg:
        g_warning("%s", msg);
        break;
    case QtCriticalMsg:
        g_critical("%s", msg);
        break;
    case QtFatalMsg:
        g_critical("%s", msg);
        abort();
    default:
        break;
    }
}

/**
 * s1 > s2 --> *ret = 1
 *    = s2 --> *ret = 0
 *    < s2 --> *ret = -1
 *
 * If any of the vesion strings is invalid, return -1; else return 0
 */
int compareVersions(const QString& s1, const QString& s2, int *ret)
{
    QStringList v1 = s1.split(".");
    QStringList v2 = s2.split(".");

    int i = 0;
    while (i < v1.size() && i < v2.size()) {
        bool ok;
        int a = v1[i].toInt(&ok);
        if (!ok) {
            return -1;
        }
        int b = v2[i].toInt(&ok);
        if (!ok) {
            return -1;
        }

        if (a > b) {
            *ret = 1;
            return 0;
        } else if (a < b) {
            *ret = -1;
            return 0;
        }

        i++;
    }

    *ret = v1.size() - v2.size();

    return 0;
}

const int kIntervalBeforeShowInitVirtualDialog = 3000;
const int kIntervalForUpdateRepoProperty = 1000;

const char *kSeafileClientDownloadUrl = "http://seafile.com/en/download/";
const char *kSeafileClientDownloadUrlChinese = "http://seafile.com/download/";

const char *kRepoServerUrlProperty = "server-url";
const char *kRepoRelayAddrProperty = "relay-address";

} // namespace

SeafileApplet *seafApplet;

SeafileApplet::SeafileApplet()
    : configurator_(new Configurator),
      account_mgr_(new AccountManager),
      daemon_mgr_(new DaemonManager),
      main_win_(NULL),
      rpc_client_(new SeafileRpcClient),
      message_listener_(new MessageListener),
      settings_dialog_(new SettingsDialog),
      settings_mgr_(new SettingsManager),
      certs_mgr_(new CertsManager),
      started_(false),
      in_exit_(false),
      is_pro_(false)
{
    tray_icon_ = new SeafileTrayIcon(this);
}

void SeafileApplet::start()
{
    refreshQss();

    configurator_->checkInit();

    initLog();

    account_mgr_->start();

    certs_mgr_->start();

    FileCacheDB::instance()->start();

    AvatarService::instance()->start();
    SeahubNotificationsMonitor::instance()->start();
    ServerStatusService::instance()->start();

#if defined(Q_WS_WIN)
    QString crash_rpt_path = QDir(configurator_->ccnetDir()).filePath("logs/seafile-crash-report.txt");
    if (!g_setenv ("CRASH_RPT_PATH", toCStr(crash_rpt_path), FALSE))
        qDebug("Failed to set CRASH_RPT_PATH env variable.\n");
#endif

    daemon_mgr_->startCcnetDaemon();

    connect(daemon_mgr_, SIGNAL(daemonStarted()),
            this, SLOT(onDaemonStarted()));
}

void SeafileApplet::onDaemonStarted()
{
    main_win_ = new MainWindow;

    rpc_client_->connectDaemon();
    message_listener_->connectDaemon();
    seafApplet->settingsManager()->loadSettings();

#if defined(Q_WS_MAC)
    seafApplet->settingsManager()->setHideDockIcon(seafApplet->settingsManager()->hideDockIcon());
#endif

    if (configurator_->firstUse() || account_mgr_->accounts().size() == 0) {
        LoginDialog login_dialog;
        login_dialog.exec();
    }

    started_ = true;

    if (configurator_->firstUse() || !settings_mgr_->hideMainWindowWhenStarted()) {
        main_win_->showWindow();
    }

    tray_icon_->start();
    tray_icon_->setState(SeafileTrayIcon::STATE_DAEMON_UP);

#if defined(Q_WS_WIN)
    QTimer::singleShot(kIntervalBeforeShowInitVirtualDialog, this, SLOT(checkInitVDrive()));
    configurator_->installCustomUrlHandler();
#endif

    if (settings_mgr_->isCheckLatestVersionEnabled()) {
        checkLatestVersionInfo();
    }

    OpenLocalHelper::instance()->checkPendingOpenLocalRequest();

    QTimer::singleShot(kIntervalForUpdateRepoProperty,
                       this, SLOT(updateReposPropertyForHttpSync()));
}

void SeafileApplet::checkInitVDrive()
{
    if (configurator_->firstUse() && account_mgr_->accounts().size() > 0) {
        const Account& account = account_mgr_->accounts()[0];
        InitVirtualDriveDialog *dialog = new InitVirtualDriveDialog(account);
        // Move the dialog to the left of the main window
        int x = main_win_->pos().x() - dialog->rect().width() - 30;
        int y = (QApplication::desktop()->screenGeometry().center() - dialog->rect().center()).y();
        dialog->move(qMax(0, x), y);
        dialog->show();
        dialog->raise();
        dialog->activateWindow();
    }
}

// cleanup before exit
void SeafileApplet::exit(int code)
{
    daemon_mgr_->stopAll();
    // Remove tray icon from system tray
    delete tray_icon_;
    if (main_win_) {
        main_win_->writeSettings();
    }
}

// stop the main event loop and return to the main function
void SeafileApplet::errorAndExit(const QString& error)
{
    if (in_exit_) {
        return;
    }

    in_exit_ = true;

    warningBox(error);
    // stop eventloop before exit and return to the main function
    QCoreApplication::exit(1);
}

void SeafileApplet::initLog()
{
    if (applet_log_init(toCStr(configurator_->ccnetDir())) < 0) {
        errorAndExit(tr("Failed to initialize log"));
    } else {
        // give a change to override DEBUG_LEVEL by environment
        QString debug_level = qgetenv("SEAFILE_CLIENT_DEBUG");
        if (!debug_level.isEmpty() && debug_level != "false" &&
            debug_level != "0")
            seafile_client_debug_level = DEBUG;

        // set up log handler respectively
        if (seafile_client_debug_level == DEBUG)
            qInstallMsgHandler(myLogHandlerDebug);
        else
            qInstallMsgHandler(myLogHandler);
    }
}

bool SeafileApplet::loadQss(const QString& path)
{
    QFile file(path);
    if (!QFileInfo(file).exists()) {
        return false;
    }
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        return false;
    }

    QTextStream input(&file);
    style_ += "\n";
    style_ += input.readAll();
    qApp->setStyleSheet(style_);

    return true;
}

void SeafileApplet::refreshQss()
{
    style_.clear();
    loadQss("qt.css") || loadQss(":/qt.css");

#if defined(Q_WS_WIN)
    loadQss("qt-win.css") || loadQss(":/qt-win.css");
#elif defined(Q_WS_X11)
    loadQss("qt-linux.css") || loadQss(":/qt-linux.css");
#else
    loadQss("qt-mac.css") || loadQss(":/qt-mac.css");
#endif
}

void SeafileApplet::warningBox(const QString& msg, QWidget *parent)
{
    QMessageBox::warning(parent != 0 ? parent : main_win_,
                         getBrand(), msg, QMessageBox::Ok);
}

void SeafileApplet::messageBox(const QString& msg, QWidget *parent)
{
    QMessageBox::information(parent != 0 ? parent : main_win_,
                             getBrand(), msg, QMessageBox::Ok);
}

bool SeafileApplet::yesOrNoBox(const QString& msg, QWidget *parent, bool default_val)
{
    QMessageBox::StandardButton default_btn = default_val ? QMessageBox::Yes : QMessageBox::No;

    return QMessageBox::question(parent != 0 ? parent : main_win_,
                                 getBrand(),
                                 msg,
                                 QMessageBox::Yes | QMessageBox::No,
                                 default_btn) == QMessageBox::Yes;
}

bool SeafileApplet::detailedYesOrNoBox(const QString& msg, const QString& detailed_text, QWidget *parent, bool default_val)
{
    QMessageBox *msgBox = new QMessageBox(QMessageBox::Question,
                       getBrand(),
                       msg,
                       QMessageBox::Yes | QMessageBox::No,
                       parent != 0 ? parent : main_win_);
    msgBox->setDetailedText(detailed_text);
    // Turns out the layout box in the QMessageBox is a grid
    // You can force the resize using a spacer this way:
    QSpacerItem* horizontalSpacer = new QSpacerItem(400, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
    QGridLayout* layout = (QGridLayout*)msgBox->layout();
layout->addItem(horizontalSpacer, layout->rowCount(), 0, 1, layout->columnCount());
    msgBox->setDefaultButton(default_val ? QMessageBox::Yes : QMessageBox::No);
    return msgBox->exec() == QMessageBox::Yes;
}

void SeafileApplet::checkLatestVersionInfo()
{
    QString id = rpc_client_->getCcnetPeerId();
    QString version = STRINGIZE(SEAFILE_CLIENT_VERSION);

    GetLatestVersionRequest *req = new GetLatestVersionRequest(id, version);
    req->send();

    connect(req, SIGNAL(success(const QString&)),
            this, SLOT(onGetLatestVersionInfoSuccess(const QString&)));
}

void SeafileApplet::onGetLatestVersionInfoSuccess(const QString& latest_version)
{
    QString current_version = STRINGIZE(SEAFILE_CLIENT_VERSION);

    int ret;
    if (compareVersions(current_version, latest_version, &ret) < 0) {
        return;
    }

    if (ret >= 0) {
        return;
    }

    QString msg = tr("A new version of %1 client (%2) is available.\n"
                     "Do you want to visit the download page?").arg(getBrand()).arg(latest_version);

    if (!yesOrNoBox(msg, NULL, true)) {
        return;
    }

    QString url;
    if (QLocale::system().name() == "zh_CN") {
        url = kSeafileClientDownloadUrlChinese;
    } else {
        url = kSeafileClientDownloadUrl;
    }

    QDesktopServices::openUrl(url);
}

/**
 * For each repo, add the "server-url" property (inferred from account url),
 * which would be used for http sync.
 */
void SeafileApplet::updateReposPropertyForHttpSync()
{
    std::vector<LocalRepo> repos;
    if (rpc_client_->listLocalRepos(&repos) < 0) {
        QTimer::singleShot(kIntervalForUpdateRepoProperty,
                           this, SLOT(updateReposPropertyForHttpSync()));
        return;
    }

    const std::vector<Account>& accounts = account_mgr_->accounts();
    for (int i = 0; i < repos.size(); i++) {
        const LocalRepo& repo = repos[i];
        QString repo_server_url;
        QString relay_addr;
        if (rpc_client_->getRepoProperty(repo.id, kRepoServerUrlProperty, &repo_server_url) < 0) {
            continue;
        }
        if (!repo_server_url.isEmpty()) {
            continue;
        }
        if (rpc_client_->getRepoProperty(repo.id, kRepoRelayAddrProperty, &relay_addr) < 0) {
            continue;
        }
        for (int i = 0; i < accounts.size(); i++) {
            const Account& account = accounts[i];
            if (account.serverUrl.host() == relay_addr) {
                QUrl url(account.serverUrl);
                url.setPath("/");
                rpc_client_->setRepoProperty(repo.id, kRepoServerUrlProperty, url.toString());
                break;
            }
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2011, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *

 * Author: Julius Kammerl (julius@kammerl.de)
 */

#include <pcl/compression/libpng_wrapper.h>

#include <png.h>
#include <zlib.h>

#include <vector>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <assert.h>

// user defined I/O callback methods for libPNG
namespace
{
  /////////////////////////////////////////////////////////////////////////////////////////
  void
  user_read_data (png_structp png_ptr, png_bytep data, png_size_t length)
  {
    uint8_t** input_pointer = reinterpret_cast<uint8_t**>(png_get_io_ptr (png_ptr));

    memcpy (data, *input_pointer, sizeof (uint8_t) * length);
    (*input_pointer) += length;
  }

  /////////////////////////////////////////////////////////////////////////////////////////
  void
  user_write_data (png_structp png_ptr,  png_bytep data, png_size_t length)
  {
    std::vector<uint8_t>* pngVec = reinterpret_cast<std::vector<uint8_t>*>(png_get_io_ptr (png_ptr));
    std::copy (data, data + length, std::back_inserter (*pngVec));
  }

  /////////////////////////////////////////////////////////////////////////////////////////
  void
  user_flush_data (png_structp)
  {
  }
}

namespace pcl
{
  namespace io
  {
    ///////////////////////////////////////////////////////////////////////////////////////////
    template<typename T> void
    encodeImageToPNG (typename std::vector<T>& image_arg,
                      size_t width_arg,
                      size_t height_arg,
                      int image_format_arg,
                      typename std::vector<uint8_t>& pngData_arg,
                      int png_level_arg)
    {
      png_structp png_ptr;
      png_infop info_ptr;
      volatile int channels;

      if (image_arg.size () ==0)
        return;

      // Get amount of channels
      switch (image_format_arg)
       {
         case PNG_COLOR_TYPE_GRAY:
           channels = 1;
           break;
         case PNG_COLOR_TYPE_GRAY_ALPHA:
           channels = 2;
           break;
         case PNG_COLOR_TYPE_RGB:
           channels = 3;
           break;
         case PNG_COLOR_TYPE_RGB_ALPHA:
           channels = 4;
           break;
         default:
           channels = 0;
           break;
       }

      // Ensure valid input array
      assert (image_arg.size () == width_arg*height_arg*channels);

      // Initialize write structure
      png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0);
      assert(png_ptr && "creating png_create_write_structpng_create_write_struct failed");

      // Initialize info structure
      info_ptr = png_create_info_struct (png_ptr);
      assert(info_ptr && "Could not allocate info struct");

      // Setup Exception handling
      if (setjmp(png_jmpbuf(png_ptr)))
      {
        assert("Error during png compression");
      }

      // reserve memory for output data (300kB)
      pngData_arg.clear ();
      pngData_arg.reserve (300 * 1024);

      // Define I/O methods
      png_set_write_fn (png_ptr, reinterpret_cast<void*> (&pngData_arg),
                        user_write_data, user_flush_data);

      // Define zlib compression level
      if (png_level_arg >= 0)
      {
        png_set_compression_level (png_ptr, png_level_arg);
      }
      else
      {
        png_set_compression_level (png_ptr, Z_DEFAULT_COMPRESSION);
      }

      // Write header
      png_set_IHDR (png_ptr, info_ptr, width_arg, height_arg, sizeof(T) * 8,
          image_format_arg, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
          PNG_FILTER_TYPE_DEFAULT);

      png_write_info (png_ptr, info_ptr);

      // Write image data
      size_t y;
      for (y = 0; y < height_arg; y++)
      {
        png_write_row (png_ptr, reinterpret_cast<png_bytep> (&image_arg[y * width_arg * channels]));
      }

      // End write
      png_write_end (png_ptr, 0);

      if (info_ptr)
        png_free_data (png_ptr, info_ptr, PNG_FREE_ALL, -1);
      if (png_ptr)
        png_destroy_write_struct (&png_ptr, 0);
    }

    ///////////////////////////////////////////////////////////////////////////////////////////
    template<typename T> void
    decodePNGImage (typename std::vector<uint8_t>& pngData_arg,
                    typename std::vector<T>& imageData_arg,
                    size_t& width_arg,
                    size_t& height_arg,
                    unsigned int& channels_arg)
    {
      int y;
      png_structp png_ptr;
      png_infop info_ptr;
      png_uint_32 png_width;
      png_uint_32 png_height;
      int png_bit_depth, png_color_type, png_interlace_type;

      png_bytep * row_pointers;

      if (pngData_arg.size () == 0)
        return;

      png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0);
      assert (png_ptr && "creating png_create_write_structpng_create_write_struct failed");

      // Initialize info structure
      info_ptr = png_create_info_struct (png_ptr);
      assert(info_ptr && "Could not allocate info struct");

      // Setup Exception handling
      if (setjmp(png_jmpbuf(png_ptr)))
      {
        assert("Error during png compression");
      }

      uint8_t* input_pointer = &pngData_arg[0];
      png_set_read_fn (png_ptr, reinterpret_cast<void*> (&input_pointer), user_read_data);

      png_read_info (png_ptr, info_ptr);

      png_get_IHDR (png_ptr, info_ptr, &png_width, &png_height, &png_bit_depth,
          &png_color_type, &png_interlace_type, NULL, NULL);

      // ensure a color bit depth of 8
      assert(png_bit_depth==sizeof(T)*8);

      unsigned int png_channels;
      switch (png_color_type)
      {
        case PNG_COLOR_TYPE_GRAY:
          png_channels = 1;
          break;
        case PNG_COLOR_TYPE_GRAY_ALPHA:
          png_channels = 2;
          break;
        case PNG_COLOR_TYPE_RGB:
          png_channels = 3;
          break;
        case PNG_COLOR_TYPE_RGB_ALPHA:
          png_channels = 4;
          break;
        default:
          png_channels = 0;
          break;
      }

      width_arg = png_width;
      height_arg = png_height;
      channels_arg = png_channels;

      imageData_arg.clear ();
      imageData_arg.resize (png_height * png_width * png_channels);

      row_pointers = reinterpret_cast<png_bytep*> (malloc (sizeof(png_bytep) * png_height));

      for (y = 0; y < png_height; y++)
        row_pointers[y] = reinterpret_cast<png_byte*> (&imageData_arg[y * png_width * png_channels]);

      png_read_image (png_ptr, row_pointers);

      if (info_ptr)
        png_free_data (png_ptr, info_ptr, PNG_FREE_ALL, -1);
      if (png_ptr)
        png_destroy_read_struct (&png_ptr, 0, 0);
      if (row_pointers)
        free (row_pointers);
    }
  } // namespace io
} // namespace pcl

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::io::encodeMonoImageToPNG (std::vector<uint8_t>& image_arg,
                               size_t width_arg,
                               size_t height_arg,
                               std::vector<uint8_t>& pngData_arg,
                              int png_level_arg)
{
  encodeImageToPNG<uint8_t>(image_arg, width_arg, height_arg, PNG_COLOR_TYPE_GRAY, pngData_arg, png_level_arg);
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::io::encodeMonoImageToPNG (std::vector<uint16_t>& image_arg,
                               size_t width_arg,
                               size_t height_arg,
                               std::vector<uint8_t>& pngData_arg,
                               int png_level_arg)
{
  encodeImageToPNG<uint16_t>(image_arg, width_arg, height_arg, PNG_COLOR_TYPE_GRAY, pngData_arg, png_level_arg);
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::io::encodeRGBImageToPNG (std::vector<uint8_t>& image_arg,
                              size_t width_arg,
                              size_t height_arg,
                              std::vector<uint8_t>& pngData_arg,
                              int png_level_arg)
{
  encodeImageToPNG<uint8_t>(image_arg, width_arg, height_arg, PNG_COLOR_TYPE_RGB, pngData_arg, png_level_arg);
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::io::encodeRGBImageToPNG (std::vector<uint16_t>& image_arg,
                              size_t width_arg,
                              size_t height_arg,
                              std::vector<uint8_t>& pngData_arg,
                              int png_level_arg)
{
  encodeImageToPNG<uint16_t>(image_arg, width_arg, height_arg, PNG_COLOR_TYPE_RGB, pngData_arg, png_level_arg);
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::io::decodePNGToImage (std::vector<uint8_t>& pngData_arg,
                           std::vector<uint8_t>& imageData_arg,
                           size_t& width_arg,
                           size_t& height_arg,
                           unsigned int& channels_arg)
{
  decodePNGImage<uint8_t> (pngData_arg, imageData_arg, width_arg, height_arg, channels_arg);
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::io::decodePNGToImage (std::vector<uint8_t>& pngData_arg,
                           std::vector<uint16_t>& imageData_arg,
                           size_t& width_arg,
                           size_t& height_arg,
                           unsigned int& channels_arg)
{
  decodePNGImage<uint16_t> (pngData_arg, imageData_arg, width_arg, height_arg, channels_arg);
}

<commit_msg>fixed #792<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2011, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *

 * Author: Julius Kammerl (julius@kammerl.de)
 */

#include <pcl/compression/libpng_wrapper.h>

#include <png.h>
#include <zlib.h>

#include <vector>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <assert.h>

// user defined I/O callback methods for libPNG
namespace
{
  /////////////////////////////////////////////////////////////////////////////////////////
  void
  user_read_data (png_structp png_ptr, png_bytep data, png_size_t length)
  {
    uint8_t** input_pointer = reinterpret_cast<uint8_t**>(png_get_io_ptr (png_ptr));

    memcpy (data, *input_pointer, sizeof (uint8_t) * length);
    (*input_pointer) += length;
  }

  /////////////////////////////////////////////////////////////////////////////////////////
  void
  user_write_data (png_structp png_ptr,  png_bytep data, png_size_t length)
  {
    std::vector<uint8_t>* pngVec = reinterpret_cast<std::vector<uint8_t>*>(png_get_io_ptr (png_ptr));
    std::copy (data, data + length, std::back_inserter (*pngVec));
  }

  /////////////////////////////////////////////////////////////////////////////////////////
  void
  user_flush_data (png_structp)
  {
  }
}

namespace pcl
{
  namespace io
  {
    ///////////////////////////////////////////////////////////////////////////////////////////
    template<typename T> void
    encodeImageToPNG (typename std::vector<T>& image_arg,
                      size_t width_arg,
                      size_t height_arg,
                      int image_format_arg,
                      typename std::vector<uint8_t>& pngData_arg,
                      int png_level_arg)
    {
      png_structp png_ptr;
      png_infop info_ptr;
      volatile int channels;

      if (image_arg.size () ==0)
        return;

      // Get amount of channels
      switch (image_format_arg)
       {
         case PNG_COLOR_TYPE_GRAY:
           channels = 1;
           break;
         case PNG_COLOR_TYPE_GRAY_ALPHA:
           channels = 2;
           break;
         case PNG_COLOR_TYPE_RGB:
           channels = 3;
           break;
         case PNG_COLOR_TYPE_RGB_ALPHA:
           channels = 4;
           break;
         default:
           channels = 0;
           break;
       }

      // Ensure valid input array
      assert (image_arg.size () == width_arg*height_arg*channels);

      // Initialize write structure
      png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0);
      assert (png_ptr && "creating png_create_write_structpng_create_write_struct failed");

      // Initialize info structure
      info_ptr = png_create_info_struct (png_ptr);
      assert (info_ptr && "Could not allocate info struct");

      // Setup Exception handling
      assert (setjmp(png_jmpbuf(png_ptr)) && "Error during png compression");

      // reserve memory for output data (300kB)
      pngData_arg.clear ();
      pngData_arg.reserve (300 * 1024);

      // Define I/O methods
      png_set_write_fn (png_ptr, reinterpret_cast<void*> (&pngData_arg),
                        user_write_data, user_flush_data);

      // Define zlib compression level
      if (png_level_arg >= 0)
      {
        png_set_compression_level (png_ptr, png_level_arg);
      }
      else
      {
        png_set_compression_level (png_ptr, Z_DEFAULT_COMPRESSION);
      }

      // Write header
      png_set_IHDR (png_ptr, info_ptr, width_arg, height_arg, sizeof(T) * 8,
          image_format_arg, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
          PNG_FILTER_TYPE_DEFAULT);

      png_write_info (png_ptr, info_ptr);

      // Write image data
      size_t y;
      for (y = 0; y < height_arg; y++)
      {
        png_write_row (png_ptr, reinterpret_cast<png_bytep> (&image_arg[y * width_arg * channels]));
      }

      // End write
      png_write_end (png_ptr, 0);

      if (info_ptr)
        png_free_data (png_ptr, info_ptr, PNG_FREE_ALL, -1);
      if (png_ptr)
        png_destroy_write_struct (&png_ptr, 0);
    }

    ///////////////////////////////////////////////////////////////////////////////////////////
    template<typename T> void
    decodePNGImage (typename std::vector<uint8_t>& pngData_arg,
                    typename std::vector<T>& imageData_arg,
                    size_t& width_arg,
                    size_t& height_arg,
                    unsigned int& channels_arg)
    {
      int y;
      png_structp png_ptr;
      png_infop info_ptr;
      png_uint_32 png_width;
      png_uint_32 png_height;
      int png_bit_depth, png_color_type, png_interlace_type;

      png_bytep * row_pointers;

      if (pngData_arg.size () == 0)
        return;

      png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0);
      assert (png_ptr && "creating png_create_write_structpng_create_write_struct failed");

      // Initialize info structure
      info_ptr = png_create_info_struct (png_ptr);
      assert(info_ptr && "Could not allocate info struct");

      // Setup Exception handling
      assert (setjmp (png_jmpbuf(png_ptr)) && "Error during png compression");

      uint8_t* input_pointer = &pngData_arg[0];
      png_set_read_fn (png_ptr, reinterpret_cast<void*> (&input_pointer), user_read_data);

      png_read_info (png_ptr, info_ptr);

      png_get_IHDR (png_ptr, info_ptr, &png_width, &png_height, &png_bit_depth,
          &png_color_type, &png_interlace_type, NULL, NULL);

      // ensure a color bit depth of 8
      assert(png_bit_depth==sizeof(T)*8);

      unsigned int png_channels;
      switch (png_color_type)
      {
        case PNG_COLOR_TYPE_GRAY:
          png_channels = 1;
          break;
        case PNG_COLOR_TYPE_GRAY_ALPHA:
          png_channels = 2;
          break;
        case PNG_COLOR_TYPE_RGB:
          png_channels = 3;
          break;
        case PNG_COLOR_TYPE_RGB_ALPHA:
          png_channels = 4;
          break;
        default:
          png_channels = 0;
          break;
      }

      width_arg = png_width;
      height_arg = png_height;
      channels_arg = png_channels;

      imageData_arg.clear ();
      imageData_arg.resize (png_height * png_width * png_channels);

      row_pointers = reinterpret_cast<png_bytep*> (malloc (sizeof(png_bytep) * png_height));

      for (y = 0; y < png_height; y++)
        row_pointers[y] = reinterpret_cast<png_byte*> (&imageData_arg[y * png_width * png_channels]);

      png_read_image (png_ptr, row_pointers);

      if (info_ptr)
        png_free_data (png_ptr, info_ptr, PNG_FREE_ALL, -1);
      if (png_ptr)
        png_destroy_read_struct (&png_ptr, 0, 0);
      if (row_pointers)
        free (row_pointers);
    }
  } // namespace io
} // namespace pcl

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::io::encodeMonoImageToPNG (std::vector<uint8_t>& image_arg,
                               size_t width_arg,
                               size_t height_arg,
                               std::vector<uint8_t>& pngData_arg,
                              int png_level_arg)
{
  encodeImageToPNG<uint8_t>(image_arg, width_arg, height_arg, PNG_COLOR_TYPE_GRAY, pngData_arg, png_level_arg);
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::io::encodeMonoImageToPNG (std::vector<uint16_t>& image_arg,
                               size_t width_arg,
                               size_t height_arg,
                               std::vector<uint8_t>& pngData_arg,
                               int png_level_arg)
{
  encodeImageToPNG<uint16_t>(image_arg, width_arg, height_arg, PNG_COLOR_TYPE_GRAY, pngData_arg, png_level_arg);
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::io::encodeRGBImageToPNG (std::vector<uint8_t>& image_arg,
                              size_t width_arg,
                              size_t height_arg,
                              std::vector<uint8_t>& pngData_arg,
                              int png_level_arg)
{
  encodeImageToPNG<uint8_t>(image_arg, width_arg, height_arg, PNG_COLOR_TYPE_RGB, pngData_arg, png_level_arg);
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::io::encodeRGBImageToPNG (std::vector<uint16_t>& image_arg,
                              size_t width_arg,
                              size_t height_arg,
                              std::vector<uint8_t>& pngData_arg,
                              int png_level_arg)
{
  encodeImageToPNG<uint16_t>(image_arg, width_arg, height_arg, PNG_COLOR_TYPE_RGB, pngData_arg, png_level_arg);
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::io::decodePNGToImage (std::vector<uint8_t>& pngData_arg,
                           std::vector<uint8_t>& imageData_arg,
                           size_t& width_arg,
                           size_t& height_arg,
                           unsigned int& channels_arg)
{
  decodePNGImage<uint8_t> (pngData_arg, imageData_arg, width_arg, height_arg, channels_arg);
}

///////////////////////////////////////////////////////////////////////////////////////////
void
pcl::io::decodePNGToImage (std::vector<uint8_t>& pngData_arg,
                           std::vector<uint16_t>& imageData_arg,
                           size_t& width_arg,
                           size_t& height_arg,
                           unsigned int& channels_arg)
{
  decodePNGImage<uint16_t> (pngData_arg, imageData_arg, width_arg, height_arg, channels_arg);
}

<|endoftext|>


<commit_before>#include "LogFile.h"

#include <fcntl.h>
#include <iostream>
#include <thrift/protocol/TJSONProtocol.h>

#include "FileOps.h"

using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;

template<class T>
struct WriteBlob : public Blob {
  WriteBlob(T obj) {
    serialize(obj);
  }

  void serialize(T obj) {
    TMemoryBuffer* buffer = new TMemoryBuffer();
    trans_.reset(buffer);
    TJSONProtocol protocol(trans_);

    obj.write(&protocol);

    buffer->getBuffer(&data, &len);
    cout << "Serialized id=" << obj.id << " len=" << len << "\n";
  }

  boost::shared_ptr<TTransport> trans_;
};

template<class T>
void deserialize(T& obj, Blob const& b) {
  TMemoryBuffer* buffer = new TMemoryBuffer(b.data, b.len, TMemoryBuffer::TAKE_OWNERSHIP);
  boost::shared_ptr<TTransport> trans(buffer);
  TJSONProtocol protocol(trans);

  obj.read(&protocol);
}

string LogFile::getValueFile(zeonid_t zid) {
  return valueDir_ + to_string(zid);
}

string LogFile::getPointFile(zeonid_t zid) {
  return pointDir_ + to_string(zid);
}

LogFile::LogFile(DataStoreConfig* config)
  : run_(true),
    queue_(config->maxBufferSize),
    pointDir_(config->pointDir),
    valueDir_(config->valueDir)
{
  FileOps::createDir(pointDir_);
  FileOps::createDir(valueDir_);
  writerThread_ = std::thread(&LogFile::consumer, this);
}

LogFile::~LogFile() {
  run_ = false;
  writerThread_.join();
}

void LogFile::consumer() {
  cout << "Starting writer thread...\n";

  core::Data data;
  int inactive = 0;
  while(run_) {
    if (queue_.read(data)) {
      cout << "Writing to disk: id=" << data.id << "\n";
      WriteBlob<Data> b(data); // serialize
      FileOps fileOp(getPointFile(data.id)); // open file
      fileOp.writeToFile(&b); // write
      inactive = 0;
    } else {
      inactive++;
    }
    if (inactive > 10) {
      this_thread::sleep_for(chrono::milliseconds(10));
    }
  }
}

void LogFile::recover(unordered_map<zeonid_t, vector<Data>>& pointData,
                      unordered_map<zeonid_t, string>& valueData)
{
  // List all files in directories
  vector<string> files;
  FileOps::getFilesInDir(pointDir_, files);

  for (auto const& file: files) {
    FileOps fileOp(pointDir_ + file);
    while(true) {
      Blob b;
      if (!fileOp.readFromFile(&b)) {
        break;
      }
      Data data;
      deserialize(data, b);
      pointData[data.id].emplace_back(data);
      cout << "Read from disk: id=" << data.id << "\n";
    }
  }

  FileOps::getFilesInDir(valueDir_, files);
  for (auto const& file: files) {
    FileOps fileOp(valueDir_ + file);
    Blob b;
    if (!fileOp.readFromFile(&b)) {
      continue;
    }
    Data data;
    deserialize(data, b);
    valueData[data.id] = data.value;
    cout << "Read from disk: id=" << data.id << " value=\"" << data.value << "\"\n";
  }
}

void LogFile::writePoint(core::Data const& data) {
  core::Data smallData;
  smallData.id = data.id;
  smallData.point = data.point;
  smallData.version = data.version;
  printf("Point enqueued for writing...\n");
  lock_guard<mutex> lock(pointLock_);
  queue_.write(smallData);
}

void LogFile::writeValue(core::Data const& data) {
  writePoint(data);

  WriteBlob<Data> b(data);

  lock_guard<mutex> lock(valueLock_);
  cout << "(reliable) Writing to disk: id=" << data.id << "\n";
  FileOps file(getValueFile(data.id), /* truncate */ true);
  if (!file.syncWriteToFile(&b)) {
    throw std::runtime_error("could not write");
  }
}
<commit_msg>no fsync temporarily<commit_after>#include "LogFile.h"

#include <fcntl.h>
#include <iostream>
#include <thrift/protocol/TJSONProtocol.h>

#include "FileOps.h"

using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;

template<class T>
struct WriteBlob : public Blob {
  WriteBlob(T obj) {
    serialize(obj);
  }

  void serialize(T obj) {
    TMemoryBuffer* buffer = new TMemoryBuffer();
    trans_.reset(buffer);
    TJSONProtocol protocol(trans_);

    obj.write(&protocol);

    buffer->getBuffer(&data, &len);
    cout << "Serialized id=" << obj.id << " len=" << len << "\n";
  }

  boost::shared_ptr<TTransport> trans_;
};

template<class T>
void deserialize(T& obj, Blob const& b) {
  TMemoryBuffer* buffer = new TMemoryBuffer(b.data, b.len, TMemoryBuffer::TAKE_OWNERSHIP);
  boost::shared_ptr<TTransport> trans(buffer);
  TJSONProtocol protocol(trans);

  obj.read(&protocol);
}

string LogFile::getValueFile(zeonid_t zid) {
  return valueDir_ + to_string(zid);
}

string LogFile::getPointFile(zeonid_t zid) {
  return pointDir_ + to_string(zid);
}

LogFile::LogFile(DataStoreConfig* config)
  : run_(true),
    queue_(config->maxBufferSize),
    pointDir_(config->pointDir),
    valueDir_(config->valueDir)
{
  FileOps::createDir(pointDir_);
  FileOps::createDir(valueDir_);
  writerThread_ = std::thread(&LogFile::consumer, this);
}

LogFile::~LogFile() {
  run_ = false;
  writerThread_.join();
}

void LogFile::consumer() {
  cout << "Starting writer thread...\n";

  core::Data data;
  int inactive = 0;
  while(run_) {
    if (queue_.read(data)) {
      cout << "Writing to disk: id=" << data.id << "\n";
      WriteBlob<Data> b(data); // serialize
      FileOps fileOp(getPointFile(data.id)); // open file
      fileOp.writeToFile(&b); // write
      inactive = 0;
    } else {
      inactive++;
    }
    if (inactive > 10) {
      this_thread::sleep_for(chrono::milliseconds(10));
    }
  }
}

void LogFile::recover(unordered_map<zeonid_t, vector<Data>>& pointData,
                      unordered_map<zeonid_t, string>& valueData)
{
  // List all files in directories
  vector<string> files;
  FileOps::getFilesInDir(pointDir_, files);

  for (auto const& file: files) {
    FileOps fileOp(pointDir_ + file);
    while(true) {
      Blob b;
      if (!fileOp.readFromFile(&b)) {
        break;
      }
      Data data;
      deserialize(data, b);
      pointData[data.id].emplace_back(data);
      cout << "Read from disk: id=" << data.id << "\n";
    }
  }

  FileOps::getFilesInDir(valueDir_, files);
  for (auto const& file: files) {
    FileOps fileOp(valueDir_ + file);
    Blob b;
    if (!fileOp.readFromFile(&b)) {
      continue;
    }
    Data data;
    deserialize(data, b);
    valueData[data.id] = data.value;
    cout << "Read from disk: id=" << data.id << " value=\"" << data.value << "\"\n";
  }
}

void LogFile::writePoint(core::Data const& data) {
  core::Data smallData;
  smallData.id = data.id;
  smallData.point = data.point;
  smallData.version = data.version;
  printf("Point enqueued for writing...\n");
  lock_guard<mutex> lock(pointLock_);
  queue_.write(smallData);
}

void LogFile::writeValue(core::Data const& data) {
  writePoint(data);

  WriteBlob<Data> b(data);

  lock_guard<mutex> lock(valueLock_);
  cout << "(reliable) Writing to disk: id=" << data.id << "\n";
  FileOps file(getValueFile(data.id), /* truncate */ true);
  //if (!file.syncWriteToFile(&b)) {
  if (!file.writeToFile(&b)) {
    throw std::runtime_error("could not write");
  }
}
<|endoftext|>


<commit_before>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2021 Hugo Beauzée-Luyssen, Videolabs, VideoLAN
 *
 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
 *
 * This program 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 program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

//#define XXH_NO_INLINE_HINTS 1

#include "XxHasher.h"

#define XXH_INLINE_ALL 1
#define XXH_STATIC_LINKING_ONLY 1

# include <xxhash.h>

#if defined(XXHASH_DYNAMIC_DISPATCH)
/*
 * The function is defined in another compile unit, but XXH_PUBLIC_API will
 * define is a static inline, which causes a static inline declaration to be
 * emited in this file while there's no definition available.
 * To work around this, we enforce an empty XXH_PUBLIC_API define before
 * including the dispatch header.
 */
# undef XXH_PUBLIC_API
# define XXH_PUBLIC_API
# include <xxh_x86dispatch.h>
#endif

#include <memory>
#include <cstdio>
#include <cinttypes>

namespace medialibrary
{
namespace utils
{
namespace hash
{

std::string toString( uint64_t hash )
{
    char buff[17];
    snprintf( buff, sizeof(buff), "%" PRIX64, hash );

    return std::string{ buff };
}

uint64_t xxFromBuff( const uint8_t* buff, size_t size )
{
    return XXH3_64bits( buff, size );
}

uint64_t xxFromFile( const std::string& path )
{
    std::unique_ptr<FILE, decltype(&fclose)> file{
        fopen( path.c_str(), "rb" ), &fclose
    };
    std::unique_ptr<XXH3_state_t, decltype(&XXH3_freeState)> state{
        XXH3_createState(), &XXH3_freeState
    };
    if ( state == nullptr )
        throw std::bad_alloc{};
    XXH3_64bits_reset( state.get() );
    uint8_t buff[ 64 * 64 ];
    while ( feof( file.get() ) == false )
    {
        auto read = fread( buff, 1, sizeof( buff ), file.get() );
        XXH3_64bits_update( state.get(), buff, read );
    }
    return XXH3_64bits_digest( state.get() );
}

}
}
}
<commit_msg>utils: XxHasher: Remove commented line<commit_after>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2021 Hugo Beauzée-Luyssen, Videolabs, VideoLAN
 *
 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
 *
 * This program 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 program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "XxHasher.h"

#define XXH_INLINE_ALL 1
#define XXH_STATIC_LINKING_ONLY 1

# include <xxhash.h>

#if defined(XXHASH_DYNAMIC_DISPATCH)
/*
 * The function is defined in another compile unit, but XXH_PUBLIC_API will
 * define is a static inline, which causes a static inline declaration to be
 * emited in this file while there's no definition available.
 * To work around this, we enforce an empty XXH_PUBLIC_API define before
 * including the dispatch header.
 */
# undef XXH_PUBLIC_API
# define XXH_PUBLIC_API
# include <xxh_x86dispatch.h>
#endif

#include <memory>
#include <cstdio>
#include <cinttypes>

namespace medialibrary
{
namespace utils
{
namespace hash
{

std::string toString( uint64_t hash )
{
    char buff[17];
    snprintf( buff, sizeof(buff), "%" PRIX64, hash );

    return std::string{ buff };
}

uint64_t xxFromBuff( const uint8_t* buff, size_t size )
{
    return XXH3_64bits( buff, size );
}

uint64_t xxFromFile( const std::string& path )
{
    std::unique_ptr<FILE, decltype(&fclose)> file{
        fopen( path.c_str(), "rb" ), &fclose
    };
    std::unique_ptr<XXH3_state_t, decltype(&XXH3_freeState)> state{
        XXH3_createState(), &XXH3_freeState
    };
    if ( state == nullptr )
        throw std::bad_alloc{};
    XXH3_64bits_reset( state.get() );
    uint8_t buff[ 64 * 64 ];
    while ( feof( file.get() ) == false )
    {
        auto read = fread( buff, 1, sizeof( buff ), file.get() );
        XXH3_64bits_update( state.get(), buff, read );
    }
    return XXH3_64bits_digest( state.get() );
}

}
}
}
<|endoftext|>


<commit_before>/**
 * bitcoind.js
 * Copyright (c) 2014, BitPay (MIT License)
 *
 * bitcoindjs.cc:
 *   A bitcoind node.js binding.
 */

#include "nan.h"

// bitcoind headers:
#include "core.h"
#include "addrman.h"
#include "checkpoints.h"
#include "crypter.h"
#include "main.h"
// #include "random.h"
// #include "timedata.h"
#include "walletdb.h"
#include "alert.h"
#include "checkqueue.h"
#include "db.h"
#include "miner.h"
#include "rpcclient.h"
#include "tinyformat.h"
#include "wallet.h"
#include "allocators.h"
#include "clientversion.h"
#include "hash.h"
#include "mruset.h"
#include "rpcprotocol.h"
#include "txdb.h"
#include "base58.h"
#include "coincontrol.h"
#include "init.h"
#include "netbase.h"
#include "rpcserver.h"
#include "txmempool.h"
#include "bloom.h"
#include "coins.h"
#include "key.h"
#include "net.h"
#include "script.h"
#include "ui_interface.h"
// #include "chainparamsbase.h"
#include "compat.h"
#include "keystore.h"
#include "noui.h"
#include "serialize.h"
#include "uint256.h"
#include "chainparams.h"
#include "core.h"
#include "leveldbwrapper.h"
// #include "pow.h"
#include "sync.h"
#include "util.h"
// #include "chainparamsseeds.h"
// #include "core_io.h"
#include "limitedmap.h"
#include "protocol.h"
#include "threadsafety.h"
#include "version.h"

#include <node.h>
#include <string>

#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>

using namespace node;
using namespace v8;

NAN_METHOD(StartBitcoind);

void
async_work(uv_work_t *req);

void
async_after(uv_work_t *req);

extern "C" void
init(Handle<Object>);

struct async_data {
  Persistent<Function> callback;
  bool err;
  std::string err_msg;
  char *result;
};

/**
 * StartBitcoind
 * bitcoind.start(callback)
 */

NAN_METHOD(StartBitcoind) {
  NanScope();

  if (args.Length() < 1 || !args[0]->IsFunction()) {
    return NanThrowError(
        "Usage: bitcoind.start(callback)");
  }

  Local<Function> callback = Local<Function>::Cast(args[0]);

  async_data* data = new async_data();
  data->err = false;
  data->callback = Persistent<Function>::New(callback);

  uv_work_t *req = new uv_work_t();
  req->data = data;

  int status = uv_queue_work(uv_default_loop(),
    req, async_work, (uv_after_work_cb)async_after);

  assert(status == 0);

  NanReturnValue(Undefined());
}

void async_work(uv_work_t *req) {
  async_data* data = static_cast<async_data*>(req->data);
  data->result = (char *)strdup("opened");
}

void async_after(uv_work_t *req) {
  NanScope();
  async_data* data = static_cast<async_data*>(req->data);

  if (data->err) {
    Local<Value> err = Exception::Error(String::New(data->err_msg.c_str()));
    const unsigned argc = 1;
    Local<Value> argv[1] = { err };
    TryCatch try_catch;
    data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
    if (try_catch.HasCaught()) {
      node::FatalException(try_catch);
    }
  } else {
    const unsigned argc = 2;
    Local<Value> argv[2] = {
      Local<Value>::New(Null()),
      Local<Value>::New(String::New(data->result))
    };
    TryCatch try_catch;
    data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
    if (try_catch.HasCaught()) {
      node::FatalException(try_catch);
    }
  }

  data->callback.Dispose();

  if (data->result != NULL) {
    free(data->result);
  }

  delete data;
  delete req;
}

/**
 * Init
 */

extern "C" void
init(Handle<Object> target) {
  NanScope();
  NODE_SET_METHOD(target, "start", StartBitcoind);
}

NODE_MODULE(bitcoindjs, init)
<commit_msg>add start_node function to start up net.cpp threads.<commit_after>/**
 * bitcoind.js
 * Copyright (c) 2014, BitPay (MIT License)
 *
 * bitcoindjs.cc:
 *   A bitcoind node.js binding.
 */

#include "nan.h"

// bitcoind headers:
#include "core.h"
#include "addrman.h"
#include "checkpoints.h"
#include "crypter.h"
#include "main.h"
// #include "random.h"
// #include "timedata.h"
#include "walletdb.h"
#include "alert.h"
#include "checkqueue.h"
#include "db.h"
#include "miner.h"
#include "rpcclient.h"
#include "tinyformat.h"
#include "wallet.h"
#include "allocators.h"
#include "clientversion.h"
#include "hash.h"
#include "mruset.h"
#include "rpcprotocol.h"
#include "txdb.h"
#include "base58.h"
#include "coincontrol.h"
#include "init.h"
#include "netbase.h"
#include "rpcserver.h"
#include "txmempool.h"
#include "bloom.h"
#include "coins.h"
#include "key.h"
#include "net.h"
#include "script.h"
#include "ui_interface.h"
// #include "chainparamsbase.h"
#include "compat.h"
#include "keystore.h"
#include "noui.h"
#include "serialize.h"
#include "uint256.h"
#include "chainparams.h"
#include "core.h"
#include "leveldbwrapper.h"
// #include "pow.h"
#include "sync.h"
#include "util.h"
// #include "chainparamsseeds.h"
// #include "core_io.h"
#include "limitedmap.h"
#include "protocol.h"
#include "threadsafety.h"
#include "version.h"

#include <node.h>
#include <string>

#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>

using namespace node;
using namespace v8;

NAN_METHOD(StartBitcoind);

static void
async_work(uv_work_t *req);

static void
async_after(uv_work_t *req);

static int
start_node(void);

extern "C" void
init(Handle<Object>);

struct async_data {
  Persistent<Function> callback;
  bool err;
  std::string err_msg;
  char *result;
};

/**
 * StartBitcoind
 * bitcoind.start(callback)
 */

NAN_METHOD(StartBitcoind) {
  NanScope();

  if (args.Length() < 1 || !args[0]->IsFunction()) {
    return NanThrowError(
        "Usage: bitcoind.start(callback)");
  }

  Local<Function> callback = Local<Function>::Cast(args[0]);

  async_data* data = new async_data();
  data->err = false;
  data->callback = Persistent<Function>::New(callback);

  uv_work_t *req = new uv_work_t();
  req->data = data;

  int status = uv_queue_work(uv_default_loop(),
    req, async_work, (uv_after_work_cb)async_after);

  assert(status == 0);

  NanReturnValue(Undefined());
}

static void
async_work(uv_work_t *req) {
  async_data* data = static_cast<async_data*>(req->data);
  //start_node();
  data->result = (char *)strdup("opened");
}

static void
async_after(uv_work_t *req) {
  NanScope();
  async_data* data = static_cast<async_data*>(req->data);

  if (data->err) {
    Local<Value> err = Exception::Error(String::New(data->err_msg.c_str()));
    const unsigned argc = 1;
    Local<Value> argv[1] = { err };
    TryCatch try_catch;
    data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
    if (try_catch.HasCaught()) {
      node::FatalException(try_catch);
    }
  } else {
    const unsigned argc = 2;
    Local<Value> argv[2] = {
      Local<Value>::New(Null()),
      Local<Value>::New(String::New(data->result))
    };
    TryCatch try_catch;
    data->callback->Call(Context::GetCurrent()->Global(), argc, argv);
    if (try_catch.HasCaught()) {
      node::FatalException(try_catch);
    }
  }

  data->callback.Dispose();

  if (data->result != NULL) {
    free(data->result);
  }

  delete data;
  delete req;
}

extern void (ThreadImport)(std::vector<boost::filesystem::path>);
extern void (DetectShutdownThread)(boost::thread_group*);
extern int nScriptCheckThreads;
// extern const int DEFAULT_SCRIPTCHECK_THREADS; // static!!

// Relevant:
// ~/bitcoin/src/init.cpp
// ~/bitcoin/src/bitcoind.cpp
// ~/bitcoin/src/main.h

static int
start_node(void) {
  boost::thread_group threadGroup;
  boost::thread *detectShutdownThread = NULL;
  detectShutdownThread = new boost::thread(
    boost::bind(&DetectShutdownThread, &threadGroup));

  // int nScriptCheckThreads = 0;
  for (int i = 0; i < nScriptCheckThreads - 1; i++) {
    threadGroup.create_thread(&ThreadScriptCheck);
  }

  std::vector<boost::filesystem::path> vImportFiles;
  threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles));

  StartNode(threadGroup);

#ifdef ENABLE_WALLET
  if (pwalletMain) {
    // Add wallet transactions that aren't already in a block to mapTransactions
    pwalletMain->ReacceptWalletTransactions();
    // Run a thread to flush wallet periodically
    threadGroup.create_thread(boost::bind(&ThreadFlushWalletDB, boost::ref(pwalletMain->strWalletFile)));
  }
#endif

  return 0;
}

/**
 * Init
 */

extern "C" void
init(Handle<Object> target) {
  NanScope();
  NODE_SET_METHOD(target, "start", StartBitcoind);
}

NODE_MODULE(bitcoindjs, init)
<|endoftext|>


<commit_before>/*
  Copyright Kitware, Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#include "Detect.h"
#include "Options.h"
#include "RunClang.h"
#include "Utils.h"

#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"

#include <iostream>
#include <set>
#include <vector>
#include <string.h>

class StringSaver: public llvm::cl::StringSaver {
  std::set<std::string> Strings;
public:
  const char* SaveString(const char* s) {
    return this->Strings.insert(s).first->c_str();
  }
};

//----------------------------------------------------------------------------
int main(int argc_in, const char** argv_in)
{
  suppressInteractiveErrors();

  llvm::SmallVector<const char*, 64> argv;
  llvm::SpecificBumpPtrAllocator<char> argAlloc;
  if(llvm::error_code e =
     llvm::sys::Process::GetArgumentVector(
       argv, llvm::ArrayRef<const char*>(argv_in, argc_in), argAlloc)) {
    llvm::errs() << "error: could not get arguments: " << e.message() << "\n";
    return 1;
  } else if(argv.empty()) {
    llvm::errs() << "error: no argv[0]?!\n";
    return 1;
  }

  StringSaver argSaver;
  llvm::cl::ExpandResponseFiles(
    argSaver, llvm::cl::TokenizeGNUCommandLine, argv);

  size_t const argc = argv.size();

  if(!findResourceDir(argv[0], std::cerr)) {
    return 1;
  }

  const char* usage =
    "Usage: castxml [--castxml-gccxml] [<clang-args>...] \\\n"
    "               [--castxml-start <qualified-name>]... \\\n"
    "               [--castxml-cc-<id> <cc> [<cc-args>...]]\n"
    ;

  Options opts;
  llvm::SmallVector<const char *, 16> clang_args;
  llvm::SmallVector<const char *, 16> cc_args;
  const char* cc_id = 0;

  for(size_t i=1; i < argc; ++i) {
    if(strcmp(argv[i], "--castxml-gccxml") == 0) {
      if(!opts.GccXml) {
        opts.GccXml = true;
      } else {
        std::cerr <<
          "error: '--castxml-gccxml' may be given at most once!\n"
          "\n" <<
          usage
          ;
        return 1;
      }
    } else if(strcmp(argv[i], "--castxml-start") == 0) {
      if((i+1) < argc) {
        opts.StartNames.push_back(argv[++i]);
      } else {
        std::cerr <<
          "error: argument to '--castxml-start' is missing "
          "(expected 1 value)\n"
          "\n" <<
          usage
          ;
        return 1;
      }
    } else if(strncmp(argv[i], "--castxml-cc-", 13) == 0) {
      if(!cc_id) {
        cc_id = argv[i] + 13;
        for(++i;i < argc && strncmp(argv[i], "--castxml-", 10) != 0; ++i) {
          cc_args.push_back(argv[i]);
        }
        --i;
      } else {
        std::cerr <<
          "error: '--castxml-cc-<id>' may be given at most once!\n"
          "\n" <<
          usage
          ;
        return 1;
      }
    } else if(strcmp(argv[i], "-E") == 0) {
      opts.PPOnly = true;
    } else if(strcmp(argv[i], "-o") == 0) {
      if((i+1) < argc) {
        opts.OutputFile = argv[++i];
      } else {
        std::cerr <<
          "error: argument to '-o' is missing (expected 1 value)\n"
          "\n" <<
          usage
          ;
        return 1;
      }
    } else if(strcmp(argv[i], "--version") == 0) {
      std::cout << "castxml version " << getVersionString() << std::endl;
      // Also print Clang version.
      clang_args.push_back(argv[i]);
    } else {
      clang_args.push_back(argv[i]);
    }
  }

  if(opts.PPOnly && opts.GccXml) {
    std::cerr <<
      "error: '--castxml-gccxml' and '-E' may not both be given\n"
      "\n" <<
      usage
      ;
    return 1;
  }

  if(cc_id) {
    opts.HaveCC = true;
    if(cc_args.empty()) {
      std::cerr <<
        "error: '--castxml-cc-" << cc_id <<
        "' must be followed by a compiler command!\n"
        "\n" <<
        usage
        ;
      return 1;
    }
    if(!detectCC(cc_id, cc_args.data(), cc_args.data() + cc_args.size(),
                 opts)) {
      return 1;
    }
  }

  if(clang_args.empty()) {
    return 0;
  }

  return runClang(clang_args.data(), clang_args.data() + clang_args.size(),
                  opts);
}
<commit_msg>castxml: Rewrite usage output to include more detail<commit_after>/*
  Copyright Kitware, Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#include "Detect.h"
#include "Options.h"
#include "RunClang.h"
#include "Utils.h"

#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"

#include <iostream>
#include <set>
#include <vector>
#include <string.h>

class StringSaver: public llvm::cl::StringSaver {
  std::set<std::string> Strings;
public:
  const char* SaveString(const char* s) {
    return this->Strings.insert(s).first->c_str();
  }
};

//----------------------------------------------------------------------------
int main(int argc_in, const char** argv_in)
{
  suppressInteractiveErrors();

  llvm::SmallVector<const char*, 64> argv;
  llvm::SpecificBumpPtrAllocator<char> argAlloc;
  if(llvm::error_code e =
     llvm::sys::Process::GetArgumentVector(
       argv, llvm::ArrayRef<const char*>(argv_in, argc_in), argAlloc)) {
    llvm::errs() << "error: could not get arguments: " << e.message() << "\n";
    return 1;
  } else if(argv.empty()) {
    llvm::errs() << "error: no argv[0]?!\n";
    return 1;
  }

  StringSaver argSaver;
  llvm::cl::ExpandResponseFiles(
    argSaver, llvm::cl::TokenizeGNUCommandLine, argv);

  size_t const argc = argv.size();

  if(!findResourceDir(argv[0], std::cerr)) {
    return 1;
  }

  const char* usage =
    "Usage: castxml ( <castxml-opt> | <clang-opt> | <src> )...\n"
    "\n"
    "  Options interpreted by castxml are listed below.\n"
    "  Remaining options are given to the internal Clang compiler.\n"
    "\n"
    "Options:\n"
    "\n"
    "  --castxml-cc-<id> <cc> [ <cc-args>... ]\n"
    "    Simulate given <id>-like compiler command, where <id> is\n"
    "    one of: gnu, msvc\n"
    "    (This option must appear last and consumes remaining options)\n"
    "\n"
    "  --castxml-gccxml\n"
    "    Write gccxml-format output to <src>.xml or file named by '-o'\n"
    "\n"
    "  --castxml-start <name>\n"
    "    Start AST traversal at declaration with given (qualified) name\n"
    "\n"
    "  -o <file>\n"
    "    Write output to <file>\n"
    "\n"
    "  --version\n"
    "    Print castxml and internal Clang compiler version information\n"
    "\n"
    ;

  Options opts;
  llvm::SmallVector<const char *, 16> clang_args;
  llvm::SmallVector<const char *, 16> cc_args;
  const char* cc_id = 0;

  for(size_t i=1; i < argc; ++i) {
    if(strcmp(argv[i], "--castxml-gccxml") == 0) {
      if(!opts.GccXml) {
        opts.GccXml = true;
      } else {
        std::cerr <<
          "error: '--castxml-gccxml' may be given at most once!\n"
          "\n" <<
          usage
          ;
        return 1;
      }
    } else if(strcmp(argv[i], "--castxml-start") == 0) {
      if((i+1) < argc) {
        opts.StartNames.push_back(argv[++i]);
      } else {
        std::cerr <<
          "error: argument to '--castxml-start' is missing "
          "(expected 1 value)\n"
          "\n" <<
          usage
          ;
        return 1;
      }
    } else if(strncmp(argv[i], "--castxml-cc-", 13) == 0) {
      if(!cc_id) {
        cc_id = argv[i] + 13;
        for(++i;i < argc && strncmp(argv[i], "--castxml-", 10) != 0; ++i) {
          cc_args.push_back(argv[i]);
        }
        --i;
      } else {
        std::cerr <<
          "error: '--castxml-cc-<id>' may be given at most once!\n"
          "\n" <<
          usage
          ;
        return 1;
      }
    } else if(strcmp(argv[i], "-E") == 0) {
      opts.PPOnly = true;
    } else if(strcmp(argv[i], "-o") == 0) {
      if((i+1) < argc) {
        opts.OutputFile = argv[++i];
      } else {
        std::cerr <<
          "error: argument to '-o' is missing (expected 1 value)\n"
          "\n" <<
          usage
          ;
        return 1;
      }
    } else if(strcmp(argv[i], "--version") == 0) {
      std::cout << "castxml version " << getVersionString() << std::endl;
      // Also print Clang version.
      clang_args.push_back(argv[i]);
    } else {
      clang_args.push_back(argv[i]);
    }
  }

  if(opts.PPOnly && opts.GccXml) {
    std::cerr <<
      "error: '--castxml-gccxml' and '-E' may not both be given\n"
      "\n" <<
      usage
      ;
    return 1;
  }

  if(cc_id) {
    opts.HaveCC = true;
    if(cc_args.empty()) {
      std::cerr <<
        "error: '--castxml-cc-" << cc_id <<
        "' must be followed by a compiler command!\n"
        "\n" <<
        usage
        ;
      return 1;
    }
    if(!detectCC(cc_id, cc_args.data(), cc_args.data() + cc_args.size(),
                 opts)) {
      return 1;
    }
  }

  if(clang_args.empty()) {
    return 0;
  }

  return runClang(clang_args.data(), clang_args.data() + clang_args.size(),
                  opts);
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com).  All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//   * Neither the name of Shuo Chen nor the names of other contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
#include "uri.h"

#include <cstdlib>
#include <string>
#include <unordered_map>

#include "string_utils.h"

namespace cnetpp {
namespace base {

const std::regex Uri::kUriRegex("([a-zA-Z][a-zA-Z0-9+.-]*):" // scheme:
                                 "([^?#]*)" // authority and path
                                 "(?:\\?([^#]*))?" // ?query
                                 "(?:#(.*))?"); // #fragment

const std::regex Uri::kAuthorityAndPathRegex("//([^/]*)(/.*)?");

const std::regex Uri::kAuthorityRegex(
    "(?:([^@:]*)(?::([^@]*))?@)?" // username, password
    "(\\[[^\\]]*\\]|[^\\[:]*)"    // host (IP-literal (e.g. '['+IPv6+']',
                                  // dotted-IPv4, or named host)
    "(?::(\\d*))?"); // port

const std::regex Uri::kQueryParamRegex("(^|&)([^=&]*)=?([^=&]*)(?=(&|$))");

static uint16_t get_scheme_default_port(const std::string& schema) {
  bool scheme2port_map_inited = false;
  std::unordered_map<std::string, uint16_t> scheme2port_map;
  if (!scheme2port_map_inited) {
    scheme2port_map.insert(std::make_pair("http", 80));
    scheme2port_map.insert(std::make_pair("https", 443));
    scheme2port_map_inited = true;
  }
  auto i = scheme2port_map.find(schema);
  if (i == scheme2port_map.end()) {
    return 0;
  }
  return i->second;
}

bool Uri::Parse(const std::string& str_uri) {
  port_ = 0;

  std::smatch match;
  if (!std::regex_match(str_uri.begin(), str_uri.end(), match, kUriRegex)) {
    return false;
  }

  auto &sub_match = match[1];
  scheme_ = std::move(std::string(sub_match.first, sub_match.second));
  scheme_ = StringUtils::ToLower(scheme_);

  auto &authority_and_path = match[2];
  std::smatch authority_and_path_match;
  if (!std::regex_match(authority_and_path.first,
                        authority_and_path.second,
                        authority_and_path_match,
                        kAuthorityAndPathRegex)) {
    // Does not start with //, doesn't have authority
    path_ = authority_and_path;
  } else {
    auto &authority = authority_and_path_match[1];
    std::smatch authority_match;
    if (!std::regex_match(authority.first,
                          authority.second,
                          authority_match,
                          kAuthorityRegex)) {
      return false;
    }

    std::string port(authority_match[4].first, authority_match[4].second);
    port_str_ = port;
    if (!port.empty()) {
      port_ = static_cast<uint16_t>(std::strtoul(port.c_str(), nullptr, 10));
    } else {
      port_ = get_scheme_default_port(scheme_);
    }

    username_ = std::string(authority_match[1].first,
                            authority_match[1].second);
    password_ = std::string(authority_match[2].first,
                            authority_match[2].second);
    host_ = std::string(authority_match[3].first,
                        authority_match[3].second);
    path_ = std::string(authority_and_path_match[2].first,
                        authority_and_path_match[2].second);
  }

  query_ = std::string(match[3].first, match[3].second);
  if (!query_.empty()) {
    // Parse query string
    std::sregex_iterator param_begin_itr(match[3].first,
                                        match[3].second,
                                        kQueryParamRegex);
    std::sregex_iterator param_end_itr;
    for (auto itr = param_begin_itr; itr != param_end_itr; itr++) {
      if (itr->length(2) == 0) {
        // key is empty, ignore it
        continue;
      }
      query_params_.emplace_back(
          std::string((*itr)[2].first, (*itr)[2].second), // parameter name
          std::string((*itr)[3].first, (*itr)[3].second)  // parameter value
      );
    }
  }

  fragment_ = std::move(std::string(match[4].first, match[4].second));
  valid_ = true;
  return true;
}

std::string Uri::String() const {
  std::string str_uri;
  str_uri.append(scheme_);
  str_uri.append("://");
  if (!password_.empty()) {
    str_uri.append(username_);
    str_uri.append(":");
    str_uri.append(password_);
    str_uri.append("@");
  } else if (!username_.empty()) {
    str_uri.append(username_);
    str_uri.append("@");
  }

  str_uri.append(host_);
  if (!port_str_.empty()) {
    str_uri.append(":");
#if 0
    str_uri.append(StringUtils::NumberToStr(port_));
#endif
    str_uri.append(port_str_);
  }
  str_uri.append(path_);
  if (!query_.empty()) {
    str_uri.append("?");
    str_uri.append(query_);
  }
  if (!fragment_.empty()) {
    str_uri.append("#");
    str_uri.append(fragment_);
  }

  return std::move(str_uri);
}

std::string Uri::Authority() const {
  std::string res;

  // Port is 5 characters max and we have up to 3 delimiters.
  res.reserve(host_.size() + username_.size() + password_.size() + 8);

  if (!username_.empty() || !password_.empty()) {
    res.append(username_);

    if (!password_.empty()) {
      res.push_back(':');
      res.append(password_);
    }

    res.push_back('@');
  }

  res.append(host_);

  if (!port_str_.empty()) {
    res.push_back(':');
#if 0
    res.append(StringUtils::NumberToStr(port_));
#endif
    res.append(port_str_);
  }

  return std::move(res);
}

std::string Uri::Hostname() const {
  if (host_.size() > 0 && host_[0] == '[') {
    // If it starts with '[', then it should end with ']',
    // this is ensured by regex
    return std::move(host_.substr(1, host_.size() - 2));
  }
  return host_;
}

}  // namespace base
}  // namespace cnetpp

<commit_msg>修改了uri中的get_scheme_default_port的bug<commit_after>// Copyright (c) 2015, myjfm(mwxjmmyjfm@gmail.com).  All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//   * Neither the name of Shuo Chen nor the names of other contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
#include "uri.h"

#include <cstdlib>
#include <string>
#include <unordered_map>

#include "string_utils.h"

namespace cnetpp {
namespace base {

const std::regex Uri::kUriRegex("([a-zA-Z][a-zA-Z0-9+.-]*):" // scheme:
                                 "([^?#]*)" // authority and path
                                 "(?:\\?([^#]*))?" // ?query
                                 "(?:#(.*))?"); // #fragment

const std::regex Uri::kAuthorityAndPathRegex("//([^/]*)(/.*)?");

const std::regex Uri::kAuthorityRegex(
    "(?:([^@:]*)(?::([^@]*))?@)?" // username, password
    "(\\[[^\\]]*\\]|[^\\[:]*)"    // host (IP-literal (e.g. '['+IPv6+']',
                                  // dotted-IPv4, or named host)
    "(?::(\\d*))?"); // port

const std::regex Uri::kQueryParamRegex("(^|&)([^=&]*)=?([^=&]*)(?=(&|$))");

static const std::unordered_map<std::string, uint16_t> kSchemeToPortMap = {{"http", 80}, {"https", 443}};
static uint16_t get_scheme_default_port(const std::string& schema) {
  auto i = kSchemeToPortMap.find(schema);
  if (i == kSchemeToPortMap.end()) {
    return 0;
  }
  return i->second;
}

bool Uri::Parse(const std::string& str_uri) {
  port_ = 0;

  std::smatch match;
  if (!std::regex_match(str_uri.begin(), str_uri.end(), match, kUriRegex)) {
    return false;
  }

  auto &sub_match = match[1];
  scheme_ = std::move(std::string(sub_match.first, sub_match.second));
  scheme_ = StringUtils::ToLower(scheme_);

  auto &authority_and_path = match[2];
  std::smatch authority_and_path_match;
  if (!std::regex_match(authority_and_path.first,
                        authority_and_path.second,
                        authority_and_path_match,
                        kAuthorityAndPathRegex)) {
    // Does not start with //, doesn't have authority
    path_ = authority_and_path;
  } else {
    auto &authority = authority_and_path_match[1];
    std::smatch authority_match;
    if (!std::regex_match(authority.first,
                          authority.second,
                          authority_match,
                          kAuthorityRegex)) {
      return false;
    }

    std::string port(authority_match[4].first, authority_match[4].second);
    port_str_ = port;
    if (!port.empty()) {
      port_ = static_cast<uint16_t>(std::strtoul(port.c_str(), nullptr, 10));
    } else {
      port_ = get_scheme_default_port(scheme_);
    }

    username_ = std::string(authority_match[1].first,
                            authority_match[1].second);
    password_ = std::string(authority_match[2].first,
                            authority_match[2].second);
    host_ = std::string(authority_match[3].first,
                        authority_match[3].second);
    path_ = std::string(authority_and_path_match[2].first,
                        authority_and_path_match[2].second);
  }

  query_ = std::string(match[3].first, match[3].second);
  if (!query_.empty()) {
    // Parse query string
    std::sregex_iterator param_begin_itr(match[3].first,
                                        match[3].second,
                                        kQueryParamRegex);
    std::sregex_iterator param_end_itr;
    for (auto itr = param_begin_itr; itr != param_end_itr; itr++) {
      if (itr->length(2) == 0) {
        // key is empty, ignore it
        continue;
      }
      query_params_.emplace_back(
          std::string((*itr)[2].first, (*itr)[2].second), // parameter name
          std::string((*itr)[3].first, (*itr)[3].second)  // parameter value
      );
    }
  }

  fragment_ = std::move(std::string(match[4].first, match[4].second));
  valid_ = true;
  return true;
}

std::string Uri::String() const {
  std::string str_uri;
  str_uri.append(scheme_);
  str_uri.append("://");
  if (!password_.empty()) {
    str_uri.append(username_);
    str_uri.append(":");
    str_uri.append(password_);
    str_uri.append("@");
  } else if (!username_.empty()) {
    str_uri.append(username_);
    str_uri.append("@");
  }

  str_uri.append(host_);
  if (!port_str_.empty()) {
    str_uri.append(":");
#if 0
    str_uri.append(StringUtils::NumberToStr(port_));
#endif
    str_uri.append(port_str_);
  }
  str_uri.append(path_);
  if (!query_.empty()) {
    str_uri.append("?");
    str_uri.append(query_);
  }
  if (!fragment_.empty()) {
    str_uri.append("#");
    str_uri.append(fragment_);
  }

  return std::move(str_uri);
}

std::string Uri::Authority() const {
  std::string res;

  // Port is 5 characters max and we have up to 3 delimiters.
  res.reserve(host_.size() + username_.size() + password_.size() + 8);

  if (!username_.empty() || !password_.empty()) {
    res.append(username_);

    if (!password_.empty()) {
      res.push_back(':');
      res.append(password_);
    }

    res.push_back('@');
  }

  res.append(host_);

  if (!port_str_.empty()) {
    res.push_back(':');
#if 0
    res.append(StringUtils::NumberToStr(port_));
#endif
    res.append(port_str_);
  }

  return std::move(res);
}

std::string Uri::Hostname() const {
  if (host_.size() > 0 && host_[0] == '[') {
    // If it starts with '[', then it should end with ']',
    // this is ensured by regex
    return std::move(host_.substr(1, host_.size() - 2));
  }
  return host_;
}

}  // namespace base
}  // namespace cnetpp

<|endoftext|>