<commit_before>/*
 * HTTPConnection.cpp
 *****************************************************************************
 * Copyright (C) 2014-2015 - VideoLAN and VLC Authors
 *
 * 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.
 *****************************************************************************/

#include "HTTPConnection.hpp"
#include "Sockets.hpp"
#include "../adaptative/tools/Helper.h"

#include <sstream>

using namespace adaptative::http;

HTTPConnection::HTTPConnection(vlc_object_t *stream_, Socket *socket_, bool persistent)
{
    socket = socket_;
    stream = stream_;
    psz_useragent = var_InheritString(stream, "http-user-agent");
    bytesRead = 0;
    contentLength = 0;
    queryOk = false;
    retries = 0;
    connectionClose = !persistent;
    port = 80;
    available = true;
}

HTTPConnection::~HTTPConnection()
{
    free(psz_useragent);
    delete socket;
}

bool HTTPConnection::compare(const std::string &hostname, uint16_t port, int type) const
{
    return ( hostname == this->hostname &&
            (socket && socket->getType() == type) &&
             port == this->port );
}

bool HTTPConnection::connect(const std::string &hostname, uint16_t port)
{
    if(!socket->connect(stream, hostname.c_str(), port))
        return false;

    this->hostname = hostname;
    this->port = port;

    return true;
}

bool HTTPConnection::connected() const
{
    return socket->connected();
}

void HTTPConnection::disconnect()
{
    queryOk = false;
    bytesRead = 0;
    contentLength = 0;
    bytesRange = BytesRange();
    socket->disconnect();
}

int HTTPConnection::query(const std::string &path, const BytesRange &range)
{
    queryOk = false;

    msg_Dbg(stream, "Retrieving ://%s:%u%s @%zu", hostname.c_str(), port, path.c_str(),
            range.isValid() ? range.getStartByte() : 0);

    if(!connected() && ( hostname.empty() || !connect(hostname, port) ))
        return VLC_EGENERIC;

    bytesRange = range;

    std::string header = buildRequestHeader(path);
    if(connectionClose)
        header.append("Connection: close\r\n");
    header.append("\r\n");

    if(!send( header ))
    {
        socket->disconnect();
        if(!connectionClose)
        {
            /* server closed connection pipeline after last req. need new */
            connectionClose = true;
            return query(path, range);
        }
        return VLC_EGENERIC;
    }

    int i_ret = parseReply();
    if(i_ret == VLC_SUCCESS)
    {
        queryOk = true;
    }
    else if(i_ret == VLC_EGENERIC)
    {
        socket->disconnect();
        if(!connectionClose)
        {
            connectionClose = true;
            return query(path, range);
        }
    }

    return i_ret;
}

ssize_t HTTPConnection::read(void *p_buffer, size_t len)
{
    if( !connected() ||
       (!queryOk && bytesRead == 0) )
        return VLC_EGENERIC;

    if(len == 0)
        return VLC_SUCCESS;

    queryOk = false;

    const size_t toRead = contentLength - bytesRead;

    if (toRead == 0)
        return VLC_SUCCESS;

    if(len > toRead)
        len = toRead;

    ssize_t ret = socket->read(stream, p_buffer, len);
    if(ret >= 0)
        bytesRead += ret;

    if(ret < 0 || (size_t)ret < len) /* set EOF */
    {
        socket->disconnect();
        return VLC_EGENERIC;
    }

    return ret;
}

bool HTTPConnection::send(const std::string &data)
{
    return send(data.c_str(), data.length());
}

bool HTTPConnection::send(const void *buf, size_t size)
{
    return socket->send(stream, buf, size);
}

int HTTPConnection::parseReply()
{
    std::string line = readLine();

    if(line.empty())
        return VLC_EGENERIC;

    if (line.compare(0, 9, "HTTP/1.1 ")!=0)
        return VLC_ENOOBJ;

    std::istringstream ss(line.substr(9));
    int replycode;
    ss >> replycode;
    if (replycode != 200 && replycode != 206)
        return VLC_ENOOBJ;

    line = readLine();

    while(!line.empty() && line.compare("\r\n"))
    {
        size_t split = line.find_first_of(':');
        size_t value = split + 1;

        while(line.at(value) == ' ')
            value++;

        onHeader(line.substr(0, split), line.substr(value));
        line = readLine();
    }

    return VLC_SUCCESS;
}

std::string HTTPConnection::readLine()
{
    return socket->readline(stream);
}

bool HTTPConnection::isAvailable() const
{
    return available;
}

void HTTPConnection::setUsed( bool b )
{
    available = !b;
    if(available)
    {
        if(!connectionClose && contentLength == bytesRead )
        {
            queryOk = false;
            bytesRead = 0;
            contentLength = 0;
            bytesRange = BytesRange();
        }
        else  /* We can't resend request if we haven't finished reading */
            disconnect();
    }
}

size_t HTTPConnection::getContentLength() const
{
    return contentLength;
}

void HTTPConnection::onHeader(const std::string &key,
                              const std::string &value)
{
    if(key == "Content-Length")
    {
        std::istringstream ss(value);
        size_t length;
        ss >> length;
        contentLength = length;
    }
    else if (key == "Connection" && value =="close")
    {
        connectionClose = true;
    }
}

std::string HTTPConnection::buildRequestHeader(const std::string &path) const
{
    std::stringstream req;
    req << "GET " << path << " HTTP/1.1\r\n" <<
           "Host: " << hostname << "\r\n" <<
           "Cache-Control: no-cache" << "\r\n" <<
           "User-Agent: " << std::string(psz_useragent) << "\r\n";
    req << extraRequestHeaders();
    return req.str();
}

std::string HTTPConnection::extraRequestHeaders() const
{
    std::stringstream ss;
    if(bytesRange.isValid())
    {
        ss << "Range: bytes=" << bytesRange.getStartByte() << "-";
        if(bytesRange.getEndByte())
            ss << bytesRange.getEndByte();
        ss << "\r\n";
    }
    return ss.str();
}
<commit_msg>demux: adaptative: compute contentlength from byterange<commit_after>/*
 * HTTPConnection.cpp
 *****************************************************************************
 * Copyright (C) 2014-2015 - VideoLAN and VLC Authors
 *
 * 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.
 *****************************************************************************/

#include "HTTPConnection.hpp"
#include "Sockets.hpp"
#include "../adaptative/tools/Helper.h"

#include <sstream>

using namespace adaptative::http;

HTTPConnection::HTTPConnection(vlc_object_t *stream_, Socket *socket_, bool persistent)
{
    socket = socket_;
    stream = stream_;
    psz_useragent = var_InheritString(stream, "http-user-agent");
    bytesRead = 0;
    contentLength = 0;
    queryOk = false;
    retries = 0;
    connectionClose = !persistent;
    port = 80;
    available = true;
}

HTTPConnection::~HTTPConnection()
{
    free(psz_useragent);
    delete socket;
}

bool HTTPConnection::compare(const std::string &hostname, uint16_t port, int type) const
{
    return ( hostname == this->hostname &&
            (socket && socket->getType() == type) &&
             port == this->port );
}

bool HTTPConnection::connect(const std::string &hostname, uint16_t port)
{
    if(!socket->connect(stream, hostname.c_str(), port))
        return false;

    this->hostname = hostname;
    this->port = port;

    return true;
}

bool HTTPConnection::connected() const
{
    return socket->connected();
}

void HTTPConnection::disconnect()
{
    queryOk = false;
    bytesRead = 0;
    contentLength = 0;
    bytesRange = BytesRange();
    socket->disconnect();
}

int HTTPConnection::query(const std::string &path, const BytesRange &range)
{
    queryOk = false;

    msg_Dbg(stream, "Retrieving ://%s:%u%s @%zu", hostname.c_str(), port, path.c_str(),
            range.isValid() ? range.getStartByte() : 0);

    if(!connected() && ( hostname.empty() || !connect(hostname, port) ))
        return VLC_EGENERIC;

    bytesRange = range;
    if(range.isValid() && range.getEndByte() > 0)
        contentLength = range.getEndByte() - range.getStartByte() + 1;

    std::string header = buildRequestHeader(path);
    if(connectionClose)
        header.append("Connection: close\r\n");
    header.append("\r\n");

    if(!send( header ))
    {
        socket->disconnect();
        if(!connectionClose)
        {
            /* server closed connection pipeline after last req. need new */
            connectionClose = true;
            return query(path, range);
        }
        return VLC_EGENERIC;
    }

    int i_ret = parseReply();
    if(i_ret == VLC_SUCCESS)
    {
        queryOk = true;
    }
    else if(i_ret == VLC_EGENERIC)
    {
        socket->disconnect();
        if(!connectionClose)
        {
            connectionClose = true;
            return query(path, range);
        }
    }

    return i_ret;
}

ssize_t HTTPConnection::read(void *p_buffer, size_t len)
{
    if( !connected() ||
       (!queryOk && bytesRead == 0) )
        return VLC_EGENERIC;

    if(len == 0)
        return VLC_SUCCESS;

    queryOk = false;

    const size_t toRead = contentLength - bytesRead;

    if (toRead == 0)
        return VLC_SUCCESS;

    if(len > toRead)
        len = toRead;

    ssize_t ret = socket->read(stream, p_buffer, len);
    if(ret >= 0)
        bytesRead += ret;

    if(ret < 0 || (size_t)ret < len) /* set EOF */
    {
        socket->disconnect();
        return VLC_EGENERIC;
    }

    return ret;
}

bool HTTPConnection::send(const std::string &data)
{
    return send(data.c_str(), data.length());
}

bool HTTPConnection::send(const void *buf, size_t size)
{
    return socket->send(stream, buf, size);
}

int HTTPConnection::parseReply()
{
    std::string line = readLine();

    if(line.empty())
        return VLC_EGENERIC;

    if (line.compare(0, 9, "HTTP/1.1 ")!=0)
        return VLC_ENOOBJ;

    std::istringstream ss(line.substr(9));
    int replycode;
    ss >> replycode;
    if (replycode != 200 && replycode != 206)
        return VLC_ENOOBJ;

    line = readLine();

    while(!line.empty() && line.compare("\r\n"))
    {
        size_t split = line.find_first_of(':');
        size_t value = split + 1;

        while(line.at(value) == ' ')
            value++;

        onHeader(line.substr(0, split), line.substr(value));
        line = readLine();
    }

    return VLC_SUCCESS;
}

std::string HTTPConnection::readLine()
{
    return socket->readline(stream);
}

bool HTTPConnection::isAvailable() const
{
    return available;
}

void HTTPConnection::setUsed( bool b )
{
    available = !b;
    if(available)
    {
        if(!connectionClose && contentLength == bytesRead )
        {
            queryOk = false;
            bytesRead = 0;
            contentLength = 0;
            bytesRange = BytesRange();
        }
        else  /* We can't resend request if we haven't finished reading */
            disconnect();
    }
}

size_t HTTPConnection::getContentLength() const
{
    return contentLength;
}

void HTTPConnection::onHeader(const std::string &key,
                              const std::string &value)
{
    if(key == "Content-Length")
    {
        std::istringstream ss(value);
        size_t length;
        ss >> length;
        contentLength = length;
    }
    else if (key == "Connection" && value =="close")
    {
        connectionClose = true;
    }
}

std::string HTTPConnection::buildRequestHeader(const std::string &path) const
{
    std::stringstream req;
    req << "GET " << path << " HTTP/1.1\r\n" <<
           "Host: " << hostname << "\r\n" <<
           "Cache-Control: no-cache" << "\r\n" <<
           "User-Agent: " << std::string(psz_useragent) << "\r\n";
    req << extraRequestHeaders();
    return req.str();
}

std::string HTTPConnection::extraRequestHeaders() const
{
    std::stringstream ss;
    if(bytesRange.isValid())
    {
        ss << "Range: bytes=" << bytesRange.getStartByte() << "-";
        if(bytesRange.getEndByte())
            ss << bytesRange.getEndByte();
        ss << "\r\n";
    }
    return ss.str();
}
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>

#include <Poco/String.h>

#include "rest/PocoContext.h"

using namespace std;
using namespace Poco;
using namespace Poco::Net;
using namespace BeeeOn;

PocoRequest::PocoRequest(HTTPServerRequest &impl):
	PocoContext<HTTPServerRequest>(impl)
{
}

istream &PocoRequest::stream() const
{
	return m_impl.stream();
}

bool PocoRequest::accepts(const string &type, const string &subtype) const
{
	if (!m_impl.has("Accept"))
		return true;

	const string fulltype(type + "/" + subtype);

	vector<string> elements;
	MessageHeader::splitElements(m_impl["Accept"], elements);

	for (const string &element : elements) {
		string value;
		NameValueCollection params;
		MessageHeader::splitParameters(element, value, params);

		if (icompare(value, fulltype) == 0)
			return true;
		else if(icompare(value, type + "/*") == 0)
			return true;
		else if (value == "*/*")
			return true;
	}

	return false;
}

PocoResponse::PocoResponse(HTTPServerResponse &impl):
	PocoContext<HTTPServerResponse>(impl)
{
}

PocoHeaderAccessor<HTTPServerResponse> PocoResponse::at(const string &key)
{
	return PocoHeaderAccessor<HTTPServerResponse>(m_impl, key);
}

void PocoResponse::setStatus(unsigned int status)
{
	m_impl.setStatusAndReason((HTTPResponse::HTTPStatus) status);
}

unsigned int PocoResponse::status() const
{
	return m_impl.getStatus();
}

void PocoResponse::sendAll(const void *p, std::size_t len)
{
	m_impl.sendBuffer(p, len);
}

ostream &PocoResponse::stream()
{
	return m_impl.send();
}
<commit_msg>PocoContext: serialize doubles with fixed precision<commit_after>#include <iostream>
#include <vector>

#include <Poco/String.h>

#include "rest/PocoContext.h"

using namespace std;
using namespace Poco;
using namespace Poco::Net;
using namespace BeeeOn;

PocoRequest::PocoRequest(HTTPServerRequest &impl):
	PocoContext<HTTPServerRequest>(impl)
{
}

istream &PocoRequest::stream() const
{
	return m_impl.stream();
}

bool PocoRequest::accepts(const string &type, const string &subtype) const
{
	if (!m_impl.has("Accept"))
		return true;

	const string fulltype(type + "/" + subtype);

	vector<string> elements;
	MessageHeader::splitElements(m_impl["Accept"], elements);

	for (const string &element : elements) {
		string value;
		NameValueCollection params;
		MessageHeader::splitParameters(element, value, params);

		if (icompare(value, fulltype) == 0)
			return true;
		else if(icompare(value, type + "/*") == 0)
			return true;
		else if (value == "*/*")
			return true;
	}

	return false;
}

PocoResponse::PocoResponse(HTTPServerResponse &impl):
	PocoContext<HTTPServerResponse>(impl)
{
}

PocoHeaderAccessor<HTTPServerResponse> PocoResponse::at(const string &key)
{
	return PocoHeaderAccessor<HTTPServerResponse>(m_impl, key);
}

void PocoResponse::setStatus(unsigned int status)
{
	m_impl.setStatusAndReason((HTTPResponse::HTTPStatus) status);
}

unsigned int PocoResponse::status() const
{
	return m_impl.getStatus();
}

void PocoResponse::sendAll(const void *p, std::size_t len)
{
	m_impl.sendBuffer(p, len);
}

ostream &PocoResponse::stream()
{
	ostream &out = m_impl.send();
	out.setf(ios::fixed);
	return out;
}
<|endoftext|>


<commit_before>/*
    sybase.cpp

    Sybase DB layer for QORE
    uses Sybase OpenClient C library

    Qore Programming language

    Copyright (C) 2003 - 2018 Qore Technologies, s.r.o.

    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 <ctpublic.h>
#include <assert.h>
#include <ctype.h>
#include <memory>
#include <string>
#include <vector>

#include "sybase.h"
#include "connection.h"
#include "encoding_helpers.h"

#include "minitest.hpp"

#ifdef SYBASE
DLLEXPORT char qore_module_name[] = "sybase";
DLLEXPORT char qore_module_description[] = "Sybase database driver";
#else
DLLEXPORT char qore_module_name[] = "freetds";
DLLEXPORT char qore_module_description[] = "FreeTDS-based database driver for MS-SQL Server and Sybase";
#endif
DLLEXPORT char qore_module_version[] = PACKAGE_VERSION;
DLLEXPORT char qore_module_author[] = "Qore Technologies";
DLLEXPORT char qore_module_url[] = "http://qore.org";
DLLEXPORT int qore_module_api_major = QORE_MODULE_API_MAJOR;
DLLEXPORT int qore_module_api_minor = QORE_MODULE_API_MINOR;
DLLEXPORT qore_module_init_t qore_module_init = sybase_module_init;
DLLEXPORT qore_module_ns_init_t qore_module_ns_init = sybase_module_ns_init;
DLLEXPORT qore_module_delete_t qore_module_delete = sybase_module_delete;
DLLEXPORT qore_license_t qore_module_license = QL_MIT;
DLLEXPORT char qore_module_license_str[] = "MIT";
static DBIDriver* DBID_SYBASE;

// capabilities of this driver
int DBI_SYBASE_CAPS =
   DBI_CAP_TRANSACTION_MANAGEMENT
   | DBI_CAP_CHARSET_SUPPORT
   | DBI_CAP_LOB_SUPPORT
   | DBI_CAP_STORED_PROCEDURES
   | DBI_CAP_BIND_BY_VALUE
   | DBI_CAP_BIND_BY_PLACEHOLDER
   | DBI_CAP_HAS_NUMBER_SUPPORT
   | DBI_CAP_AUTORECONNECT
   | DBI_CAP_HAS_EXECRAW
   | DBI_CAP_TIME_ZONE_SUPPORT
   | DBI_CAP_SERVER_TIME_ZONE
   ;

#define BEGIN_CALLBACK \
       do { \
           try { do {} while(0)

#define END_CALLBACK(RV) \
           } catch (const ss::Error &e) { \
               e.raise(xsink); \
               return RV; \
           }\
      } while(0)

/*
#ifdef DEBUG
// exported
AbstractQoreNode* runSybaseTests(const QoreListNode *params, ExceptionSink *xsink) {
   minitest::result res = minitest::execute_all_tests();
   if (res.all_tests_succeeded) {
      printf("************************************************\n");
      printf("Sybase module: %d tests succeeded\n", res.sucessful_tests_count);
      printf("************************************************\n");
      return 0;
   }

   xsink->raiseException("SYBASE-TEST-FAILURE", "Sybase test in file %s, line %d threw an exception.",
			 res.failed_test_file, res.failed_test_line);
   return 0;
}

AbstractQoreNode* runRecentSybaseTests(const QoreListNode *params, ExceptionSink *xsink) {
   minitest::result res = minitest::test_last_changed_files(1);
   if (res.all_tests_succeeded) {
      printf("************************************************\n");
      printf("Sybase module: %d recent tests succeeded\n", res.sucessful_tests_count);
      printf("************************************************\n");
      return 0;
   }

   xsink->raiseException("SYBASE-TEST-FAILURE", "Sybase test in file %s, line %d threw an exception.",
			 res.failed_test_file, res.failed_test_line);
   return 0;
}
#endif
*/

static int sybase_open(Datasource *ds, ExceptionSink *xsink) {
    BEGIN_CALLBACK;
    // username is a required parameter
    if (!ds->getUsername()) {
        xsink->raiseException("DATASOURCE-MISSING-USERNAME", "Datasource has an empty username parameter");
        return -1;
    }

    // DB name is a required parameter
    if (!ds->getDBName()) {
        xsink->raiseException("DATASOURCE-MISSING-DBNAME", "Datasource has an empty dbname parameter");
        return -1;
    }

    // set the encoding for the connection
    if (ds->getDBEncoding()) {
        const QoreEncoding *enc = name_to_QoreEncoding(ds->getDBEncoding());
        ds->setQoreEncoding(enc);
    }
    else {
        const char *enc = QoreEncoding_to_SybaseName(QCS_DEFAULT);
        // if the encoding cannot be mapped, throw a Qore-language exception and return
        if (!enc) {
            xsink->raiseException("TDS-UNKNOWN-CHARACTER-SET", "cannot find the Sybase character encoding equivalent for '%s'", QCS_DEFAULT->getCode());
            return -1;
        }
        ds->setDBEncoding(enc);
        ds->setQoreEncoding(QCS_DEFAULT);
    }

    // create the connection object
    std::unique_ptr<connection> sc(new connection(ds, xsink));
    if (*xsink)
        return -1;

    int port = ds->getPort();

    if (port && !ds->getHostName()) {
        xsink->raiseException("TDS-CONNECT-ERROR", "port is set to %d, but no hostname is set; both hostname and port must be set to override the interfaces file", port);
        return -1;
    }

    if (!port && ds->getHostName()) {
        xsink->raiseException("TDS-CONNECT-ERROR", "hostname is set to '%s', but no port is set; both hostname and port must be set to override the interfaces file", ds->getHostName());
        return -1;
    }

    // make the actual connection to the database
    sc->init(ds->getUsername(), ds->getPassword() ? ds->getPassword() : "", ds->getDBName(), ds->getDBEncoding(), ds->getQoreEncoding(), ds->getHostName(), port, xsink);
    // return with an error if it didn't work
    if (*xsink)
        return -1;

    // set the private data
    ds->setPrivateData(sc.release());

    // return 0 for OK
    return 0;
    END_CALLBACK(-1);
}

static int sybase_close(Datasource *ds) {
    try {
        connection* sc = (connection*)ds->getPrivateData();
        ds->setPrivateData(0);
        delete sc;
    } catch (const ss::Error &e) {}
    return 0;
}

static QoreValue sybase_select(Datasource *ds, const QoreString *qstr, const QoreListNode *args, ExceptionSink *xsink) {
    BEGIN_CALLBACK;
    connection *conn = (connection*)ds->getPrivateData();
    return conn->select(qstr, args, xsink);
    END_CALLBACK(0);
}

static QoreHashNode* sybase_select_row(Datasource *ds, const QoreString *qstr, const QoreListNode *args, ExceptionSink *xsink) {
   BEGIN_CALLBACK;
   connection *conn = (connection*)ds->getPrivateData();
   ValueHolder holder(conn->exec_row(qstr, args, xsink), xsink);
   qore_type_t nt = holder->getType();
   if (nt != NT_HASH && nt != NT_NOTHING) {
      if (!*xsink)
         xsink->raiseException("DBI-SELECT-ROW-ERROR", "selectRow() returned type '%s'; expecting a hash for a single row", holder->getTypeName());
      holder.release().discard(xsink);
   }
   return holder ? holder.release().get<QoreHashNode>() : nullptr;
   END_CALLBACK(0);
}

static QoreValue sybase_select_rows(Datasource *ds, const QoreString *qstr, const QoreListNode *args, ExceptionSink *xsink) {
    BEGIN_CALLBACK;
    connection *conn = (connection*)ds->getPrivateData();
    QoreValue rv = conn->exec_rows(qstr, args, xsink);
    if (rv.getType() == NT_HASH) {
        QoreListNode* l = new QoreListNode(autoTypeInfo);
        l->push(rv, xsink);
        rv = l;
    }
    return rv;
    //return conn->exec_rows(qstr, args, xsink);
    END_CALLBACK(0);
}

static QoreValue sybase_exec(Datasource *ds, const QoreString *qstr, const QoreListNode *args, ExceptionSink *xsink) {
    BEGIN_CALLBACK;
    connection *conn = (connection*)ds->getPrivateData();
    QoreValue rv = conn->exec(qstr, args, xsink);
    if (!rv) {
        rv = 0;
    }
    return rv;
    END_CALLBACK(0);
}

static QoreValue sybase_execRaw(Datasource *ds, const QoreString *qstr, ExceptionSink *xsink) {
    BEGIN_CALLBACK;
    connection *conn = (connection*)ds->getPrivateData();
    QoreValue rv = conn->execRaw(qstr, xsink);
    if (!rv) {
        rv = 0;
    }
    return rv;
    END_CALLBACK(0);
}

static int sybase_commit(Datasource *ds, ExceptionSink *xsink) {
   BEGIN_CALLBACK;
   connection* conn = (connection*)ds->getPrivateData();
   return conn->commit(xsink);
   END_CALLBACK(0);
}

static int sybase_rollback(Datasource *ds, ExceptionSink *xsink) {
   BEGIN_CALLBACK;
   connection* conn = (connection*)ds->getPrivateData();
   return conn->rollback(xsink);
   END_CALLBACK(0);
}

static QoreValue sybase_get_client_version(const Datasource *ds, ExceptionSink *xsink) {
    BEGIN_CALLBACK;
    context m_context(xsink);
    if (!m_context)
        return QoreValue();

    return m_context.get_client_version(xsink);
    END_CALLBACK(0);
}

static QoreValue sybase_get_server_version(Datasource *ds, ExceptionSink *xsink) {
    BEGIN_CALLBACK;
    connection* conn = (connection*)ds->getPrivateData();
    return conn->get_server_version(xsink);
    END_CALLBACK(0);
}

static int sybase_opt_set(Datasource* ds, const char* opt, const QoreValue val, ExceptionSink* xsink) {
    BEGIN_CALLBACK;
    connection *conn = (connection*)ds->getPrivateData();
    return conn->setOption(opt, val, xsink);
    END_CALLBACK(0);
}

static QoreValue sybase_opt_get(const Datasource* ds, const char* opt) {
    try {
        connection *conn = (connection*)ds->getPrivateData();
        return conn->getOption(opt).takeNode();
    } catch (const ss::Error &e) {
        return QoreValue();
    }
}

namespace ss {
    void init(qore_dbi_method_list &methods);
}

QoreStringNode *sybase_module_init() {
   QORE_TRACE("sybase_module_init()");

   // init_namespace();

/*
#ifdef DEBUG
   builtinFunctions.add("runSybaseTests", runSybaseTests, QDOM_DATABASE);
   builtinFunctions.add("runRecentSybaseTests", runRecentSybaseTests, QDOM_DATABASE);
#endif
*/

   // register driver with DBI subsystem
   qore_dbi_method_list methods;
   methods.add(QDBI_METHOD_OPEN, sybase_open);
   methods.add(QDBI_METHOD_CLOSE, sybase_close);
   methods.add(QDBI_METHOD_SELECT, sybase_select);
   methods.add(QDBI_METHOD_SELECT_ROW, sybase_select_row);
   methods.add(QDBI_METHOD_SELECT_ROWS, sybase_select_rows);
   methods.add(QDBI_METHOD_EXEC, sybase_exec);
   methods.add(QDBI_METHOD_EXECRAW, sybase_execRaw);
   methods.add(QDBI_METHOD_COMMIT, sybase_commit);
   methods.add(QDBI_METHOD_ROLLBACK, sybase_rollback);
   methods.add(QDBI_METHOD_GET_CLIENT_VERSION, sybase_get_client_version);
   methods.add(QDBI_METHOD_GET_SERVER_VERSION, sybase_get_server_version);

   methods.add(QDBI_METHOD_OPT_SET, sybase_opt_set);
   methods.add(QDBI_METHOD_OPT_GET, sybase_opt_get);

   methods.registerOption(DBI_OPT_NUMBER_OPT, "when set, numeric/decimal values are returned as integers if possible, otherwise as arbitrary-precision number values; the argument is ignored; setting this option turns it on and turns off 'string-numbers' and 'numeric-numbers'");
   methods.registerOption(DBI_OPT_NUMBER_STRING, "when set, numeric/decimal values are returned as strings for backwards-compatibility; the argument is ignored; setting this option turns it on and turns off 'optimal-numbers' and 'numeric-numbers'");
   methods.registerOption(DBI_OPT_NUMBER_NUMERIC, "when set, numeric/decimal values are returned as arbitrary-precision number values; the argument is ignored; setting this option turns it on and turns off 'string-numbers' and 'optimal-numbers'");
   methods.registerOption(DBI_OPT_TIMEZONE, "set the server-side timezone,"
           " value must be a string in the format accepted by"
           " Timezone::constructor() on the client (ie either a region"
           " name or a UTC offset like \"+01:00\"), if not set the"
           " server's time zone will be assumed to be the same as"
           " the client's", stringTypeInfo);

   ss::init(methods);

#ifdef SYBASE
   DBID_SYBASE = DBI.registerDriver("sybase", methods, DBI_SYBASE_CAPS);
#else
   DBID_SYBASE = DBI.registerDriver("freetds", methods, DBI_SYBASE_CAPS);
#endif

   return 0;
}

void sybase_module_ns_init(QoreNamespace *rns, QoreNamespace *qns) {
}

void sybase_module_delete() {
   QORE_TRACE("sybase_module_delete()");
}
<commit_msg>refs qorelanguagw/qore#1573 QoreValue API updates<commit_after>/*
    sybase.cpp

    Sybase DB layer for QORE
    uses Sybase OpenClient C library

    Qore Programming language

    Copyright (C) 2003 - 2018 Qore Technologies, s.r.o.

    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 <ctpublic.h>
#include <assert.h>
#include <ctype.h>
#include <memory>
#include <string>
#include <vector>

#include "sybase.h"
#include "connection.h"
#include "encoding_helpers.h"

#include "minitest.hpp"

#ifdef SYBASE
DLLEXPORT char qore_module_name[] = "sybase";
DLLEXPORT char qore_module_description[] = "Sybase database driver";
#else
DLLEXPORT char qore_module_name[] = "freetds";
DLLEXPORT char qore_module_description[] = "FreeTDS-based database driver for MS-SQL Server and Sybase";
#endif
DLLEXPORT char qore_module_version[] = PACKAGE_VERSION;
DLLEXPORT char qore_module_author[] = "Qore Technologies";
DLLEXPORT char qore_module_url[] = "http://qore.org";
DLLEXPORT int qore_module_api_major = QORE_MODULE_API_MAJOR;
DLLEXPORT int qore_module_api_minor = QORE_MODULE_API_MINOR;
DLLEXPORT qore_module_init_t qore_module_init = sybase_module_init;
DLLEXPORT qore_module_ns_init_t qore_module_ns_init = sybase_module_ns_init;
DLLEXPORT qore_module_delete_t qore_module_delete = sybase_module_delete;
DLLEXPORT qore_license_t qore_module_license = QL_MIT;
DLLEXPORT char qore_module_license_str[] = "MIT";
static DBIDriver* DBID_SYBASE;

// capabilities of this driver
int DBI_SYBASE_CAPS =
   DBI_CAP_TRANSACTION_MANAGEMENT
   | DBI_CAP_CHARSET_SUPPORT
   | DBI_CAP_LOB_SUPPORT
   | DBI_CAP_STORED_PROCEDURES
   | DBI_CAP_BIND_BY_VALUE
   | DBI_CAP_BIND_BY_PLACEHOLDER
   | DBI_CAP_HAS_NUMBER_SUPPORT
   | DBI_CAP_AUTORECONNECT
   | DBI_CAP_HAS_EXECRAW
   | DBI_CAP_TIME_ZONE_SUPPORT
   | DBI_CAP_SERVER_TIME_ZONE
   ;

#define BEGIN_CALLBACK \
       do { \
           try { do {} while(0)

#define END_CALLBACK(RV) \
           } catch (const ss::Error &e) { \
               e.raise(xsink); \
               return RV; \
           }\
      } while(0)

/*
#ifdef DEBUG
// exported
AbstractQoreNode* runSybaseTests(const QoreListNode *params, ExceptionSink *xsink) {
   minitest::result res = minitest::execute_all_tests();
   if (res.all_tests_succeeded) {
      printf("************************************************\n");
      printf("Sybase module: %d tests succeeded\n", res.sucessful_tests_count);
      printf("************************************************\n");
      return 0;
   }

   xsink->raiseException("SYBASE-TEST-FAILURE", "Sybase test in file %s, line %d threw an exception.",
			 res.failed_test_file, res.failed_test_line);
   return 0;
}

AbstractQoreNode* runRecentSybaseTests(const QoreListNode *params, ExceptionSink *xsink) {
   minitest::result res = minitest::test_last_changed_files(1);
   if (res.all_tests_succeeded) {
      printf("************************************************\n");
      printf("Sybase module: %d recent tests succeeded\n", res.sucessful_tests_count);
      printf("************************************************\n");
      return 0;
   }

   xsink->raiseException("SYBASE-TEST-FAILURE", "Sybase test in file %s, line %d threw an exception.",
			 res.failed_test_file, res.failed_test_line);
   return 0;
}
#endif
*/

static int sybase_open(Datasource *ds, ExceptionSink *xsink) {
    BEGIN_CALLBACK;
    // username is a required parameter
    if (!ds->getUsername()) {
        xsink->raiseException("DATASOURCE-MISSING-USERNAME", "Datasource has an empty username parameter");
        return -1;
    }

    // DB name is a required parameter
    if (!ds->getDBName()) {
        xsink->raiseException("DATASOURCE-MISSING-DBNAME", "Datasource has an empty dbname parameter");
        return -1;
    }

    // set the encoding for the connection
    if (ds->getDBEncoding()) {
        const QoreEncoding *enc = name_to_QoreEncoding(ds->getDBEncoding());
        ds->setQoreEncoding(enc);
    }
    else {
        const char *enc = QoreEncoding_to_SybaseName(QCS_DEFAULT);
        // if the encoding cannot be mapped, throw a Qore-language exception and return
        if (!enc) {
            xsink->raiseException("TDS-UNKNOWN-CHARACTER-SET", "cannot find the Sybase character encoding equivalent for '%s'", QCS_DEFAULT->getCode());
            return -1;
        }
        ds->setDBEncoding(enc);
        ds->setQoreEncoding(QCS_DEFAULT);
    }

    // create the connection object
    std::unique_ptr<connection> sc(new connection(ds, xsink));
    if (*xsink)
        return -1;

    int port = ds->getPort();

    if (port && !ds->getHostName()) {
        xsink->raiseException("TDS-CONNECT-ERROR", "port is set to %d, but no hostname is set; both hostname and port must be set to override the interfaces file", port);
        return -1;
    }

    if (!port && ds->getHostName()) {
        xsink->raiseException("TDS-CONNECT-ERROR", "hostname is set to '%s', but no port is set; both hostname and port must be set to override the interfaces file", ds->getHostName());
        return -1;
    }

    // make the actual connection to the database
    sc->init(ds->getUsername(), ds->getPassword() ? ds->getPassword() : "", ds->getDBName(), ds->getDBEncoding(), ds->getQoreEncoding(), ds->getHostName(), port, xsink);
    // return with an error if it didn't work
    if (*xsink)
        return -1;

    // set the private data
    ds->setPrivateData(sc.release());

    // return 0 for OK
    return 0;
    END_CALLBACK(-1);
}

static int sybase_close(Datasource *ds) {
    try {
        connection* sc = (connection*)ds->getPrivateData();
        ds->setPrivateData(0);
        delete sc;
    } catch (const ss::Error &e) {}
    return 0;
}

static QoreValue sybase_select(Datasource *ds, const QoreString *qstr, const QoreListNode *args, ExceptionSink *xsink) {
    BEGIN_CALLBACK;
    connection *conn = (connection*)ds->getPrivateData();
    return conn->select(qstr, args, xsink);
    END_CALLBACK(0);
}

static QoreHashNode* sybase_select_row(Datasource *ds, const QoreString *qstr, const QoreListNode *args, ExceptionSink *xsink) {
   BEGIN_CALLBACK;
   connection *conn = (connection*)ds->getPrivateData();
   ValueHolder holder(conn->exec_row(qstr, args, xsink), xsink);
   qore_type_t nt = holder->getType();
   if (nt != NT_HASH && nt != NT_NOTHING) {
      if (!*xsink)
         xsink->raiseException("DBI-SELECT-ROW-ERROR", "selectRow() returned type '%s'; expecting a hash for a single row", holder->getTypeName());
      holder.release().discard(xsink);
   }
   return holder ? holder.release().get<QoreHashNode>() : nullptr;
   END_CALLBACK(0);
}

static QoreValue sybase_select_rows(Datasource *ds, const QoreString *qstr, const QoreListNode *args, ExceptionSink *xsink) {
    BEGIN_CALLBACK;
    connection *conn = (connection*)ds->getPrivateData();
    QoreValue rv = conn->exec_rows(qstr, args, xsink);
    if (rv.getType() == NT_HASH) {
        QoreListNode* l = new QoreListNode(autoTypeInfo);
        l->push(rv, xsink);
        rv = l;
    }
    return rv;
    //return conn->exec_rows(qstr, args, xsink);
    END_CALLBACK(0);
}

static QoreValue sybase_exec(Datasource *ds, const QoreString *qstr, const QoreListNode *args, ExceptionSink *xsink) {
    BEGIN_CALLBACK;
    connection *conn = (connection*)ds->getPrivateData();
    QoreValue rv = conn->exec(qstr, args, xsink);
    if (!rv) {
        rv = 0;
    }
    return rv;
    END_CALLBACK(0);
}

static QoreValue sybase_execRaw(Datasource *ds, const QoreString *qstr, ExceptionSink *xsink) {
    BEGIN_CALLBACK;
    connection *conn = (connection*)ds->getPrivateData();
    QoreValue rv = conn->execRaw(qstr, xsink);
    if (!rv) {
        rv = 0;
    }
    return rv;
    END_CALLBACK(0);
}

static int sybase_commit(Datasource *ds, ExceptionSink *xsink) {
   BEGIN_CALLBACK;
   connection* conn = (connection*)ds->getPrivateData();
   return conn->commit(xsink);
   END_CALLBACK(0);
}

static int sybase_rollback(Datasource *ds, ExceptionSink *xsink) {
   BEGIN_CALLBACK;
   connection* conn = (connection*)ds->getPrivateData();
   return conn->rollback(xsink);
   END_CALLBACK(0);
}

static QoreValue sybase_get_client_version(const Datasource *ds, ExceptionSink *xsink) {
    BEGIN_CALLBACK;
    context m_context(xsink);
    if (!m_context)
        return QoreValue();

    return m_context.get_client_version(xsink);
    END_CALLBACK(0);
}

static QoreValue sybase_get_server_version(Datasource *ds, ExceptionSink *xsink) {
    BEGIN_CALLBACK;
    connection* conn = (connection*)ds->getPrivateData();
    return conn->get_server_version(xsink);
    END_CALLBACK(0);
}

static int sybase_opt_set(Datasource* ds, const char* opt, const QoreValue val, ExceptionSink* xsink) {
    BEGIN_CALLBACK;
    connection *conn = (connection*)ds->getPrivateData();
    return conn->setOption(opt, val, xsink);
    END_CALLBACK(0);
}

static QoreValue sybase_opt_get(const Datasource* ds, const char* opt) {
    try {
        connection *conn = (connection*)ds->getPrivateData();
        return conn->getOption(opt);
    } catch (const ss::Error &e) {
        return QoreValue();
    }
}

namespace ss {
    void init(qore_dbi_method_list &methods);
}

QoreStringNode *sybase_module_init() {
   QORE_TRACE("sybase_module_init()");

   // init_namespace();

/*
#ifdef DEBUG
   builtinFunctions.add("runSybaseTests", runSybaseTests, QDOM_DATABASE);
   builtinFunctions.add("runRecentSybaseTests", runRecentSybaseTests, QDOM_DATABASE);
#endif
*/

   // register driver with DBI subsystem
   qore_dbi_method_list methods;
   methods.add(QDBI_METHOD_OPEN, sybase_open);
   methods.add(QDBI_METHOD_CLOSE, sybase_close);
   methods.add(QDBI_METHOD_SELECT, sybase_select);
   methods.add(QDBI_METHOD_SELECT_ROW, sybase_select_row);
   methods.add(QDBI_METHOD_SELECT_ROWS, sybase_select_rows);
   methods.add(QDBI_METHOD_EXEC, sybase_exec);
   methods.add(QDBI_METHOD_EXECRAW, sybase_execRaw);
   methods.add(QDBI_METHOD_COMMIT, sybase_commit);
   methods.add(QDBI_METHOD_ROLLBACK, sybase_rollback);
   methods.add(QDBI_METHOD_GET_CLIENT_VERSION, sybase_get_client_version);
   methods.add(QDBI_METHOD_GET_SERVER_VERSION, sybase_get_server_version);

   methods.add(QDBI_METHOD_OPT_SET, sybase_opt_set);
   methods.add(QDBI_METHOD_OPT_GET, sybase_opt_get);

   methods.registerOption(DBI_OPT_NUMBER_OPT, "when set, numeric/decimal values are returned as integers if possible, otherwise as arbitrary-precision number values; the argument is ignored; setting this option turns it on and turns off 'string-numbers' and 'numeric-numbers'");
   methods.registerOption(DBI_OPT_NUMBER_STRING, "when set, numeric/decimal values are returned as strings for backwards-compatibility; the argument is ignored; setting this option turns it on and turns off 'optimal-numbers' and 'numeric-numbers'");
   methods.registerOption(DBI_OPT_NUMBER_NUMERIC, "when set, numeric/decimal values are returned as arbitrary-precision number values; the argument is ignored; setting this option turns it on and turns off 'string-numbers' and 'optimal-numbers'");
   methods.registerOption(DBI_OPT_TIMEZONE, "set the server-side timezone,"
           " value must be a string in the format accepted by"
           " Timezone::constructor() on the client (ie either a region"
           " name or a UTC offset like \"+01:00\"), if not set the"
           " server's time zone will be assumed to be the same as"
           " the client's", stringTypeInfo);

   ss::init(methods);

#ifdef SYBASE
   DBID_SYBASE = DBI.registerDriver("sybase", methods, DBI_SYBASE_CAPS);
#else
   DBID_SYBASE = DBI.registerDriver("freetds", methods, DBI_SYBASE_CAPS);
#endif

   return 0;
}

void sybase_module_ns_init(QoreNamespace *rns, QoreNamespace *qns) {
}

void sybase_module_delete() {
   QORE_TRACE("sybase_module_delete()");
}
<|endoftext|>


<commit_before>/*
 * This file is part of btag.
 *
 * © 2010-2011 Fernando Tarlá Cardoso Lemos
 *
 * Refer to the LICENSE file for licensing information.
 *
 */

#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/optional.hpp>
#include <taglib/fileref.h>
#include <taglib/tag.h>
#include <cassert>
#include <cstdlib>
#include <exception>

#include "InteractiveTagger.h"
#include "validators.h"
#include "wide_string_cast.h"

namespace fs = boost::filesystem;

InteractiveTagger::InteractiveTagger()
    : m_input_filter(NULL), m_output_filter(NULL), m_dry_run(false)
{
    // Load the extensions supported by TagLib
    TagLib::StringList extensions = TagLib::FileRef::defaultFileExtensions();
    for (TagLib::StringList::ConstIterator it = extensions.begin(); it != extensions.end(); ++it)
        m_supported_extensions.push_back(L'.' + it->toWString());
}

void InteractiveTagger::set_file_rename_format(const std::string &format)
{
    m_file_rename_format = boost::lexical_cast<std::wstring>(format);
}

void InteractiveTagger::set_dir_rename_format(const std::string &format)
{
    m_dir_rename_format = boost::lexical_cast<std::wstring>(format);
}

void InteractiveTagger::tag(int num_paths, const char **paths)
{
    assert(m_terminal);

    // Build a list with the normalized paths
    std::list<fs::path> path_list;
    for (int i = 0; i < num_paths; ++i) {
        char *real_path = realpath(paths[i], NULL);
        if (!real_path) {
            std::string errstr("\"");
            errstr += paths[i];
            errstr += "\" is not a valid path";
            m_terminal->display_warning_message(errstr);
            continue;
        }
        path_list.push_back(fs::path(boost::lexical_cast<std::wstring>(std::string(real_path))));
        free(real_path);
    }

    // Sort it and tag the paths
    path_list.sort();
    BOOST_FOREACH(const fs::path &path, path_list) {
        // Check if the path exists
        if (!fs::exists(path)) {
            m_terminal->display_warning_message(L"Path \"" + path.string<std::wstring>()
                    + L"\" not found, skipping...");
            continue;
        }

        try {
            // If it's a regular file, just tag it
            if (fs::is_regular_file(path)) {
                if (!is_supported_extension(path)) {
                    m_terminal->display_warning_message(L"Path \"" + path.string<std::wstring>()
                            + L"\" has no supported extension, skipping...");
                    continue;
                }
                tag_file(path);
            }

            // If it's a directory, tag its contents
            else if (fs::is_directory(path)) {
                tag_directory(path);
            }

            // It's none of the above, do something about it
            else {
                m_terminal->display_warning_message(L"Path \"" + path.string<std::wstring>()
                        + L"\" is not a regular file or directory, skipping...");
            }
        }
        catch (std::exception &e) {
            m_terminal->display_warning_message(e.what());
        }
    }

    // Save the unsaved files
    if (!m_unsaved_files.empty()
            && (m_dry_run || m_terminal->ask_yes_no_question(L"=== OK to save the changes to the files?"))) {
        if (m_dry_run)
            m_terminal->display_info_message("=== Not saving changes (dry run mode)");
        BOOST_FOREACH(TagLib::FileRef &f, m_unsaved_files) {
            std::string message(m_dry_run ? "Not saving " : "Saving");
            message += " \"" + std::string(f.file()->name()) + '\"';
            m_terminal->display_info_message(message);
            if (!m_dry_run && !f.save())
                m_terminal->display_warning_message("Unable to save " + std::string(f.file()->name()) + "\"");
        }
    }

    // Perform the pending renames
    if (!m_pending_renames.empty()
            && (m_dry_run || m_terminal->ask_yes_no_question(L"=== OK to rename the files?"))) {
        m_terminal->display_info_message("=== Not renaming files (dry run mode)");
        std::list<std::pair<fs::path, fs::path> >::const_iterator it;
        for (it = m_pending_renames.begin(); it != m_pending_renames.end(); ++it) {
            const fs::path &from((*it).first);
            const fs::path &to((*it).second);
            m_terminal->display_info_message(from.string());
            m_terminal->display_info_message(L"-> " + to.string<std::wstring>());
            if (!m_dry_run) {
                try { fs::rename(from, to); }
                catch (std::exception &e) { m_terminal->display_warning_message(e.what()); }
            }
        }
    }

    m_terminal->display_info_message("=== All done!");
}

bool InteractiveTagger::is_supported_extension(const fs::path &path)
{
    std::wstring extension(path.extension().string<std::wstring>());
    boost::to_lower(extension);

    BOOST_FOREACH(const std::wstring &supported_extension, m_supported_extensions) {
        if (extension == supported_extension)
            return true;
    }

    return false;
}

std::wstring InteractiveTagger::replace_tokens(const std::wstring &str,
        const std::map<std::wstring, std::wstring> &replacements)
{
    std::wstring res;
    res.reserve(str.size() * 3);

    bool parsing_token = false;
    std::wstring current_token;
    BOOST_FOREACH(char c, str) {
        if (c == '%') {
            if (parsing_token) {
                std::map<std::wstring, std::wstring>::const_iterator it = replacements.find(current_token);
                res += it == replacements.end() ? current_token : it->second;
                current_token.erase();
            }
            parsing_token = true;
        }
        else if (parsing_token) {
            if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
                current_token += c;
            }
            else {
                std::map<std::wstring, std::wstring>::const_iterator it = replacements.find(current_token);
                res += it == replacements.end() ? current_token : it->second;
                res += c;
                parsing_token = false;
                current_token.erase();
            }
        }
        else {
            res += c;
        }
    }
    if (parsing_token) {
        std::map<std::wstring, std::wstring>::const_iterator it = replacements.find(current_token);
        res += it == replacements.end() ? current_token : it->second;
    }

    return res;
}

void InteractiveTagger::tag_file(const fs::path &path, ConfirmationHandler &artist_confirmation,
       ConfirmationHandler &album_confirmation, int *year, int track)
{
    m_terminal->display_info_message(L"=== Tagging \"" + path.filename().string<std::wstring>() + L"\"");

    // Get a reference to the file
    TagLib::FileRef f(path.c_str());

    // Ask for the artist
    artist_confirmation.reset();
    if (!f.tag()->artist().isNull())
        artist_confirmation.set_local_default(m_input_filter->filter(f.tag()->artist().toWString()));
    artist_confirmation.ask(L"Artist:");
    while (!artist_confirmation.complies())
        artist_confirmation.ask(L"Artist (confirmation):");
    f.tag()->setArtist(artist_confirmation.answer());

    // Ask for the album
    album_confirmation.reset();
    if (!f.tag()->album().isNull())
        album_confirmation.set_local_default(m_input_filter->filter(f.tag()->album().toWString()));
    album_confirmation.ask(L"Album:");
    while (!album_confirmation.complies())
        album_confirmation.ask(L"Album (confirmation):");
    f.tag()->setAlbum(album_confirmation.answer());

    // Ask for the year
    boost::optional<int> default_year;
    if (year && *year != -1)
        default_year = *year;
    else if (f.tag()->year())
        default_year = f.tag()->year();
    YearValidator year_validator;
    int new_year = m_terminal->ask_number_question(L"Year:", default_year, &year_validator);
    f.tag()->setYear(new_year);
    if (year) *year = new_year;

    // Ask for the track
    if (track == -1)
        track = f.tag()->track();
    TrackValidator track_validator;
    int new_track = m_terminal->ask_number_question(L"Track:",
            track > 0 ? track : boost::optional<int>(), &track_validator);
    f.tag()->setTrack(new_track);

    // Ask for the song title
    boost::optional<std::wstring> default_title;
    if (!f.tag()->title().isNull())
        default_title = m_input_filter->filter(f.tag()->title().toWString());
    std::wstring new_title = m_terminal->ask_string_question(L"Title:", default_title);
    if (m_output_filter) {
        std::wstring filtered_title = m_output_filter->filter(new_title);
        if (m_input_filter->requires_confirmation_as_output_filter() && filtered_title != new_title)
            filtered_title = m_terminal->ask_string_question(L"Title (confirmation):", filtered_title);
        new_title = filtered_title;
    }
    f.tag()->setTitle(new_title);

    // Reset the comment and genre fields
    f.tag()->setComment(TagLib::String::null);
    f.tag()->setGenre(TagLib::String::null);

    // Add it to the list of unsaved files
    m_unsaved_files.push_back(f);

    // Add it to the list of pending renames based on the supplied format
    if (m_file_rename_format) {
        std::map<std::wstring, std::wstring> tokens;
        tokens[L"artist"] = m_renaming_filter->filter(artist_confirmation.answer());
        tokens[L"album"] = m_renaming_filter->filter(album_confirmation.answer());
        tokens[L"year"] = boost::lexical_cast<std::wstring>(new_year);
        std::wstring track_str(boost::lexical_cast<std::wstring>(new_track));
        if (track_str.size() == 1) track_str = L"0" + track_str;
        tokens[L"track"] = track_str;
        tokens[L"title"] = m_renaming_filter->filter(new_title);
        fs::path new_path = path.parent_path();
        new_path /= replace_tokens(*m_file_rename_format, tokens)
            + boost::to_lower_copy(path.extension().string<std::wstring>());
        if (new_path != path)
            m_pending_renames.push_back(std::pair<fs::path, fs::path>(path, new_path));
    }
}

void InteractiveTagger::tag_file(const boost::filesystem::path &path)
{
    // Tag a file without recording the global default
    ConfirmationHandler amnesiac(*m_terminal, m_input_filter, m_output_filter);
    tag_file(path, amnesiac, amnesiac, NULL, -1);
}

void InteractiveTagger::tag_directory(const fs::path &path)
{
    m_terminal->display_info_message(L"=== Entering \"" + path.string<std::wstring>() + L"\"");

    // Create lists of files and subdirectories
    std::list<fs::path> file_list, dir_list;
    fs::directory_iterator end_it;
    for (fs::directory_iterator it(path); it != end_it; ++it) {
        // Normalize the path (needed here so that we follow symlinks)
        char *real_path = realpath(it->path().c_str(), NULL);
        if (!real_path) {
            m_terminal->display_warning_message(L"\"" + it->path().filename().string<std::wstring>()
                    + L"\" is not a valid path, skipping...");
            continue;
        }
        fs::path boost_path(boost::lexical_cast<std::wstring>(real_path));
        free(real_path);

        // Add to the right list
        if (fs::is_regular_file(boost_path)) {
            if (is_supported_extension(boost_path)) {
                file_list.push_back(boost_path);
            }
            else {
                m_terminal->display_warning_message(L"\"" + it->path().filename().string<std::wstring>()
                        + L"\" has no supported extension, skipping...");
            }
        }
        else if (fs::is_directory(boost_path)) {
            dir_list.push_back(boost_path);
        }
        else {
            m_terminal->display_warning_message(L"\"" + boost_path.filename().string<std::wstring>()
                    + L"\" is not a regular file or directory, skipping...");
        }
    }

    // Sort those lists
    file_list.sort();
    dir_list.sort();

    // Tag all individual files
    ConfirmationHandler artist(*m_terminal, m_input_filter, m_output_filter);
    ConfirmationHandler album(*m_terminal, m_input_filter, m_output_filter);
    int year = -1;
    if (!file_list.empty()) {
        int track = 1;
        BOOST_FOREACH(const fs::path &p, file_list)
            tag_file(p, artist, album, &year, track++);
    }

    // We'll ask confirmation to descend into the subdirectories only if there are files
    BOOST_FOREACH(const fs::path &p, dir_list) {
        if (file_list.empty() || m_terminal->ask_yes_no_question(L"Descend into subdirectory \""
                    + boost::lexical_cast<std::wstring>(p.filename()) + L"\"?", false))
            tag_directory(p);
    }

    // Add it to the list of pending renames based on the supplied format
    if (artist.answer().empty() && m_dir_rename_format) {
        std::map<std::wstring, std::wstring> tokens;
        tokens[L"artist"] = m_renaming_filter->filter(artist.answer());
        tokens[L"album"] = m_renaming_filter->filter(album.answer());
        tokens[L"year"] = boost::lexical_cast<std::wstring>(year);
        fs::path new_path = path.parent_path();
        new_path /= replace_tokens(*m_dir_rename_format, tokens);
        if (new_path != path)
            m_pending_renames.push_back(std::pair<fs::path, fs::path>(path, new_path));
    }
}
<commit_msg>Fix directory renaming.<commit_after>/*
 * This file is part of btag.
 *
 * © 2010-2011 Fernando Tarlá Cardoso Lemos
 *
 * Refer to the LICENSE file for licensing information.
 *
 */

#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/optional.hpp>
#include <taglib/fileref.h>
#include <taglib/tag.h>
#include <cassert>
#include <cstdlib>
#include <exception>

#include "InteractiveTagger.h"
#include "validators.h"
#include "wide_string_cast.h"

namespace fs = boost::filesystem;

InteractiveTagger::InteractiveTagger()
    : m_input_filter(NULL), m_output_filter(NULL), m_dry_run(false)
{
    // Load the extensions supported by TagLib
    TagLib::StringList extensions = TagLib::FileRef::defaultFileExtensions();
    for (TagLib::StringList::ConstIterator it = extensions.begin(); it != extensions.end(); ++it)
        m_supported_extensions.push_back(L'.' + it->toWString());
}

void InteractiveTagger::set_file_rename_format(const std::string &format)
{
    m_file_rename_format = boost::lexical_cast<std::wstring>(format);
}

void InteractiveTagger::set_dir_rename_format(const std::string &format)
{
    m_dir_rename_format = boost::lexical_cast<std::wstring>(format);
}

void InteractiveTagger::tag(int num_paths, const char **paths)
{
    assert(m_terminal);

    // Build a list with the normalized paths
    std::list<fs::path> path_list;
    for (int i = 0; i < num_paths; ++i) {
        char *real_path = realpath(paths[i], NULL);
        if (!real_path) {
            std::string errstr("\"");
            errstr += paths[i];
            errstr += "\" is not a valid path";
            m_terminal->display_warning_message(errstr);
            continue;
        }
        path_list.push_back(fs::path(boost::lexical_cast<std::wstring>(std::string(real_path))));
        free(real_path);
    }

    // Sort it and tag the paths
    path_list.sort();
    BOOST_FOREACH(const fs::path &path, path_list) {
        // Check if the path exists
        if (!fs::exists(path)) {
            m_terminal->display_warning_message(L"Path \"" + path.string<std::wstring>()
                    + L"\" not found, skipping...");
            continue;
        }

        try {
            // If it's a regular file, just tag it
            if (fs::is_regular_file(path)) {
                if (!is_supported_extension(path)) {
                    m_terminal->display_warning_message(L"Path \"" + path.string<std::wstring>()
                            + L"\" has no supported extension, skipping...");
                    continue;
                }
                tag_file(path);
            }

            // If it's a directory, tag its contents
            else if (fs::is_directory(path)) {
                tag_directory(path);
            }

            // It's none of the above, do something about it
            else {
                m_terminal->display_warning_message(L"Path \"" + path.string<std::wstring>()
                        + L"\" is not a regular file or directory, skipping...");
            }
        }
        catch (std::exception &e) {
            m_terminal->display_warning_message(e.what());
        }
    }

    // Save the unsaved files
    if (!m_unsaved_files.empty()
            && (m_dry_run || m_terminal->ask_yes_no_question(L"=== OK to save the changes to the files?"))) {
        if (m_dry_run)
            m_terminal->display_info_message("=== Not saving changes (dry run mode)");
        BOOST_FOREACH(TagLib::FileRef &f, m_unsaved_files) {
            std::string message(m_dry_run ? "Not saving" : "Saving");
            message += " \"" + std::string(f.file()->name()) + '\"';
            m_terminal->display_info_message(message);
            if (!m_dry_run && !f.save())
                m_terminal->display_warning_message("Unable to save " + std::string(f.file()->name()) + "\"");
        }
    }

    // Perform the pending renames
    if (!m_pending_renames.empty()
            && (m_dry_run || m_terminal->ask_yes_no_question(L"=== OK to rename the files?"))) {
        m_terminal->display_info_message("=== Not renaming files (dry run mode)");
        std::list<std::pair<fs::path, fs::path> >::const_iterator it;
        for (it = m_pending_renames.begin(); it != m_pending_renames.end(); ++it) {
            const fs::path &from((*it).first);
            const fs::path &to((*it).second);
            m_terminal->display_info_message(from.string());
            m_terminal->display_info_message(L"-> " + to.string<std::wstring>());
            if (!m_dry_run) {
                try { fs::rename(from, to); }
                catch (std::exception &e) { m_terminal->display_warning_message(e.what()); }
            }
        }
    }

    m_terminal->display_info_message("=== All done!");
}

bool InteractiveTagger::is_supported_extension(const fs::path &path)
{
    std::wstring extension(path.extension().string<std::wstring>());
    boost::to_lower(extension);

    BOOST_FOREACH(const std::wstring &supported_extension, m_supported_extensions) {
        if (extension == supported_extension)
            return true;
    }

    return false;
}

std::wstring InteractiveTagger::replace_tokens(const std::wstring &str,
        const std::map<std::wstring, std::wstring> &replacements)
{
    std::wstring res;
    res.reserve(str.size() * 3);

    bool parsing_token = false;
    std::wstring current_token;
    BOOST_FOREACH(char c, str) {
        if (c == '%') {
            if (parsing_token) {
                std::map<std::wstring, std::wstring>::const_iterator it = replacements.find(current_token);
                res += it == replacements.end() ? current_token : it->second;
                current_token.erase();
            }
            parsing_token = true;
        }
        else if (parsing_token) {
            if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
                current_token += c;
            }
            else {
                std::map<std::wstring, std::wstring>::const_iterator it = replacements.find(current_token);
                res += it == replacements.end() ? current_token : it->second;
                res += c;
                parsing_token = false;
                current_token.erase();
            }
        }
        else {
            res += c;
        }
    }
    if (parsing_token) {
        std::map<std::wstring, std::wstring>::const_iterator it = replacements.find(current_token);
        res += it == replacements.end() ? current_token : it->second;
    }

    return res;
}

void InteractiveTagger::tag_file(const fs::path &path, ConfirmationHandler &artist_confirmation,
       ConfirmationHandler &album_confirmation, int *year, int track)
{
    m_terminal->display_info_message(L"=== Tagging \"" + path.filename().string<std::wstring>() + L"\"");

    // Get a reference to the file
    TagLib::FileRef f(path.c_str());

    // Ask for the artist
    artist_confirmation.reset();
    if (!f.tag()->artist().isNull())
        artist_confirmation.set_local_default(m_input_filter->filter(f.tag()->artist().toWString()));
    artist_confirmation.ask(L"Artist:");
    while (!artist_confirmation.complies())
        artist_confirmation.ask(L"Artist (confirmation):");
    f.tag()->setArtist(artist_confirmation.answer());

    // Ask for the album
    album_confirmation.reset();
    if (!f.tag()->album().isNull())
        album_confirmation.set_local_default(m_input_filter->filter(f.tag()->album().toWString()));
    album_confirmation.ask(L"Album:");
    while (!album_confirmation.complies())
        album_confirmation.ask(L"Album (confirmation):");
    f.tag()->setAlbum(album_confirmation.answer());

    // Ask for the year
    boost::optional<int> default_year;
    if (year && *year != -1)
        default_year = *year;
    else if (f.tag()->year())
        default_year = f.tag()->year();
    YearValidator year_validator;
    int new_year = m_terminal->ask_number_question(L"Year:", default_year, &year_validator);
    f.tag()->setYear(new_year);
    if (year) *year = new_year;

    // Ask for the track
    if (track == -1)
        track = f.tag()->track();
    TrackValidator track_validator;
    int new_track = m_terminal->ask_number_question(L"Track:",
            track > 0 ? track : boost::optional<int>(), &track_validator);
    f.tag()->setTrack(new_track);

    // Ask for the song title
    boost::optional<std::wstring> default_title;
    if (!f.tag()->title().isNull())
        default_title = m_input_filter->filter(f.tag()->title().toWString());
    std::wstring new_title = m_terminal->ask_string_question(L"Title:", default_title);
    if (m_output_filter) {
        std::wstring filtered_title = m_output_filter->filter(new_title);
        if (m_input_filter->requires_confirmation_as_output_filter() && filtered_title != new_title)
            filtered_title = m_terminal->ask_string_question(L"Title (confirmation):", filtered_title);
        new_title = filtered_title;
    }
    f.tag()->setTitle(new_title);

    // Reset the comment and genre fields
    f.tag()->setComment(TagLib::String::null);
    f.tag()->setGenre(TagLib::String::null);

    // Add it to the list of unsaved files
    m_unsaved_files.push_back(f);

    // Add it to the list of pending renames based on the supplied format
    if (m_file_rename_format) {
        std::map<std::wstring, std::wstring> tokens;
        tokens[L"artist"] = m_renaming_filter->filter(artist_confirmation.answer());
        tokens[L"album"] = m_renaming_filter->filter(album_confirmation.answer());
        tokens[L"year"] = boost::lexical_cast<std::wstring>(new_year);
        std::wstring track_str(boost::lexical_cast<std::wstring>(new_track));
        if (track_str.size() == 1) track_str = L"0" + track_str;
        tokens[L"track"] = track_str;
        tokens[L"title"] = m_renaming_filter->filter(new_title);
        fs::path new_path = path.parent_path();
        new_path /= replace_tokens(*m_file_rename_format, tokens)
            + boost::to_lower_copy(path.extension().string<std::wstring>());
        if (new_path != path)
            m_pending_renames.push_back(std::pair<fs::path, fs::path>(path, new_path));
    }
}

void InteractiveTagger::tag_file(const boost::filesystem::path &path)
{
    // Tag a file without recording the global default
    ConfirmationHandler amnesiac(*m_terminal, m_input_filter, m_output_filter);
    tag_file(path, amnesiac, amnesiac, NULL, -1);
}

void InteractiveTagger::tag_directory(const fs::path &path)
{
    m_terminal->display_info_message(L"=== Entering \"" + path.string<std::wstring>() + L"\"");

    // Create lists of files and subdirectories
    std::list<fs::path> file_list, dir_list;
    fs::directory_iterator end_it;
    for (fs::directory_iterator it(path); it != end_it; ++it) {
        // Normalize the path (needed here so that we follow symlinks)
        char *real_path = realpath(it->path().c_str(), NULL);
        if (!real_path) {
            m_terminal->display_warning_message(L"\"" + it->path().filename().string<std::wstring>()
                    + L"\" is not a valid path, skipping...");
            continue;
        }
        fs::path boost_path(boost::lexical_cast<std::wstring>(real_path));
        free(real_path);

        // Add to the right list
        if (fs::is_regular_file(boost_path)) {
            if (is_supported_extension(boost_path)) {
                file_list.push_back(boost_path);
            }
            else {
                m_terminal->display_warning_message(L"\"" + it->path().filename().string<std::wstring>()
                        + L"\" has no supported extension, skipping...");
            }
        }
        else if (fs::is_directory(boost_path)) {
            dir_list.push_back(boost_path);
        }
        else {
            m_terminal->display_warning_message(L"\"" + boost_path.filename().string<std::wstring>()
                    + L"\" is not a regular file or directory, skipping...");
        }
    }

    // Sort those lists
    file_list.sort();
    dir_list.sort();

    // Tag all individual files
    ConfirmationHandler artist(*m_terminal, m_input_filter, m_output_filter);
    ConfirmationHandler album(*m_terminal, m_input_filter, m_output_filter);
    int year = -1;
    if (!file_list.empty()) {
        int track = 1;
        BOOST_FOREACH(const fs::path &p, file_list)
            tag_file(p, artist, album, &year, track++);
    }

    // We'll ask confirmation to descend into the subdirectories only if there are files
    BOOST_FOREACH(const fs::path &p, dir_list) {
        if (file_list.empty() || m_terminal->ask_yes_no_question(L"Descend into subdirectory \""
                    + boost::lexical_cast<std::wstring>(p.filename()) + L"\"?", false))
            tag_directory(p);
    }

    // Add it to the list of pending renames based on the supplied format
    if (!artist.answer().empty() && m_dir_rename_format) {
        std::map<std::wstring, std::wstring> tokens;
        tokens[L"artist"] = m_renaming_filter->filter(artist.answer());
        tokens[L"album"] = m_renaming_filter->filter(album.answer());
        tokens[L"year"] = boost::lexical_cast<std::wstring>(year);
        fs::path new_path = path.parent_path();
        new_path /= replace_tokens(*m_dir_rename_format, tokens);
        if (new_path != path)
            m_pending_renames.push_back(std::pair<fs::path, fs::path>(path, new_path));
    }
}
<|endoftext|>


<commit_before>#include <stdlib.h>
#include "ShapePopulationViewerCLP.h"
#include <string>

int main( int argc , char* argv[] )
{
  PARSE_ARGS;
  std::string path = argv[0] ;
  unsigned int found = path.find_last_of( "/" ) ;
  path = path.substr( 0 , found ) ;
#ifdef WIN32
  std::string cmd = path + "/../hidden-cli-modules/ShapePopulationViewer.exe" ;
#else
  std::string cmd = path + "/../hidden-cli-modules/ShapePopulationViewer" ;
#endif
  for( int i = 1 ; i < argc ; i++ )
  {
    cmd += " " ;
    cmd += argv[ i ] ;
  }
  std::cout<< cmd << std::endl ;
  int val = system( cmd.c_str() ) ;
  return val ;
}
<commit_msg>BUG: Launcher could not run SPV if path had spaces<commit_after>#include <stdlib.h>
#include "ShapePopulationViewerCLP.h"
#include <string>

int main( int argc , char* argv[] )
{
  PARSE_ARGS;
  std::string path = argv[0] ;
  unsigned int found = path.find_last_of( "/" ) ;
  path = path.substr( 0 , found ) ;
#ifdef WIN32
  std::string cmd = path + "/../hidden-cli-modules/ShapePopulationViewer.exe" ;
#else
  std::string cmd = path + "/../hidden-cli-modules/ShapePopulationViewer" ;
#endif
  std::string filler("\"");
  cmd =  filler +  cmd + filler;
  for( int i = 1 ; i < argc ; i++ )
  {
    cmd += " " ;
    cmd += argv[i];
  }
  std::cout<< cmd << std::endl ;
  int val = system( cmd.c_str() ) ;
  return val ;
}
<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

/**
 * @file
 **/

#include <iostream>
#include <string>
#include <vector>

#include "gflags/gflags.h"
#include "modules/common/log.h"
#include "modules/common/math/vec2d.h"
#include "modules/common/util/util.h"
#include "modules/map/pnc_map/path.h"
#include "modules/planning/common/planning_gflags.h"
#include "modules/planning/reference_line/qp_spline_reference_line_smoother.h"
#include "modules/planning/reference_line/reference_line.h"
#include "modules/planning/reference_line/reference_line_smoother.h"

DEFINE_string(input_file, "", "input file with format x,y per line");
DEFINE_string(output_file, "", "output file with format x,y per line");
DEFINE_double(smooth_length, 200, "Smooth this amount of length ");

namespace apollo {
namespace planning {

using common::math::LineSegment2d;
using common::math::Vec2d;
using common::util::DistanceXY;
using hdmap::MapPathPoint;

class SmootherUtil {
 public:
  explicit SmootherUtil(const std::string& filename) {
    filename_ = filename;
    std::ifstream ifs(filename.c_str(), std::ifstream::in);
    std::string point_str;
    while (std::getline(ifs, point_str)) {
      std::size_t idx = point_str.find(',');
      if (idx == std::string::npos) {
        continue;
      }
      auto x_str = point_str.substr(0, idx);
      auto y_str = point_str.substr(idx + 1);
      raw_points_.emplace_back(std::stod(x_str), std::stod(y_str));
    }
    CHECK(common::util::GetProtoFromFile(FLAGS_smoother_config_filename,
                                         &config_))
        << "Failed to read smoother config file: "
        << FLAGS_smoother_config_filename;
  }

  bool Smooth() {
    if (raw_points_.size() <= 2) {
      AERROR << "the original point size is " << raw_points_.size();
      return false;
    }
    std::size_t i = 1;
    {
      std::vector<ReferencePoint> ref_points;
      double s = 0.0;
      for (; s < FLAGS_smooth_length && i < raw_points_.size(); ++i) {
        LineSegment2d segment(raw_points_[i - 1], raw_points_[i]);
        ref_points.emplace_back(MapPathPoint(raw_points_[i], segment.heading()),
                                0.0, 0.0, 0.0, 0.0);
        s += segment.length();
      }
      ReferenceLine init_ref(ref_points);
      std::unique_ptr<ReferenceLineSmoother> smoother_ptr(
          new QpSplineReferenceLineSmoother(config_));
      auto anchors =
          CreateAnchorPoints(init_ref.reference_points().front(), init_ref);
      smoother_ptr->SetAnchorPoints(anchors);
      ReferenceLine smoothed_init_ref;
      if (!smoother_ptr->Smooth(init_ref, &smoothed_init_ref)) {
        AERROR << "smooth initial reference line failed";
        return false;
      }
      ref_points_ = smoothed_init_ref.reference_points();
    }
    for (; i < raw_points_.size(); ++i) {
      double s = 0.0;
      std::size_t j = ref_points_.size() - 1;
      while (j > 0 && s < FLAGS_smooth_length / 2.0) {
        s += DistanceXY(ref_points_[j - 1], ref_points_[j]);
        --j;
      }
      ReferenceLine prev_half_ref(ref_points_.begin() + j, ref_points_.end());
      ref_points_.erase(ref_points_.begin() + j, ref_points_.end());
      common::SLPoint sl;
      prev_half_ref.XYToSL(raw_points_[i], &sl);
      while (sl.s() <= prev_half_ref.Length() && i + 1 < raw_points_.size()) {
        ++i;
        prev_half_ref.XYToSL(raw_points_[i], &sl);
      }
      s = 0.0;
      j = i;
      auto ref_points = prev_half_ref.reference_points();
      while (j + 1 < raw_points_.size() && s < FLAGS_smooth_length / 2.0) {
        Vec2d vec = raw_points_[j + 1] - raw_points_[j];
        s += vec.Length();
        ref_points.emplace_back(MapPathPoint(raw_points_[j], vec.Angle()), 0.0,
                                0.0, 0.0, 0.0);
        ++j;
      }
      i = j;
      ReferenceLine local_ref(ref_points);
      auto anchors = CreateAnchorPoints(ref_points.front(), local_ref);
      std::unique_ptr<ReferenceLineSmoother> smoother_ptr(
          new QpSplineReferenceLineSmoother(config_));
      smoother_ptr->SetAnchorPoints(anchors);
      ReferenceLine smoothed_local_ref;
      if (!smoother_ptr->Smooth(local_ref, &smoothed_local_ref)) {
        AERROR << "Failed to smooth reference line";
        return false;
      }
      ref_points_.insert(ref_points_.end(),
                         smoothed_local_ref.reference_points().begin(),
                         smoothed_local_ref.reference_points().end());
    }
    return true;
  }

  void Export(const std::string& filename) {
    std::ofstream ofs(filename.c_str());
    ofs.precision(6);
    double s = 0.0;
    for (std::size_t i = 0; i + 1 < ref_points_.size(); ++i) {
      const auto& point = ref_points_[i];
      ofs << std::fixed << "{\"kappa\": " << point.kappa() << ", \"s\": " << s
          << ", \"theta\": " << point.heading() << ", \"x\":" << point.x()
          << ", \"y\":" << point.y() << ", \"dkappa\":" << point.dkappa() << "}"
          << std::endl;
      s += DistanceXY(point, ref_points_[i + 1]);
    }
    ofs.close();
    AINFO << "Smoothed result saved to " << filename;
  }

 private:
  std::vector<AnchorPoint> CreateAnchorPoints(const ReferencePoint& init_point,
                                              const ReferenceLine& ref_line) {
    std::vector<AnchorPoint> anchor_points;
    int num_of_anchors = std::max(
        2, static_cast<int>(
               ref_line.Length() / config_.max_constraint_interval() + 0.5));
    std::vector<double> anchor_s;
    common::util::uniform_slice(0.0, ref_line.Length(), num_of_anchors - 1,
                                &anchor_s);
    common::SLPoint sl;
    if (!ref_line.XYToSL(Vec2d(init_point.x(), init_point.y()), &sl)) {
      AERROR << "Failed to project init point to reference line";
      return anchor_points;
    }
    bool set_init_point = false;
    for (const double s : anchor_s) {
      if (s + config_.max_constraint_interval() / 2.0 < sl.s()) {
        continue;
      }
      ReferencePoint ref_point;
      if (!set_init_point) {
        set_init_point = true;
        ref_point = init_point;
      } else {
        ref_point = ref_line.GetReferencePoint(s);
      }
      AnchorPoint anchor;
      anchor.path_point.set_x(ref_point.x());
      anchor.path_point.set_y(ref_point.y());
      anchor.path_point.set_z(0.0);
      anchor.path_point.set_s(s);
      anchor.path_point.set_theta(ref_point.heading());
      anchor.path_point.set_kappa(ref_point.kappa());
      anchor.lateral_bound = config_.lateral_boundary_bound();
      anchor.longitudinal_bound = config_.longitudinal_boundary_bound();
      anchor_points.emplace_back(anchor);
    }
    anchor_points.front().longitudinal_bound = 0;
    anchor_points.front().lateral_bound = 0;
    anchor_points.front().enforced = true;
    anchor_points.back().longitudinal_bound = 0;
    anchor_points.back().lateral_bound = 0;
    anchor_points.back().enforced = true;
    return anchor_points;
  }

 private:
  std::string filename_;
  std::vector<common::math::Vec2d> raw_points_;
  std::vector<ReferencePoint> ref_points_;
  ReferenceLine smoothed_ref_;
  ReferenceLineSmootherConfig config_;
};

}  // namespace planning
}  // namespace apollo

int main(int argc, char* argv[]) {
  google::InitGoogleLogging(argv[0]);
  google::ParseCommandLineFlags(&argc, &argv, true);

  if (FLAGS_input_file.empty()) {
    AERROR << "need to provide --input_file";
    return 0;
  }
  apollo::planning::SmootherUtil smoother_util(FLAGS_input_file);
  if (!smoother_util.Smooth()) {
    AERROR << "Failed to smooth a the line";
  }
  if (FLAGS_output_file.empty()) {
    FLAGS_output_file = FLAGS_input_file + ".smoothed";
    AINFO << "Output file not provided, set to: " << FLAGS_output_file;
  }
  smoother_util.Export(FLAGS_output_file);
  return 0;
}
<commit_msg>smoother: skip the first point and the last point after smooth<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

/**
 * @file
 **/

#include <iostream>
#include <string>
#include <vector>

#include "gflags/gflags.h"
#include "modules/common/log.h"
#include "modules/common/math/vec2d.h"
#include "modules/common/util/util.h"
#include "modules/map/pnc_map/path.h"
#include "modules/planning/common/planning_gflags.h"
#include "modules/planning/reference_line/qp_spline_reference_line_smoother.h"
#include "modules/planning/reference_line/reference_line.h"
#include "modules/planning/reference_line/reference_line_smoother.h"

DEFINE_string(input_file, "", "input file with format x,y per line");
DEFINE_string(output_file, "", "output file with format x,y per line");
DEFINE_double(smooth_length, 200, "Smooth this amount of length ");

namespace apollo {
namespace planning {

using common::math::LineSegment2d;
using common::math::Vec2d;
using common::util::DistanceXY;
using hdmap::MapPathPoint;

class SmootherUtil {
 public:
  explicit SmootherUtil(const std::string& filename) {
    filename_ = filename;
    std::ifstream ifs(filename.c_str(), std::ifstream::in);
    std::string point_str;
    while (std::getline(ifs, point_str)) {
      std::size_t idx = point_str.find(',');
      if (idx == std::string::npos) {
        continue;
      }
      auto x_str = point_str.substr(0, idx);
      auto y_str = point_str.substr(idx + 1);
      raw_points_.emplace_back(std::stod(x_str), std::stod(y_str));
    }
    CHECK(common::util::GetProtoFromFile(FLAGS_smoother_config_filename,
                                         &config_))
        << "Failed to read smoother config file: "
        << FLAGS_smoother_config_filename;
  }

  bool Smooth() {
    if (raw_points_.size() <= 2) {
      AERROR << "the original point size is " << raw_points_.size();
      return false;
    }
    std::size_t i = 1;
    {
      std::vector<ReferencePoint> ref_points;
      double s = 0.0;
      for (; s < FLAGS_smooth_length && i < raw_points_.size(); ++i) {
        LineSegment2d segment(raw_points_[i - 1], raw_points_[i]);
        ref_points.emplace_back(MapPathPoint(raw_points_[i], segment.heading()),
                                0.0, 0.0, 0.0, 0.0);
        s += segment.length();
      }
      ReferenceLine init_ref(ref_points);
      std::unique_ptr<ReferenceLineSmoother> smoother_ptr(
          new QpSplineReferenceLineSmoother(config_));
      auto anchors =
          CreateAnchorPoints(init_ref.reference_points().front(), init_ref);
      smoother_ptr->SetAnchorPoints(anchors);
      ReferenceLine smoothed_init_ref;
      if (!smoother_ptr->Smooth(init_ref, &smoothed_init_ref)) {
        AERROR << "smooth initial reference line failed";
        return false;
      }
      ref_points_ = smoothed_init_ref.reference_points();
    }
    for (; i < raw_points_.size(); ++i) {
      double s = 0.0;
      std::size_t j = ref_points_.size() - 1;
      while (j > 0 && s < FLAGS_smooth_length / 2.0) {
        s += DistanceXY(ref_points_[j - 1], ref_points_[j]);
        --j;
      }
      ReferenceLine prev_half_ref(ref_points_.begin() + j, ref_points_.end());
      ref_points_.erase(ref_points_.begin() + j, ref_points_.end());
      common::SLPoint sl;
      prev_half_ref.XYToSL(raw_points_[i], &sl);
      while (sl.s() <= prev_half_ref.Length() && i + 1 < raw_points_.size()) {
        ++i;
        prev_half_ref.XYToSL(raw_points_[i], &sl);
      }
      s = 0.0;
      j = i;
      auto ref_points = prev_half_ref.reference_points();
      while (j + 1 < raw_points_.size() && s < FLAGS_smooth_length / 2.0) {
        Vec2d vec = raw_points_[j + 1] - raw_points_[j];
        s += vec.Length();
        ref_points.emplace_back(MapPathPoint(raw_points_[j], vec.Angle()), 0.0,
                                0.0, 0.0, 0.0);
        ++j;
      }
      i = j;
      ReferenceLine local_ref(ref_points);
      auto anchors = CreateAnchorPoints(ref_points.front(), local_ref);
      std::unique_ptr<ReferenceLineSmoother> smoother_ptr(
          new QpSplineReferenceLineSmoother(config_));
      smoother_ptr->SetAnchorPoints(anchors);
      ReferenceLine smoothed_local_ref;
      if (!smoother_ptr->Smooth(local_ref, &smoothed_local_ref)) {
        AERROR << "Failed to smooth reference line";
        return false;
      }
      ref_points_.insert(ref_points_.end(),
                         smoothed_local_ref.reference_points().begin(),
                         smoothed_local_ref.reference_points().end());
    }
    return true;
  }

  void Export(const std::string& filename) {
    std::ofstream ofs(filename.c_str());
    ofs.precision(6);
    double s = 0.0;
    // skip the first point and the last point
    for (std::size_t i = 1; i + 1 < ref_points_.size(); ++i) {
      const auto& point = ref_points_[i];
      ofs << std::fixed << "{\"kappa\": " << point.kappa() << ", \"s\": " << s
          << ", \"theta\": " << point.heading() << ", \"x\":" << point.x()
          << ", \"y\":" << point.y() << ", \"dkappa\":" << point.dkappa() << "}"
          << std::endl;
      s += DistanceXY(point, ref_points_[i + 1]);
    }
    ofs.close();
    AINFO << "Smoothed result saved to " << filename;
  }

 private:
  std::vector<AnchorPoint> CreateAnchorPoints(const ReferencePoint& init_point,
                                              const ReferenceLine& ref_line) {
    std::vector<AnchorPoint> anchor_points;
    int num_of_anchors = std::max(
        2, static_cast<int>(
               ref_line.Length() / config_.max_constraint_interval() + 0.5));
    std::vector<double> anchor_s;
    common::util::uniform_slice(0.0, ref_line.Length(), num_of_anchors - 1,
                                &anchor_s);
    common::SLPoint sl;
    if (!ref_line.XYToSL(Vec2d(init_point.x(), init_point.y()), &sl)) {
      AERROR << "Failed to project init point to reference line";
      return anchor_points;
    }
    bool set_init_point = false;
    for (const double s : anchor_s) {
      if (s + config_.max_constraint_interval() / 2.0 < sl.s()) {
        continue;
      }
      ReferencePoint ref_point;
      if (!set_init_point) {
        set_init_point = true;
        ref_point = init_point;
      } else {
        ref_point = ref_line.GetReferencePoint(s);
      }
      AnchorPoint anchor;
      anchor.path_point.set_x(ref_point.x());
      anchor.path_point.set_y(ref_point.y());
      anchor.path_point.set_z(0.0);
      anchor.path_point.set_s(s);
      anchor.path_point.set_theta(ref_point.heading());
      anchor.path_point.set_kappa(ref_point.kappa());
      anchor.lateral_bound = config_.lateral_boundary_bound();
      anchor.longitudinal_bound = config_.longitudinal_boundary_bound();
      anchor_points.emplace_back(anchor);
    }
    anchor_points.front().longitudinal_bound = 0;
    anchor_points.front().lateral_bound = 0;
    anchor_points.front().enforced = true;
    anchor_points.back().longitudinal_bound = 0;
    anchor_points.back().lateral_bound = 0;
    anchor_points.back().enforced = true;
    return anchor_points;
  }

 private:
  std::string filename_;
  std::vector<common::math::Vec2d> raw_points_;
  std::vector<ReferencePoint> ref_points_;
  ReferenceLine smoothed_ref_;
  ReferenceLineSmootherConfig config_;
};

}  // namespace planning
}  // namespace apollo

int main(int argc, char* argv[]) {
  google::InitGoogleLogging(argv[0]);
  google::ParseCommandLineFlags(&argc, &argv, true);

  if (FLAGS_input_file.empty()) {
    AERROR << "need to provide --input_file";
    return 0;
  }
  apollo::planning::SmootherUtil smoother_util(FLAGS_input_file);
  if (!smoother_util.Smooth()) {
    AERROR << "Failed to smooth a the line";
  }
  if (FLAGS_output_file.empty()) {
    FLAGS_output_file = FLAGS_input_file + ".smoothed";
    AINFO << "Output file not provided, set to: " << FLAGS_output_file;
  }
  smoother_util.Export(FLAGS_output_file);
  return 0;
}
<|endoftext|>


<commit_before>/*
 * MIT License
 *
 * Copyright (c) 2016 xiongziliang <771730766@qq.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
#include "TcpClient.h"

namespace ZL {
namespace Network {

TcpClient::TcpClient() : SocketHelper(nullptr) {
}

TcpClient::~TcpClient() {
}

void TcpClient::shutdown() {
    weak_ptr<TcpClient> weakSelf = shared_from_this();
    ASYNC_TRACE([weakSelf,this](){
        auto strongSelf = weakSelf.lock();
        if(!strongSelf){
            return;
        }
        if(_sock){
            _sock->setOnErr(nullptr);
            _sock->setOnRead(nullptr);
            _sock->setOnFlush(nullptr);
            setSock(nullptr);
        }
        _managerTimer.reset();
    });
}

bool TcpClient::alive() {
    bool ret = _sock.operator bool();
    return ret;
}

void TcpClient::startConnect(const string &strUrl, uint16_t iPort,float fTimeOutSec) {
    weak_ptr<TcpClient> weakSelf = shared_from_this();
    ASYNC_TRACE([strUrl,iPort,fTimeOutSec,weakSelf,this](){
        auto strongSelf = weakSelf.lock();
        if(!strongSelf){
            return;
        }
        shutdown();
        SocketHelper::setSock(std::make_shared<Socket>());

        weak_ptr<TcpClient> weakSelf = shared_from_this();
        _sock->connect(strUrl, iPort, [weakSelf](const SockException &err){
            auto strongSelf = weakSelf.lock();
            if(strongSelf){
                if(err){
                    strongSelf->SocketHelper::setSock(nullptr);
                }
                strongSelf->onSockConnect(err);
            }
        }, fTimeOutSec);
    });
}
void TcpClient::onSockConnect(const SockException &ex) {
	if(!ex && _sock) {
        weak_ptr<TcpClient> weakSelf = shared_from_this();
        _sock->setOnErr([weakSelf](const SockException &ex) {
			auto strongSelf = weakSelf.lock();
			if (!strongSelf) {
				return;
			}
            strongSelf->onSockErr(ex);
		});
        _sock->setOnFlush([weakSelf]() {
			auto strongSelf = weakSelf.lock();
			if (!strongSelf) {
				return false;
			}
            strongSelf->onSockSend();
			return true;
		});
        _sock->setOnRead([weakSelf](const Buffer::Ptr &pBuf, struct sockaddr *addr) {
			auto strongSelf = weakSelf.lock();
			if (!strongSelf) {
				return;
			}
            strongSelf->onSockRecv(pBuf);
		});
        _managerTimer.reset(new Timer(2,[weakSelf](){
            auto strongSelf = weakSelf.lock();
            if (!strongSelf) {
                return false;
            }
            strongSelf->onManager();
            return true;
        }));
	}
    onConnect(ex);
}

void TcpClient::onSockRecv(const Buffer::Ptr& pBuf) {
	onRecv(pBuf);
}

void TcpClient::onSockSend() {
	onSend();
}

void TcpClient::onSockErr(const SockException& ex) {
	shutdown();
	onErr(ex);
}

} /* namespace Network */
} /* namespace ZL */
<commit_msg>buf fixed when reconnect<commit_after>/*
 * MIT License
 *
 * Copyright (c) 2016 xiongziliang <771730766@qq.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
#include "TcpClient.h"

namespace ZL {
namespace Network {

TcpClient::TcpClient() : SocketHelper(nullptr) {
}

TcpClient::~TcpClient() {
}

void TcpClient::shutdown() {
    weak_ptr<TcpClient> weakSelf = shared_from_this();
    ASYNC_TRACE([weakSelf,this](){
        auto strongSelf = weakSelf.lock();
        if(!strongSelf){
            return;
        }
        setSock(nullptr);
        _managerTimer.reset();
    });
}

bool TcpClient::alive() {
    bool ret = _sock.operator bool();
    return ret;
}

void TcpClient::startConnect(const string &strUrl, uint16_t iPort,float fTimeOutSec) {
    weak_ptr<TcpClient> weakSelf = shared_from_this();
    ASYNC_TRACE([strUrl,iPort,fTimeOutSec,weakSelf,this](){
        auto strongSelf = weakSelf.lock();
        if(!strongSelf){
            return;
        }
        shutdown();
        SocketHelper::setSock(std::make_shared<Socket>());

        weak_ptr<TcpClient> weakSelf = shared_from_this();
        _sock->connect(strUrl, iPort, [weakSelf](const SockException &err){
            auto strongSelf = weakSelf.lock();
            if(strongSelf){
                if(err){
                    strongSelf->SocketHelper::setSock(nullptr);
                }
                strongSelf->onSockConnect(err);
            }
        }, fTimeOutSec);
    });
}
void TcpClient::onSockConnect(const SockException &ex) {
	if(!ex && _sock) {
        weak_ptr<TcpClient> weakSelf = shared_from_this();
        auto sock_ptr = _sock.get();
        _sock->setOnErr([weakSelf,sock_ptr](const SockException &ex) {
			auto strongSelf = weakSelf.lock();
			if (!strongSelf) {
				return;
			}
			if(sock_ptr != strongSelf->_sock.get()){
                return;
			}
            strongSelf->onSockErr(ex);
		});
        _sock->setOnFlush([weakSelf,sock_ptr]() {
			auto strongSelf = weakSelf.lock();
			if (!strongSelf) {
				return false;
			}
            if(sock_ptr != strongSelf->_sock.get()){
                return false;
            }
            strongSelf->onSockSend();
			return true;
		});
        _sock->setOnRead([weakSelf,sock_ptr](const Buffer::Ptr &pBuf, struct sockaddr *addr) {
			auto strongSelf = weakSelf.lock();
			if (!strongSelf) {
				return;
			}
            if(sock_ptr != strongSelf->_sock.get()){
                return;
            }
            strongSelf->onSockRecv(pBuf);
		});
        _managerTimer.reset(new Timer(2,[weakSelf](){
            auto strongSelf = weakSelf.lock();
            if (!strongSelf) {
                return false;
            }
            strongSelf->onManager();
            return true;
        }));
	}
    onConnect(ex);
}

void TcpClient::onSockRecv(const Buffer::Ptr& pBuf) {
	onRecv(pBuf);
}

void TcpClient::onSockSend() {
	onSend();
}

void TcpClient::onSockErr(const SockException& ex) {
	shutdown();
	onErr(ex);
}

} /* namespace Network */
} /* namespace ZL */
<|endoftext|>