<commit_before>/*************************************************************************
 *
 * Copyright (c) 2012-2013 Kohei Yoshida
 *
 * 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.
 *
 ************************************************************************/

namespace mdds { namespace __mtv {

/**
 * Node that represents the content of each iterator.  The private data part
 * is an implementation detail that should never be accessed externally.
 * What the end position stores in its private data is totally &
 * intentionally undefined.
 */
template<typename _SizeT, typename _ElemBlkT>
struct iterator_value_node
{
    typedef _SizeT size_type;
    typedef _ElemBlkT element_block_type;

    mdds::mtv::element_t type;
    size_type size;
    element_block_type* data;

    iterator_value_node(size_type start_pos, size_type block_index) :
        type(mdds::mtv::element_type_empty), size(0), data(NULL), __private_data(start_pos, block_index) {}

    iterator_value_node(const iterator_value_node& other) :
        type(other.type), size(other.size), data(other.data), __private_data(other.__private_data) {}

    void swap(iterator_value_node& other)
    {
        std::swap(type, other.type);
        std::swap(size, other.size);
        std::swap(data, other.data);

        __private_data.swap(other.__private_data);
    }

    struct private_data
    {
        size_type start_pos;
        size_type block_index;

        private_data() : start_pos(0), block_index(0) {}
        private_data(size_type _start_pos, size_type _block_index) :
            start_pos(_start_pos), block_index(_block_index) {}
        private_data(const private_data& other) :
            start_pos(other.start_pos), block_index(other.block_index) {}

        void swap(private_data& other)
        {
            std::swap(start_pos, other.start_pos);
            std::swap(block_index, other.block_index);
        }
    };
    private_data __private_data;

    bool operator== (const iterator_value_node& other) const
    {
        return type == other.type && size == other.size && data == other.data &&
            __private_data.start_pos == other.__private_data.start_pos &&
            __private_data.block_index == other.__private_data.block_index;
    }

    bool operator!= (const iterator_value_node& other) const
    {
        return !operator== (other);
    }
};

template<typename _NodeT>
struct private_data_no_update
{
    typedef _NodeT node_type;

    static void inc(node_type&) {}
    static void dec(node_type&) {}
};

template<typename _NodeT>
struct private_data_forward_update
{
    typedef _NodeT node_type;

    static void inc(node_type& nd)
    {
        ++nd.__private_data.block_index;
        nd.__private_data.start_pos += nd.size;
    }

    static void dec(node_type& nd)
    {
        --nd.__private_data.block_index;
        nd.__private_data.start_pos -= nd.size;
    }
};

/**
 * Common base for both const and non-const iterators.  Its protected inc()
 * and dec() methods have non-const return type, and the derived classes
 * wrap them and return values with their respective const modifiers.
 */
template<typename _Trait>
class iterator_common_base
{
protected:
    typedef typename _Trait::parent parent_type;
    typedef typename _Trait::blocks blocks_type;
    typedef typename _Trait::base_iterator base_iterator_type;

    typedef typename parent_type::size_type size_type;
    typedef iterator_value_node<size_type, typename parent_type::element_block_type> node;

    iterator_common_base() : m_cur_node(0, 0) {}

    iterator_common_base(
        const base_iterator_type& pos, const base_iterator_type& end,
        size_type start_pos, size_type block_index) :
        m_cur_node(start_pos, block_index),
        m_pos(pos),
        m_end(end)
    {
        if (m_pos != m_end)
            update_node();
    }

    iterator_common_base(const iterator_common_base& other) :
        m_cur_node(other.m_cur_node),
        m_pos(other.m_pos),
        m_end(other.m_end)
    {
    }

    void update_node()
    {
#ifdef MDDS_MULTI_TYPE_VECTOR_DEBUG
        if (m_pos == m_end)
            throw general_error("Current node position should never equal the end position during node update.");
#endif
        // blocks_type::value_type is a pointer to multi_type_vector::block.
        typename blocks_type::value_type blk = *m_pos;
        if (blk->mp_data)
            m_cur_node.type = mdds::mtv::get_block_type(*blk->mp_data);
        else
            m_cur_node.type = mdds::mtv::element_type_empty;

        m_cur_node.size = blk->m_size;
        m_cur_node.data = blk->mp_data;
    }

    node* inc()
    {
        ++m_pos;
        if (m_pos == m_end)
            return NULL;

        update_node();
        return &m_cur_node;
    }

    node* dec()
    {
        --m_pos;
        update_node();
        return &m_cur_node;
    }

    node m_cur_node;
    base_iterator_type m_pos;
    base_iterator_type m_end;

public:
    bool operator== (const iterator_common_base& other) const
    {
        if (m_pos != m_end && other.m_pos != other.m_end)
        {
            // TODO: Set hard-coded values to the current node for the end
            // position nodes to remove this if block.
            if (m_cur_node != other.m_cur_node)
                return false;
        }
        return m_pos == other.m_pos && m_end == other.m_end;
    }

    bool operator!= (const iterator_common_base& other) const
    {
        return !operator==(other);
    }

    iterator_common_base& operator= (const iterator_common_base& other)
    {
        iterator_common_base assigned(other);
        swap(assigned);
        return *this;
    }

    void swap(iterator_common_base& other)
    {
        m_cur_node.swap(other.m_cur_node);
        std::swap(m_pos, other.m_pos);
        std::swap(m_end, other.m_end);
    }
};

template<typename _Trait, typename _NodeUpdateFunc>
class iterator_base : public iterator_common_base<_Trait>
{
    typedef _Trait trait;
    typedef _NodeUpdateFunc node_update_func;
    typedef iterator_common_base<trait> common_base;

    typedef typename trait::base_iterator base_iterator_type;
    typedef typename common_base::size_type size_type;

    using common_base::inc;
    using common_base::dec;
    using common_base::m_cur_node;
    using common_base::m_pos;
    using common_base::m_end;

public:

    // iterator traits
    typedef typename common_base::node value_type;
    typedef value_type* pointer;
    typedef value_type& reference;
    typedef ptrdiff_t   difference_type;
    typedef std::bidirectional_iterator_tag iterator_category;

public:
    iterator_base() {}
    iterator_base(
        const base_iterator_type& pos, const base_iterator_type& end,
        size_type start_pos, size_type block_index) :
        common_base(pos, end, start_pos, block_index) {}

    iterator_base(const iterator_base& other) :
        common_base(other) {}

    value_type& operator*()
    {
        return m_cur_node;
    }

    const value_type& operator*() const
    {
        return m_cur_node;
    }

    value_type* operator->()
    {
        return &m_cur_node;
    }

    const value_type* operator->() const
    {
        return &m_cur_node;
    }

    value_type* operator++()
    {
        node_update_func::inc(m_cur_node);
        return inc();
    }

    value_type* operator--()
    {
        value_type* ret = dec();
        node_update_func::dec(m_cur_node);
        return ret;
    }

    /**
     * These method are public only to allow const_iterator_base to
     * instantiate from iterator_base.
     */
    const base_iterator_type& get_pos() const { return m_pos; }
    const base_iterator_type& get_end() const { return m_end; }
};

template<typename _Trait, typename _NonConstItrBase>
class const_iterator_base : public iterator_common_base<_Trait>
{
    typedef _Trait trait;
    typedef iterator_common_base<trait> common_base;

    typedef typename trait::base_iterator base_iterator_type;
    typedef typename common_base::size_type size_type;

    using common_base::inc;
    using common_base::dec;
    using common_base::m_cur_node;

public:

    typedef _NonConstItrBase iterator_base;

    // iterator traits
    typedef typename common_base::node value_type;
    typedef value_type* pointer;
    typedef value_type& reference;
    typedef ptrdiff_t   difference_type;
    typedef std::bidirectional_iterator_tag iterator_category;

public:
    const_iterator_base() : common_base() {}
    const_iterator_base(
        const base_iterator_type& pos, const base_iterator_type& end,
        size_type start_pos, size_type block_index) :
        common_base(pos, end, start_pos, block_index) {}

    const_iterator_base(const const_iterator_base& other) :
        common_base(other) {}

    /**
     * Take the non-const iterator counterpart to create a const iterator.
     */
    const_iterator_base(const iterator_base& other) :
        common_base(other.get_pos(), other.get_end(), 0, 0) {}

    const value_type& operator*() const
    {
        return m_cur_node;
    }

    const value_type* operator->() const
    {
        return &m_cur_node;
    }

    const value_type* operator++()
    {
        return inc();
    }

    const value_type* operator--()
    {
        return dec();
    }

    bool operator== (const const_iterator_base& other) const
    {
        return iterator_common_base<_Trait>::operator==(other);
    }

    bool operator!= (const const_iterator_base& other) const
    {
        return iterator_common_base<_Trait>::operator!=(other);
    }
};

}}
<commit_msg>I forgot to guard this header.<commit_after>/*************************************************************************
 *
 * Copyright (c) 2012-2013 Kohei Yoshida
 *
 * 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.
 *
 ************************************************************************/

#ifndef MDDS_MULTI_TYPE_VECTOR_ITR_HPP
#define MDDS_MULTI_TYPE_VECTOR_ITR_HPP

#include "multi_type_vector_types.hpp"

namespace mdds { namespace __mtv {

/**
 * Node that represents the content of each iterator.  The private data part
 * is an implementation detail that should never be accessed externally.
 * What the end position stores in its private data is totally &
 * intentionally undefined.
 */
template<typename _SizeT, typename _ElemBlkT>
struct iterator_value_node
{
    typedef _SizeT size_type;
    typedef _ElemBlkT element_block_type;

    mdds::mtv::element_t type;
    size_type size;
    element_block_type* data;

    iterator_value_node(size_type start_pos, size_type block_index) :
        type(mdds::mtv::element_type_empty), size(0), data(NULL), __private_data(start_pos, block_index) {}

    iterator_value_node(const iterator_value_node& other) :
        type(other.type), size(other.size), data(other.data), __private_data(other.__private_data) {}

    void swap(iterator_value_node& other)
    {
        std::swap(type, other.type);
        std::swap(size, other.size);
        std::swap(data, other.data);

        __private_data.swap(other.__private_data);
    }

    struct private_data
    {
        size_type start_pos;
        size_type block_index;

        private_data() : start_pos(0), block_index(0) {}
        private_data(size_type _start_pos, size_type _block_index) :
            start_pos(_start_pos), block_index(_block_index) {}
        private_data(const private_data& other) :
            start_pos(other.start_pos), block_index(other.block_index) {}

        void swap(private_data& other)
        {
            std::swap(start_pos, other.start_pos);
            std::swap(block_index, other.block_index);
        }
    };
    private_data __private_data;

    bool operator== (const iterator_value_node& other) const
    {
        return type == other.type && size == other.size && data == other.data &&
            __private_data.start_pos == other.__private_data.start_pos &&
            __private_data.block_index == other.__private_data.block_index;
    }

    bool operator!= (const iterator_value_node& other) const
    {
        return !operator== (other);
    }
};

template<typename _NodeT>
struct private_data_no_update
{
    typedef _NodeT node_type;

    static void inc(node_type&) {}
    static void dec(node_type&) {}
};

template<typename _NodeT>
struct private_data_forward_update
{
    typedef _NodeT node_type;

    static void inc(node_type& nd)
    {
        ++nd.__private_data.block_index;
        nd.__private_data.start_pos += nd.size;
    }

    static void dec(node_type& nd)
    {
        --nd.__private_data.block_index;
        nd.__private_data.start_pos -= nd.size;
    }
};

/**
 * Common base for both const and non-const iterators.  Its protected inc()
 * and dec() methods have non-const return type, and the derived classes
 * wrap them and return values with their respective const modifiers.
 */
template<typename _Trait>
class iterator_common_base
{
protected:
    typedef typename _Trait::parent parent_type;
    typedef typename _Trait::blocks blocks_type;
    typedef typename _Trait::base_iterator base_iterator_type;

    typedef typename parent_type::size_type size_type;
    typedef iterator_value_node<size_type, typename parent_type::element_block_type> node;

    iterator_common_base() : m_cur_node(0, 0) {}

    iterator_common_base(
        const base_iterator_type& pos, const base_iterator_type& end,
        size_type start_pos, size_type block_index) :
        m_cur_node(start_pos, block_index),
        m_pos(pos),
        m_end(end)
    {
        if (m_pos != m_end)
            update_node();
    }

    iterator_common_base(const iterator_common_base& other) :
        m_cur_node(other.m_cur_node),
        m_pos(other.m_pos),
        m_end(other.m_end)
    {
    }

    void update_node()
    {
#ifdef MDDS_MULTI_TYPE_VECTOR_DEBUG
        if (m_pos == m_end)
            throw general_error("Current node position should never equal the end position during node update.");
#endif
        // blocks_type::value_type is a pointer to multi_type_vector::block.
        typename blocks_type::value_type blk = *m_pos;
        if (blk->mp_data)
            m_cur_node.type = mdds::mtv::get_block_type(*blk->mp_data);
        else
            m_cur_node.type = mdds::mtv::element_type_empty;

        m_cur_node.size = blk->m_size;
        m_cur_node.data = blk->mp_data;
    }

    node* inc()
    {
        ++m_pos;
        if (m_pos == m_end)
            return NULL;

        update_node();
        return &m_cur_node;
    }

    node* dec()
    {
        --m_pos;
        update_node();
        return &m_cur_node;
    }

    node m_cur_node;
    base_iterator_type m_pos;
    base_iterator_type m_end;

public:
    bool operator== (const iterator_common_base& other) const
    {
        if (m_pos != m_end && other.m_pos != other.m_end)
        {
            // TODO: Set hard-coded values to the current node for the end
            // position nodes to remove this if block.
            if (m_cur_node != other.m_cur_node)
                return false;
        }
        return m_pos == other.m_pos && m_end == other.m_end;
    }

    bool operator!= (const iterator_common_base& other) const
    {
        return !operator==(other);
    }

    iterator_common_base& operator= (const iterator_common_base& other)
    {
        iterator_common_base assigned(other);
        swap(assigned);
        return *this;
    }

    void swap(iterator_common_base& other)
    {
        m_cur_node.swap(other.m_cur_node);
        std::swap(m_pos, other.m_pos);
        std::swap(m_end, other.m_end);
    }
};

template<typename _Trait, typename _NodeUpdateFunc>
class iterator_base : public iterator_common_base<_Trait>
{
    typedef _Trait trait;
    typedef _NodeUpdateFunc node_update_func;
    typedef iterator_common_base<trait> common_base;

    typedef typename trait::base_iterator base_iterator_type;
    typedef typename common_base::size_type size_type;

    using common_base::inc;
    using common_base::dec;
    using common_base::m_cur_node;
    using common_base::m_pos;
    using common_base::m_end;

public:

    // iterator traits
    typedef typename common_base::node value_type;
    typedef value_type* pointer;
    typedef value_type& reference;
    typedef ptrdiff_t   difference_type;
    typedef std::bidirectional_iterator_tag iterator_category;

public:
    iterator_base() {}
    iterator_base(
        const base_iterator_type& pos, const base_iterator_type& end,
        size_type start_pos, size_type block_index) :
        common_base(pos, end, start_pos, block_index) {}

    iterator_base(const iterator_base& other) :
        common_base(other) {}

    value_type& operator*()
    {
        return m_cur_node;
    }

    const value_type& operator*() const
    {
        return m_cur_node;
    }

    value_type* operator->()
    {
        return &m_cur_node;
    }

    const value_type* operator->() const
    {
        return &m_cur_node;
    }

    value_type* operator++()
    {
        node_update_func::inc(m_cur_node);
        return inc();
    }

    value_type* operator--()
    {
        value_type* ret = dec();
        node_update_func::dec(m_cur_node);
        return ret;
    }

    /**
     * These method are public only to allow const_iterator_base to
     * instantiate from iterator_base.
     */
    const base_iterator_type& get_pos() const { return m_pos; }
    const base_iterator_type& get_end() const { return m_end; }
};

template<typename _Trait, typename _NonConstItrBase>
class const_iterator_base : public iterator_common_base<_Trait>
{
    typedef _Trait trait;
    typedef iterator_common_base<trait> common_base;

    typedef typename trait::base_iterator base_iterator_type;
    typedef typename common_base::size_type size_type;

    using common_base::inc;
    using common_base::dec;
    using common_base::m_cur_node;

public:

    typedef _NonConstItrBase iterator_base;

    // iterator traits
    typedef typename common_base::node value_type;
    typedef value_type* pointer;
    typedef value_type& reference;
    typedef ptrdiff_t   difference_type;
    typedef std::bidirectional_iterator_tag iterator_category;

public:
    const_iterator_base() : common_base() {}
    const_iterator_base(
        const base_iterator_type& pos, const base_iterator_type& end,
        size_type start_pos, size_type block_index) :
        common_base(pos, end, start_pos, block_index) {}

    const_iterator_base(const const_iterator_base& other) :
        common_base(other) {}

    /**
     * Take the non-const iterator counterpart to create a const iterator.
     */
    const_iterator_base(const iterator_base& other) :
        common_base(other.get_pos(), other.get_end(), 0, 0) {}

    const value_type& operator*() const
    {
        return m_cur_node;
    }

    const value_type* operator->() const
    {
        return &m_cur_node;
    }

    const value_type* operator++()
    {
        return inc();
    }

    const value_type* operator--()
    {
        return dec();
    }

    bool operator== (const const_iterator_base& other) const
    {
        return iterator_common_base<_Trait>::operator==(other);
    }

    bool operator!= (const const_iterator_base& other) const
    {
        return iterator_common_base<_Trait>::operator!=(other);
    }
};

}}

#endif
<|endoftext|>


<commit_before>/**
 * \file
 * \brief Basic UDP receiver
 *
 * \copyright 2012 Omnibius, LLC
 * \author Dmitriy Kargapolov
 * \version 1.0
 * \since 27 May 2012
 *
 */

/*
 * Copyright (c) 2012 Omnibius, LLC
 * Author: Dmitriy Kargapolov <dmitriy.kargapolov@gmail.com>
 * Use, modification and distribution are subject to the Boost Software
 * License, Version 1.0 (See accompanying file LICENSE_1_0.txt or copy
 * at http://www.boost.org/LICENSE_1_0.txt)
 */

#ifndef _UTIL_IO_BASIC_UDP_RECEIVER_HPP_
#define _UTIL_IO_BASIC_UDP_RECEIVER_HPP_

#include <boost/asio.hpp>
#include <util/buffer.hpp>

namespace util {
namespace io {

template <typename Derived, size_t BufSize = 16*1024>
class basic_udp_receiver : private boost::noncopyable {
public:
    typedef basic_io_buffer<BufSize> buffer_type;

    /// Constructor
    basic_udp_receiver(boost::asio::io_service& a_io_service)
        : m_io_service(a_io_service)
        , m_socket(a_io_service)
    {}

    void init(int a_port, size_t a_buf_sz = 0) {
        init(boost::asio::ip::udp::endpoint(
                boost::asio::ip::udp::v4(), a_port),
             a_buf_sz);
    }

    void init(const std::string& a_host, const std::string& a_service, size_t a_buf_sz = 0) {
        boost::asio::ip::udp::resolver l_resolver(m_io_service);
        boost::asio::ip::udp::resolver::query l_query(a_host, a_service);
        boost::asio::ip::udp::endpoint l_ep = *l_resolver.resolve(l_query);
        init(l_ep, a_buf_sz);
    }

    void init(boost::asio::ip::udp::endpoint a_endpoint, size_t a_buf_sz = 0) {
        m_socket.open(a_endpoint.protocol());

        boost::asio::socket_base::reuse_address l_opt(true);
        m_socket.set_option(l_opt);

        if (a_buf_sz) {
            boost::asio::socket_base::send_buffer_size l_opt(a_buf_sz);
            m_socket.set_option(l_opt);
        }

        m_socket.bind(a_endpoint);
    }

    /// Begin reading from socket
    void start()    { m_rx_bytes = 0; async_read(); }
    /// Request to stop
    void stop()     { m_socket.close(); }

    /// Accessor to internal socket
    boost::asio::ip::udp::socket& socket() { return m_socket; }

    /// Total number of bytes received
    size_t rx_bytes() const { return m_rx_bytes; }

private:
    /// Start asynchronous socket read.
    void async_read() {
        m_socket.async_receive_from(m_in_buffer.space(), m_sender_endpoint,
            boost::bind(&basic_udp_receiver::handle_read,
                this, boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred));
    }

    /// Handle completion of a read operation.
    void handle_read(const boost::system::error_code& e, std::size_t n) {
        if (!e && n > 0) {
            m_rx_bytes += n;
            m_in_buffer.commit(n);
            static_cast<Derived*>(this)->on_data(m_in_buffer);
            m_in_buffer.crunch();
            async_read();
        }
    }

    /// The io_service used to perform asynchronous operations.
    boost::asio::io_service& m_io_service;

    /// Socket for basic_udp_receiver
    boost::asio::ip::udp::socket m_socket;

    /// Sender address
    boost::asio::ip::udp::endpoint m_sender_endpoint;

    /// Buffer for incoming data.
    buffer_type m_in_buffer;

    /// Total number of bytes read from socket
    size_t m_rx_bytes;
};

} // namespace io
} // namespace util

#endif // _UTIL_IO_BASIC_UDP_RECEIVER_HPP_
<commit_msg>socket option typo fix<commit_after>/**
 * \file
 * \brief Basic UDP receiver
 *
 * \copyright 2012 Omnibius, LLC
 * \author Dmitriy Kargapolov
 * \version 1.0
 * \since 27 May 2012
 *
 */

/*
 * Copyright (c) 2012 Omnibius, LLC
 * Author: Dmitriy Kargapolov <dmitriy.kargapolov@gmail.com>
 * Use, modification and distribution are subject to the Boost Software
 * License, Version 1.0 (See accompanying file LICENSE_1_0.txt or copy
 * at http://www.boost.org/LICENSE_1_0.txt)
 */

#ifndef _UTIL_IO_BASIC_UDP_RECEIVER_HPP_
#define _UTIL_IO_BASIC_UDP_RECEIVER_HPP_

#include <boost/asio.hpp>
#include <util/buffer.hpp>

namespace util {
namespace io {

template <typename Derived, size_t BufSize = 16*1024>
class basic_udp_receiver : private boost::noncopyable {
public:
    typedef basic_io_buffer<BufSize> buffer_type;

    /// Constructor
    basic_udp_receiver(boost::asio::io_service& a_io_service)
        : m_io_service(a_io_service)
        , m_socket(a_io_service)
    {}

    void init(int a_port, size_t a_buf_sz = 0) {
        init(boost::asio::ip::udp::endpoint(
                boost::asio::ip::udp::v4(), a_port),
             a_buf_sz);
    }

    void init(const std::string& a_host, const std::string& a_service, size_t a_buf_sz = 0) {
        boost::asio::ip::udp::resolver l_resolver(m_io_service);
        boost::asio::ip::udp::resolver::query l_query(a_host, a_service);
        boost::asio::ip::udp::endpoint l_ep = *l_resolver.resolve(l_query);
        init(l_ep, a_buf_sz);
    }

    void init(boost::asio::ip::udp::endpoint a_endpoint, size_t a_buf_sz = 0) {
        m_socket.open(a_endpoint.protocol());

        boost::asio::socket_base::reuse_address l_opt(true);
        m_socket.set_option(l_opt);

        if (a_buf_sz) {
            boost::asio::socket_base::receive_buffer_size l_opt(a_buf_sz);
            m_socket.set_option(l_opt);
        }

        m_socket.bind(a_endpoint);
    }

    /// Begin reading from socket
    void start()    { m_rx_bytes = 0; async_read(); }
    /// Request to stop
    void stop()     { m_socket.close(); }

    /// Accessor to internal socket
    boost::asio::ip::udp::socket& socket() { return m_socket; }

    /// Total number of bytes received
    size_t rx_bytes() const { return m_rx_bytes; }

private:
    /// Start asynchronous socket read.
    void async_read() {
        m_socket.async_receive_from(m_in_buffer.space(), m_sender_endpoint,
            boost::bind(&basic_udp_receiver::handle_read,
                this, boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred));
    }

    /// Handle completion of a read operation.
    void handle_read(const boost::system::error_code& e, std::size_t n) {
        if (!e && n > 0) {
            m_rx_bytes += n;
            m_in_buffer.commit(n);
            static_cast<Derived*>(this)->on_data(m_in_buffer);
            m_in_buffer.crunch();
            async_read();
        }
    }

    /// The io_service used to perform asynchronous operations.
    boost::asio::io_service& m_io_service;

    /// Socket for basic_udp_receiver
    boost::asio::ip::udp::socket m_socket;

    /// Sender address
    boost::asio::ip::udp::endpoint m_sender_endpoint;

    /// Buffer for incoming data.
    buffer_type m_in_buffer;

    /// Total number of bytes read from socket
    size_t m_rx_bytes;
};

} // namespace io
} // namespace util

#endif // _UTIL_IO_BASIC_UDP_RECEIVER_HPP_
<|endoftext|>


<commit_before>/**
 * @file lllocaltextureobject.cpp
 *
 * $LicenseInfo:firstyear=2009&license=viewergpl$
 *
 * Copyright (c) 2009-2009, Linden Research, Inc.
 *
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 *
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at
 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 *
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 *
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "lllocaltextureobject.h"

#include "lltexlayer.h"
#include "llviewertexture.h"
#include "lltextureentry.h"
#include "lluuid.h"
#include "llwearable.h"

LLLocalTextureObject::LLLocalTextureObject() :
	mIsBakedReady(FALSE),
	mDiscard(MAX_DISCARD_LEVEL+1)
{
	mImage = NULL;
}

LLLocalTextureObject::LLLocalTextureObject(LLViewerFetchedTexture* image, const LLUUID& id)
{
	mImage = image;
	gGL.getTexUnit(0)->bind(mImage);
	mID = id;
}

LLLocalTextureObject::LLLocalTextureObject(const LLLocalTextureObject& lto) :
	mImage(lto.mImage),
	mID(lto.mID),
	mIsBakedReady(lto.mIsBakedReady),
	mDiscard(lto.mDiscard)
{
	U32 num_layers = lto.getNumTexLayers();
	mTexLayers.reserve(num_layers);
	for (U32 index = 0; index < num_layers; index++)
	{
		LLTexLayer* original_layer = lto.getTexLayer(index);
		if (!original_layer)
		{
			llerrs << "could not clone Local Texture Object: unable to extract texlayer!" << llendl;
		}

		LLTexLayer* new_layer = new LLTexLayer(*original_layer);
		new_layer->setLTO(this);
		mTexLayers.push_back(new_layer);
	}
}

LLLocalTextureObject::~LLLocalTextureObject()
{
}

LLViewerFetchedTexture* LLLocalTextureObject::getImage() const
{
	return mImage;
}

LLTexLayer* LLLocalTextureObject::getTexLayer(U32 index) const
{
	if (index >= getNumTexLayers())
	{
		return NULL;
	}

	return mTexLayers[index];
}

LLTexLayer* LLLocalTextureObject::getTexLayer(const std::string &name)
{
	for( tex_layer_vec_t::iterator iter = mTexLayers.begin(); iter != mTexLayers.end(); iter++)
	{
		LLTexLayer *layer = *iter;
		if (layer->getName().compare(name) == 0)
		{
			return layer;
		}
	}

	return NULL;
}

U32 LLLocalTextureObject::getNumTexLayers() const
{
	return mTexLayers.size();
}

LLUUID LLLocalTextureObject::getID() const
{
	return mID;
}

S32 LLLocalTextureObject::getDiscard() const
{
	return mDiscard;
}

BOOL LLLocalTextureObject::getBakedReady() const
{
	return mIsBakedReady;
}

void LLLocalTextureObject::setImage(LLViewerFetchedTexture* new_image)
{
	mImage = new_image;
}

BOOL LLLocalTextureObject::setTexLayer(LLTexLayer *new_tex_layer, U32 index)
{
	if (index >= getNumTexLayers() )
	{
		return FALSE;
	}

	if (new_tex_layer == NULL)
	{
		return removeTexLayer(index);
	}

	LLTexLayer *layer = new LLTexLayer(*new_tex_layer);
	layer->setLTO(this);

	if (mTexLayers[index])
	{
		delete mTexLayers[index];
	}
	mTexLayers[index] = layer;

	return TRUE;
}

BOOL LLLocalTextureObject::addTexLayer(LLTexLayer *new_tex_layer, LLWearable *wearable)
{
	if (new_tex_layer == NULL)
	{
		return FALSE;
	}

	LLTexLayer *layer = new LLTexLayer(*new_tex_layer, wearable);
	layer->setLTO(this);
	mTexLayers.push_back(layer);
	return TRUE;
}

BOOL LLLocalTextureObject::addTexLayer(LLTexLayerTemplate *new_tex_layer, LLWearable *wearable)
{
	if (new_tex_layer == NULL)
	{
		return FALSE;
	}

	LLTexLayer *layer = new LLTexLayer(*new_tex_layer, this, wearable);
	layer->setLTO(this);
	mTexLayers.push_back(layer);
	return TRUE;
}

BOOL LLLocalTextureObject::removeTexLayer(U32 index)
{
	if (index >= getNumTexLayers())
	{
		return FALSE;
	}
	tex_layer_vec_t::iterator iter = mTexLayers.begin();
	iter += index;

	delete *iter;
	mTexLayers.erase(iter);
	return TRUE;
}

void LLLocalTextureObject::setID(LLUUID new_id)
{
	mID = new_id;
}

void LLLocalTextureObject::setDiscard(S32 new_discard)
{
	mDiscard = new_discard;
}

void LLLocalTextureObject::setBakedReady(BOOL ready)
{
	mIsBakedReady = ready;
}

<commit_msg>CID-359<commit_after>/**
 * @file lllocaltextureobject.cpp
 *
 * $LicenseInfo:firstyear=2009&license=viewergpl$
 *
 * Copyright (c) 2009-2009, Linden Research, Inc.
 *
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 *
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at
 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 *
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 *
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "lllocaltextureobject.h"

#include "lltexlayer.h"
#include "llviewertexture.h"
#include "lltextureentry.h"
#include "lluuid.h"
#include "llwearable.h"

LLLocalTextureObject::LLLocalTextureObject() :
	mIsBakedReady(FALSE),
	mDiscard(MAX_DISCARD_LEVEL+1)
{
	mImage = NULL;
}

LLLocalTextureObject::LLLocalTextureObject(LLViewerFetchedTexture* image, const LLUUID& id) :
	mIsBakedReady(FALSE),
	mDiscard(MAX_DISCARD_LEVEL+1)
{
	mImage = image;
	gGL.getTexUnit(0)->bind(mImage);
	mID = id;
}

LLLocalTextureObject::LLLocalTextureObject(const LLLocalTextureObject& lto) :
	mImage(lto.mImage),
	mID(lto.mID),
	mIsBakedReady(lto.mIsBakedReady),
	mDiscard(lto.mDiscard)
{
	U32 num_layers = lto.getNumTexLayers();
	mTexLayers.reserve(num_layers);
	for (U32 index = 0; index < num_layers; index++)
	{
		LLTexLayer* original_layer = lto.getTexLayer(index);
		if (!original_layer)
		{
			llerrs << "could not clone Local Texture Object: unable to extract texlayer!" << llendl;
		}

		LLTexLayer* new_layer = new LLTexLayer(*original_layer);
		new_layer->setLTO(this);
		mTexLayers.push_back(new_layer);
	}
}

LLLocalTextureObject::~LLLocalTextureObject()
{
}

LLViewerFetchedTexture* LLLocalTextureObject::getImage() const
{
	return mImage;
}

LLTexLayer* LLLocalTextureObject::getTexLayer(U32 index) const
{
	if (index >= getNumTexLayers())
	{
		return NULL;
	}

	return mTexLayers[index];
}

LLTexLayer* LLLocalTextureObject::getTexLayer(const std::string &name)
{
	for( tex_layer_vec_t::iterator iter = mTexLayers.begin(); iter != mTexLayers.end(); iter++)
	{
		LLTexLayer *layer = *iter;
		if (layer->getName().compare(name) == 0)
		{
			return layer;
		}
	}

	return NULL;
}

U32 LLLocalTextureObject::getNumTexLayers() const
{
	return mTexLayers.size();
}

LLUUID LLLocalTextureObject::getID() const
{
	return mID;
}

S32 LLLocalTextureObject::getDiscard() const
{
	return mDiscard;
}

BOOL LLLocalTextureObject::getBakedReady() const
{
	return mIsBakedReady;
}

void LLLocalTextureObject::setImage(LLViewerFetchedTexture* new_image)
{
	mImage = new_image;
}

BOOL LLLocalTextureObject::setTexLayer(LLTexLayer *new_tex_layer, U32 index)
{
	if (index >= getNumTexLayers() )
	{
		return FALSE;
	}

	if (new_tex_layer == NULL)
	{
		return removeTexLayer(index);
	}

	LLTexLayer *layer = new LLTexLayer(*new_tex_layer);
	layer->setLTO(this);

	if (mTexLayers[index])
	{
		delete mTexLayers[index];
	}
	mTexLayers[index] = layer;

	return TRUE;
}

BOOL LLLocalTextureObject::addTexLayer(LLTexLayer *new_tex_layer, LLWearable *wearable)
{
	if (new_tex_layer == NULL)
	{
		return FALSE;
	}

	LLTexLayer *layer = new LLTexLayer(*new_tex_layer, wearable);
	layer->setLTO(this);
	mTexLayers.push_back(layer);
	return TRUE;
}

BOOL LLLocalTextureObject::addTexLayer(LLTexLayerTemplate *new_tex_layer, LLWearable *wearable)
{
	if (new_tex_layer == NULL)
	{
		return FALSE;
	}

	LLTexLayer *layer = new LLTexLayer(*new_tex_layer, this, wearable);
	layer->setLTO(this);
	mTexLayers.push_back(layer);
	return TRUE;
}

BOOL LLLocalTextureObject::removeTexLayer(U32 index)
{
	if (index >= getNumTexLayers())
	{
		return FALSE;
	}
	tex_layer_vec_t::iterator iter = mTexLayers.begin();
	iter += index;

	delete *iter;
	mTexLayers.erase(iter);
	return TRUE;
}

void LLLocalTextureObject::setID(LLUUID new_id)
{
	mID = new_id;
}

void LLLocalTextureObject::setDiscard(S32 new_discard)
{
	mDiscard = new_discard;
}

void LLLocalTextureObject::setBakedReady(BOOL ready)
{
	mIsBakedReady = ready;
}

<|endoftext|>


<commit_before><commit_msg>Planning: add more debug more in iterative smoother<commit_after><|endoftext|>


<commit_before>#include <papyrus/parser/PapyrusLexer.h>

#include <cctype>
#include <map>

namespace caprica { namespace papyrus { namespace parser {

void PapyrusLexer::setTok(TokenType tp, int consumeChars) {
  cur = Token(tp);
  cur.line = lineNum;
  for (int i = 0; i < consumeChars; i++)
    strm.get();
}

void PapyrusLexer::setTok(Token& tok) {
  cur = tok;
  cur.line = lineNum;
}

static std::map<std::string, TokenType, CaselessStringComparer> keywordMap {
  { "as", TokenType::kAs },
  { "auto", TokenType::kAuto },
  { "autoreadonly", TokenType::kAutoReadOnly },
  { "bool", TokenType::kBool },
  { "else", TokenType::kElse },
  { "elseif", TokenType::kElseIf },
  { "endevent", TokenType::kEndEvent },
  { "endfunction", TokenType::kEndFunction },
  { "endif", TokenType::kEndIf },
  { "endproperty", TokenType::kEndProperty },
  { "endstate", TokenType::kEndState },
  { "endwhile", TokenType::kEndWhile },
  { "event", TokenType::kEvent },
  { "extends", TokenType::kExtends },
  { "false", TokenType::kFalse },
  { "float", TokenType::kFloat },
  { "function", TokenType::kFunction },
  { "global", TokenType::kGlobal },
  { "if", TokenType::kIf },
  { "import", TokenType::kImport },
  { "int", TokenType::kInt },
  { "length", TokenType::kLength },
  { "native", TokenType::kNative },
  { "new", TokenType::kNew },
  { "none", TokenType::kNone },
  { "parent", TokenType::kParent },
  { "property", TokenType::kProperty },
  { "return", TokenType::kReturn },
  { "scriptname", TokenType::kScriptName },
  { "self", TokenType::kSelf },
  { "state", TokenType::kState },
  { "string", TokenType::kString },
  { "true", TokenType::kTrue },
  { "while", TokenType::kWhile },

  // Additional speculative keywords for FO4
  { "const", TokenType::kConst },
  { "endpropertygroup", TokenType::kEndPropertyGroup },
  { "endstruct", TokenType::kEndStruct },
  { "propertygroup", TokenType::kPropertyGroup },
  { "struct", TokenType::kStruct },
  { "var", TokenType::kVar },
};

void PapyrusLexer::consume() {
StartOver:
  auto c = strm.get();

  switch (c) {
    case -1:
      return setTok(TokenType::END);
    case '(':
      return setTok(TokenType::LParen);
    case ')':
      return setTok(TokenType::RParen);
    case '[':
      return setTok(TokenType::LSquare);
    case ']':
      return setTok(TokenType::RSqaure);
    case '.':
      return setTok(TokenType::Dot);
    case ',':
      return setTok(TokenType::Comma);

    case '=':
      if (strm.peek() == '=')
        return setTok(TokenType::CmpEq, 1);
      return setTok(TokenType::Equal);
    case '!':
      if (strm.peek() == '=')
        return setTok(TokenType::CmpNeq, 1);
      return setTok(TokenType::Exclaim);
    case '+':
      if (strm.peek() == '=')
        return setTok(TokenType::PlusEqual, 1);
      return setTok(TokenType::Plus);
    case '-':
      if (strm.peek() == '=')
        return setTok(TokenType::MinusEqual, 1);
      if (isdigit(strm.peek()))
        goto Number;
      return setTok(TokenType::Minus);
    case '*':
      if (strm.peek() == '=')
        return setTok(TokenType::MulEqual, 1);
      return setTok(TokenType::Mul);
    case '/':
      if (strm.peek() == '=')
        return setTok(TokenType::DivEqual, 1);
      return setTok(TokenType::Div);
    case '%':
      if (strm.peek() == '=')
        return setTok(TokenType::ModEqual, 1);
      return setTok(TokenType::Mod);
    case '<':
      if (strm.peek() == '=')
        return setTok(TokenType::CmpLte, 1);
      return setTok(TokenType::CmpLt);
    case '>':
      if (strm.peek() == '=')
        return setTok(TokenType::CmpGte, 1);
      return setTok(TokenType::CmpGt);

    case '|':
      if (strm.peek() != '|')
        fatalError("Bitwise OR is unsupported. Did you intend to use a logical or (\"||\") instead?");
      return setTok(TokenType::LogicalOr);
    case '&':
      if (strm.peek() != '|')
        fatalError("Bitwise AND is unsupported. Did you intend to use a logical and (\"&&\") instead?");
      return setTok(TokenType::LogicalAnd);

    Number:
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
    {
      std::ostringstream str;
      str.put(c);

      // It's hex.
      if (c == '0' && strm.peek() == 'x') {
        str.put(strm.get());
        while (isxdigit(strm.peek()))
          str.put(strm.get());

        auto i = std::stoul(str.str(), nullptr, 16);
        auto tok = Token(TokenType::Integer);
        tok.iValue = (int32_t)i;
        return setTok(tok);
      }

      // Either normal int or float.
      while (isdigit(strm.peek()))
        str.put(strm.get());

      // It's a float.
      if (strm.peek() == '.') {
        str.put(strm.get());
        while (isdigit(strm.peek()))
          str.put(strm.get());

        auto f = std::stof(str.str());
        auto tok = Token(TokenType::Float);
        tok.fValue = f;
        return setTok(tok);
      }

      // It's an integer.
      auto i = std::stoul(str.str());
      auto tok = Token(TokenType::Integer);
      tok.iValue = (int32_t)i;
      return setTok(tok);
    }

    case '_':
    case 'a':
    case 'b':
    case 'c':
    case 'd':
    case 'e':
    case 'f':
    case 'g':
    case 'h':
    case 'i':
    case 'j':
    case 'k':
    case 'l':
    case 'm':
    case 'n':
    case 'o':
    case 'p':
    case 'q':
    case 'r':
    case 's':
    case 't':
    case 'u':
    case 'v':
    case 'w':
    case 'x':
    case 'y':
    case 'z':
    case 'A':
    case 'B':
    case 'C':
    case 'D':
    case 'E':
    case 'F':
    case 'G':
    case 'H':
    case 'I':
    case 'J':
    case 'K':
    case 'L':
    case 'M':
    case 'N':
    case 'O':
    case 'P':
    case 'Q':
    case 'R':
    case 'S':
    case 'T':
    case 'U':
    case 'V':
    case 'W':
    case 'X':
    case 'Y':
    case 'Z':
    {
      std::ostringstream str;
      str.put(c);

      while (isalnum(strm.peek()) || strm.peek() == '_')
        str.put(strm.get());

      auto ident = str.str();
      auto f = keywordMap.find(ident);
      if (f != keywordMap.end())
        return setTok(f->second);

      auto tok = Token(TokenType::Identifier);
      tok.sValue = ident;
      return setTok(tok);
    }

    case '"':
    {
      std::ostringstream str;

      while (strm.peek() != '"' && strm.peek() != '\r' && strm.peek() != '\n' && strm.peek() != -1) {
        if (strm.peek() == '\\') {
          strm.get();
          auto escapeChar = strm.get();
          switch (escapeChar) {
            case 'n':
              str.put('\n');
              break;
            case 't':
              str.put('\t');
              break;
            case '\\':
              str.put('\\');
              break;
            case '"':
              str.put('"');
              break;
            case -1:
              fatalError("Unexpected EOF before the end of the string.");
            default:
              fatalError((std::string)"Unrecognized escape sequence: '\\" + (char)escapeChar + "'");
          }
        }
      }

      if (strm.peek() != '"')
        fatalError("Unclosed string!");
      strm.get();

      auto tok = Token(TokenType::String);
      tok.sValue = str.str();
      return setTok(tok);
    }

    case ';':
    {
      if (strm.peek() == '/') {
        // Multiline comment.
        strm.get();

        while (strm.peek() != -1) {
          if (strm.peek() == '\r' || strm.peek() == '\n') {
            auto c2 = strm.get();
            if (c2 == '\r' && strm.peek() == '\n')
              strm.get();
            lineNum++;
          }

          if (strm.get() == '/' && strm.peek() == ';') {
            strm.get();
            goto StartOver;
          }
        }

        fatalError("Unexpected EOF before the end of a multiline comment!");
      }

      // Single line comment.
      while (strm.peek() != '\r' && strm.peek() != '\n' && strm.peek() != -1)
        strm.get();
      goto StartOver;
    }

    case '{':
    {
      std::ostringstream str;

      while (strm.peek() != '}' && strm.peek() != -1)
        str.put(strm.get());

      if (strm.peek() == -1)
        fatalError("Unexpected EOF before the end of a documentation comment!");
      strm.get();

      auto tok = Token(TokenType::DocComment);
      tok.sValue = str.str();
      return setTok(tok);
    }

    case '\\':
    {
      consume();
      if (cur.type != TokenType::EOL)
        fatalError("Unexpected '\'! Division is done with a forward slash '/'.");
      goto StartOver;
    }

    case '\r':
    case '\n':
    {
      if (c == '\r' && strm.peek() == '\n')
        strm.get();
      lineNum++;
      return setTok(TokenType::EOL);
    }

    case ' ':
    case '\t':
    {
      while (strm.peek() == ' ' || strm.peek() == '\t')
        strm.get();
      goto StartOver;
    }

    default:
      fatalError((std::string)"Unexpected character '" + (char)c + "'!");
  }
}

}}}
<commit_msg>Trim the leading and trailing whitespace from documentation comments, and only emit unix newlines inside of them, even if a windows newline was provided.<commit_after>#include <papyrus/parser/PapyrusLexer.h>

#include <cctype>
#include <map>

namespace caprica { namespace papyrus { namespace parser {

void PapyrusLexer::setTok(TokenType tp, int consumeChars) {
  cur = Token(tp);
  cur.line = lineNum;
  for (int i = 0; i < consumeChars; i++)
    strm.get();
}

void PapyrusLexer::setTok(Token& tok) {
  cur = tok;
  cur.line = lineNum;
}

static std::map<std::string, TokenType, CaselessStringComparer> keywordMap {
  { "as", TokenType::kAs },
  { "auto", TokenType::kAuto },
  { "autoreadonly", TokenType::kAutoReadOnly },
  { "bool", TokenType::kBool },
  { "else", TokenType::kElse },
  { "elseif", TokenType::kElseIf },
  { "endevent", TokenType::kEndEvent },
  { "endfunction", TokenType::kEndFunction },
  { "endif", TokenType::kEndIf },
  { "endproperty", TokenType::kEndProperty },
  { "endstate", TokenType::kEndState },
  { "endwhile", TokenType::kEndWhile },
  { "event", TokenType::kEvent },
  { "extends", TokenType::kExtends },
  { "false", TokenType::kFalse },
  { "float", TokenType::kFloat },
  { "function", TokenType::kFunction },
  { "global", TokenType::kGlobal },
  { "if", TokenType::kIf },
  { "import", TokenType::kImport },
  { "int", TokenType::kInt },
  { "length", TokenType::kLength },
  { "native", TokenType::kNative },
  { "new", TokenType::kNew },
  { "none", TokenType::kNone },
  { "parent", TokenType::kParent },
  { "property", TokenType::kProperty },
  { "return", TokenType::kReturn },
  { "scriptname", TokenType::kScriptName },
  { "self", TokenType::kSelf },
  { "state", TokenType::kState },
  { "string", TokenType::kString },
  { "true", TokenType::kTrue },
  { "while", TokenType::kWhile },

  // Additional speculative keywords for FO4
  { "const", TokenType::kConst },
  { "endpropertygroup", TokenType::kEndPropertyGroup },
  { "endstruct", TokenType::kEndStruct },
  { "propertygroup", TokenType::kPropertyGroup },
  { "struct", TokenType::kStruct },
  { "var", TokenType::kVar },
};

void PapyrusLexer::consume() {
StartOver:
  auto c = strm.get();

  switch (c) {
    case -1:
      return setTok(TokenType::END);
    case '(':
      return setTok(TokenType::LParen);
    case ')':
      return setTok(TokenType::RParen);
    case '[':
      return setTok(TokenType::LSquare);
    case ']':
      return setTok(TokenType::RSqaure);
    case '.':
      return setTok(TokenType::Dot);
    case ',':
      return setTok(TokenType::Comma);

    case '=':
      if (strm.peek() == '=')
        return setTok(TokenType::CmpEq, 1);
      return setTok(TokenType::Equal);
    case '!':
      if (strm.peek() == '=')
        return setTok(TokenType::CmpNeq, 1);
      return setTok(TokenType::Exclaim);
    case '+':
      if (strm.peek() == '=')
        return setTok(TokenType::PlusEqual, 1);
      return setTok(TokenType::Plus);
    case '-':
      if (strm.peek() == '=')
        return setTok(TokenType::MinusEqual, 1);
      if (isdigit(strm.peek()))
        goto Number;
      return setTok(TokenType::Minus);
    case '*':
      if (strm.peek() == '=')
        return setTok(TokenType::MulEqual, 1);
      return setTok(TokenType::Mul);
    case '/':
      if (strm.peek() == '=')
        return setTok(TokenType::DivEqual, 1);
      return setTok(TokenType::Div);
    case '%':
      if (strm.peek() == '=')
        return setTok(TokenType::ModEqual, 1);
      return setTok(TokenType::Mod);
    case '<':
      if (strm.peek() == '=')
        return setTok(TokenType::CmpLte, 1);
      return setTok(TokenType::CmpLt);
    case '>':
      if (strm.peek() == '=')
        return setTok(TokenType::CmpGte, 1);
      return setTok(TokenType::CmpGt);

    case '|':
      if (strm.peek() != '|')
        fatalError("Bitwise OR is unsupported. Did you intend to use a logical or (\"||\") instead?");
      return setTok(TokenType::LogicalOr);
    case '&':
      if (strm.peek() != '|')
        fatalError("Bitwise AND is unsupported. Did you intend to use a logical and (\"&&\") instead?");
      return setTok(TokenType::LogicalAnd);

    Number:
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
    {
      std::ostringstream str;
      str.put(c);

      // It's hex.
      if (c == '0' && strm.peek() == 'x') {
        str.put(strm.get());
        while (isxdigit(strm.peek()))
          str.put(strm.get());

        auto i = std::stoul(str.str(), nullptr, 16);
        auto tok = Token(TokenType::Integer);
        tok.iValue = (int32_t)i;
        return setTok(tok);
      }

      // Either normal int or float.
      while (isdigit(strm.peek()))
        str.put(strm.get());

      // It's a float.
      if (strm.peek() == '.') {
        str.put(strm.get());
        while (isdigit(strm.peek()))
          str.put(strm.get());

        auto f = std::stof(str.str());
        auto tok = Token(TokenType::Float);
        tok.fValue = f;
        return setTok(tok);
      }

      // It's an integer.
      auto i = std::stoul(str.str());
      auto tok = Token(TokenType::Integer);
      tok.iValue = (int32_t)i;
      return setTok(tok);
    }

    case '_':
    case 'a':
    case 'b':
    case 'c':
    case 'd':
    case 'e':
    case 'f':
    case 'g':
    case 'h':
    case 'i':
    case 'j':
    case 'k':
    case 'l':
    case 'm':
    case 'n':
    case 'o':
    case 'p':
    case 'q':
    case 'r':
    case 's':
    case 't':
    case 'u':
    case 'v':
    case 'w':
    case 'x':
    case 'y':
    case 'z':
    case 'A':
    case 'B':
    case 'C':
    case 'D':
    case 'E':
    case 'F':
    case 'G':
    case 'H':
    case 'I':
    case 'J':
    case 'K':
    case 'L':
    case 'M':
    case 'N':
    case 'O':
    case 'P':
    case 'Q':
    case 'R':
    case 'S':
    case 'T':
    case 'U':
    case 'V':
    case 'W':
    case 'X':
    case 'Y':
    case 'Z':
    {
      std::ostringstream str;
      str.put(c);

      while (isalnum(strm.peek()) || strm.peek() == '_')
        str.put(strm.get());

      auto ident = str.str();
      auto f = keywordMap.find(ident);
      if (f != keywordMap.end())
        return setTok(f->second);

      auto tok = Token(TokenType::Identifier);
      tok.sValue = ident;
      return setTok(tok);
    }

    case '"':
    {
      std::ostringstream str;

      while (strm.peek() != '"' && strm.peek() != '\r' && strm.peek() != '\n' && strm.peek() != -1) {
        if (strm.peek() == '\\') {
          strm.get();
          auto escapeChar = strm.get();
          switch (escapeChar) {
            case 'n':
              str.put('\n');
              break;
            case 't':
              str.put('\t');
              break;
            case '\\':
              str.put('\\');
              break;
            case '"':
              str.put('"');
              break;
            case -1:
              fatalError("Unexpected EOF before the end of the string.");
            default:
              fatalError((std::string)"Unrecognized escape sequence: '\\" + (char)escapeChar + "'");
          }
        }
      }

      if (strm.peek() != '"')
        fatalError("Unclosed string!");
      strm.get();

      auto tok = Token(TokenType::String);
      tok.sValue = str.str();
      return setTok(tok);
    }

    case ';':
    {
      if (strm.peek() == '/') {
        // Multiline comment.
        strm.get();

        while (strm.peek() != -1) {
          if (strm.peek() == '\r' || strm.peek() == '\n') {
            auto c2 = strm.get();
            if (c2 == '\r' && strm.peek() == '\n')
              strm.get();
            lineNum++;
          }

          if (strm.get() == '/' && strm.peek() == ';') {
            strm.get();
            goto StartOver;
          }
        }

        fatalError("Unexpected EOF before the end of a multiline comment!");
      }

      // Single line comment.
      while (strm.peek() != '\r' && strm.peek() != '\n' && strm.peek() != -1)
        strm.get();
      goto StartOver;
    }

    case '{':
    {
      std::ostringstream str;

      // Trim all leading whitespace.
      while (isspace(strm.peek()))
        strm.get();

      while (strm.peek() != '}' && strm.peek() != -1) {
        // For sanity reasons, we only put out unix newlines in the
        // doc comment string.
        auto c2 = strm.get();
        if (c2 == '\r' && strm.peek() == '\n') {
          strm.get();
          str.put('\n');
        } else {
          // Whether this is a Unix newline, or a normal character,
          // we don't care, they both get written as-is.
          str.put(c2);
        }
      }

      if (strm.peek() == -1)
        fatalError("Unexpected EOF before the end of a documentation comment!");
      strm.get();

      auto tok = Token(TokenType::DocComment);
      tok.sValue = str.str();
      // Trim trailing whitespace.
      if (tok.sValue.length())
        tok.sValue = tok.sValue.substr(0, tok.sValue.find_last_not_of(" \t\n\v\f\r") + 1);
      return setTok(tok);
    }

    case '\\':
    {
      consume();
      if (cur.type != TokenType::EOL)
        fatalError("Unexpected '\'! Division is done with a forward slash '/'.");
      goto StartOver;
    }

    case '\r':
    case '\n':
    {
      if (c == '\r' && strm.peek() == '\n')
        strm.get();
      lineNum++;
      return setTok(TokenType::EOL);
    }

    case ' ':
    case '\t':
    {
      while (strm.peek() == ' ' || strm.peek() == '\t')
        strm.get();
      goto StartOver;
    }

    default:
      fatalError((std::string)"Unexpected character '" + (char)c + "'!");
  }
}

}}}
<|endoftext|>


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

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkArchetypeSeriesFileNames.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

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

=========================================================================*/
#ifndef _itkArchetypeSeriesFileNames_h
#define _itkArchetypeSeriesFileNames_h

#ifdef _MSC_VER
#pragma warning ( disable : 4786 )
#endif

#include "itkArchetypeSeriesFileNames.h"
#include "itkRegularExpressionSeriesFileNames.h"
#include <itksys/SystemTools.hxx>
#include <stdio.h>
#include <algorithm>

namespace itk
{

ArchetypeSeriesFileNames
::ArchetypeSeriesFileNames() :
  m_Archetype("")
{
}

void
ArchetypeSeriesFileNames
::SetArchetype( const std::string &archetype )
{
  if (archetype != m_Archetype)
    {
    m_Archetype = archetype;
    this->Modified();
    m_ArchetypeMTime.Modified();
    }
}

unsigned int
ArchetypeSeriesFileNames
::GetNumberOfGroupings()
{
  if (m_ScanTime < m_ArchetypeMTime)
    {
    this->Scan();
    }

  return m_Groupings.size();
}

const std::vector<std::string> &
ArchetypeSeriesFileNames
::GetFileNames(unsigned int group)
{
  if (m_ScanTime < m_ArchetypeMTime)
    {
    this->Scan();
    }

  if (group < m_Groupings.size())
    {
    m_FileNames = m_Groupings[group];
    }
  else
    {
    m_FileNames.clear();
    }

  return m_FileNames;
}

void
ArchetypeSeriesFileNames
::Scan()
{
  // For each group of contiguous numbers in m_Archetype, create a
  // regular expression that is identical to m_Archetype except that
  // it replaces that group of numbers with the pattern ([0-9]+).
  // Each of these new strings will then be passed into a
  // RegularExpressionSeriesFileNames to generate the list of those
  // files that fit that pattern.

  m_Groupings.clear();

  std::string unixArchetype = m_Archetype;
  itksys::SystemTools::ConvertToUnixSlashes(unixArchetype);

  if (itksys::SystemTools::FileIsDirectory( unixArchetype.c_str() ))
    {
    return;
    }

  // Parse the fileNameName and fileNamePath
  std::string fileName = itksys::SystemTools::GetFilenameName( unixArchetype.c_str() );
  std::string fileNamePath = itksys::SystemTools::GetFilenamePath( unixArchetype.c_str() );
  std::string pathPrefix;

  // If there is no "/" in the name, the directory is not specified.
  // In that case, use the default ".".  This is necessary for the RegularExpressionSeriesFileNames.
  if (fileNamePath == "")
    {
    fileNamePath = ".";
    pathPrefix = "./";
    }
  else
    {
    pathPrefix = "";
    }

  std::vector < std::string > regExpFileNameVector;
  std::string regExpString = "([0-9]+)";
  std::vector < int > numGroupStart;
  std::vector < int > numGroupLength;
  int sIndex;
  std::string::iterator sit;
  for (sit = fileName.begin(); sit < fileName.end(); sit++)
    {
    // If the element is a number, find its starting index and length.
    if ((*sit) >= '0' && (*sit) <= '9')
      {
      sIndex = sit - fileName.begin();
      numGroupStart.push_back( sIndex );

      // Loop to one past the end of the group of numbers.
      while ((*sit) >= '0' && (*sit) <= '9' && sit != fileName.end() )
        {
        ++sit;
        }

      numGroupLength.push_back( (sit - fileName.begin()) - sIndex );
      }
    }

  // Create a set of regular expressions, one for each group of
  // numbers in m_FileName. We walk the regular expression groups
  // from right to left since numbers at the end of filenames are more
  // likely to be image numbers.
  int i;
  for (i = (int)numGroupLength.size()-1 ; i >= 0; i--)
    {
    std::string regExpFileName = fileName;

    regExpFileName.replace(numGroupStart[i],numGroupLength[i],regExpString);
    regExpFileName = "^" + regExpFileName + "$";
    regExpFileNameVector.push_back( regExpFileName );
    }

  // Use a RegularExpressionSeriesFileNames to find the files to return
  std::vector<std::string> names;

  for (i = 0; i < (int) regExpFileNameVector.size(); i++)
    {
    itk::RegularExpressionSeriesFileNames::Pointer fit = itk::RegularExpressionSeriesFileNames::New();
    fit->SetDirectory( fileNamePath.c_str() );
    fit->SetRegularExpression( regExpFileNameVector[i].c_str() );
    fit->SetSubMatch(1);
    fit->NumericSortOn();
    names = fit->GetFileNames();

    std::vector<std::string>::iterator ait;
    ait = std::find(names.begin(), names.end(), pathPrefix + unixArchetype);

    // Accept the list if it contains the archetype and is not the
    // "trivial" list (containing only the archetype)
    if ( ait != names.end() && names.size() > 1)
      {
      m_Groupings.push_back(names);
      }
    }

  // if the group list is empty, create a single group containing the
  // archetype
  if ( m_Groupings.size() == 0 && itksys::SystemTools::FileExists(unixArchetype.c_str()))
    {
    std::vector<std::string> tlist;

    tlist.push_back( unixArchetype );
    m_Groupings.push_back( tlist );
    }

  m_ScanTime.Modified();
}

void
ArchetypeSeriesFileNames
::PrintSelf(std::ostream& os, Indent indent) const
{
  Superclass::PrintSelf(os, indent);

  os << indent << "Archetype: " << m_Archetype << std::endl;
  os << indent << "Number of groupings: "
     << const_cast<ArchetypeSeriesFileNames*>(this)->GetNumberOfGroupings() << std::endl;

  for (unsigned int j = 0; j < const_cast<ArchetypeSeriesFileNames*>(this)->GetNumberOfGroupings(); j++)
    {
    os << indent << "Grouping #" << j << std::endl;
    std::vector<std::string> group = const_cast<ArchetypeSeriesFileNames*>(this)->GetFileNames(j);
    for (unsigned int i = 0; i < group.size(); i++)
      {
      os << indent << indent << "Filenames[" << i << "]: " << group[i] << std::endl;
      }
    }
}
} //namespace ITK

#endif
<commit_msg>ENH: Allow filenames that include special characters<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkArchetypeSeriesFileNames.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

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

=========================================================================*/
#ifndef _itkArchetypeSeriesFileNames_h
#define _itkArchetypeSeriesFileNames_h

#ifdef _MSC_VER
#pragma warning ( disable : 4786 )
#endif

#include "itkArchetypeSeriesFileNames.h"
#include "itkRegularExpressionSeriesFileNames.h"
#include <itksys/SystemTools.hxx>
#include <stdio.h>
#include <algorithm>

namespace itk
{

ArchetypeSeriesFileNames
::ArchetypeSeriesFileNames() :
  m_Archetype("")
{
}

void
ArchetypeSeriesFileNames
::SetArchetype( const std::string &archetype )
{
  if (archetype != m_Archetype)
    {
    m_Archetype = archetype;
    this->Modified();
    m_ArchetypeMTime.Modified();
    }
}

unsigned int
ArchetypeSeriesFileNames
::GetNumberOfGroupings()
{
  if (m_ScanTime < m_ArchetypeMTime)
    {
    this->Scan();
    }

  return m_Groupings.size();
}

const std::vector<std::string> &
ArchetypeSeriesFileNames
::GetFileNames(unsigned int group)
{
  if (m_ScanTime < m_ArchetypeMTime)
    {
    this->Scan();
    }

  if (group < m_Groupings.size())
    {
    m_FileNames = m_Groupings[group];
    }
  else
    {
    m_FileNames.clear();
    }

  return m_FileNames;
}

void
ArchetypeSeriesFileNames
::Scan()
{
  // For each group of contiguous numbers in m_Archetype, create a
  // regular expression that is identical to m_Archetype except that
  // it replaces that group of numbers with the pattern ([0-9]+).
  // Each of these new strings will then be passed into a
  // RegularExpressionSeriesFileNames to generate the list of those
  // files that fit that pattern.

  m_Groupings.clear();

  std::string unixArchetype = m_Archetype;
  itksys::SystemTools::ConvertToUnixSlashes(unixArchetype);

  if (itksys::SystemTools::FileIsDirectory( unixArchetype.c_str() ))
    {
    return;
    }

  // Parse the fileNameName and fileNamePath
  std::string origFileName = itksys::SystemTools::GetFilenameName( unixArchetype.c_str() );
  std::string fileNamePath = itksys::SystemTools::GetFilenamePath( unixArchetype.c_str() );
  std::string pathPrefix;

  // "Clean" the filename by escaping any special characters with backslashes.
  // This allows us to pass in filenames that include these special characters.
  std::string fileName;
  for( unsigned int j = 0; j < origFileName.length(); j++ )
    {
    char oneChar = origFileName[j];
    if( oneChar == '^' ||
        oneChar == '$' ||
        oneChar == '.' ||
        oneChar == '[' ||
        oneChar == ']' ||
        oneChar == '-' ||
        oneChar == '*' ||
        oneChar == '+' ||
        oneChar == '?' ||
        oneChar == '(' ||
        oneChar == ')' )
      {
      fileName += "\\";
      }
    fileName += oneChar;
    }

  // If there is no "/" in the name, the directory is not specified.
  // In that case, use the default ".".  This is necessary for the RegularExpressionSeriesFileNames.
  if (fileNamePath == "")
    {
    fileNamePath = ".";
    pathPrefix = "./";
    }
  else
    {
    pathPrefix = "";
    }

  std::vector < std::string > regExpFileNameVector;
  std::string regExpString = "([0-9]+)";
  std::vector < int > numGroupStart;
  std::vector < int > numGroupLength;
  int sIndex;
  std::string::iterator sit;
  for (sit = fileName.begin(); sit < fileName.end(); sit++)
    {
    // If the element is a number, find its starting index and length.
    if ((*sit) >= '0' && (*sit) <= '9')
      {
      sIndex = sit - fileName.begin();
      numGroupStart.push_back( sIndex );

      // Loop to one past the end of the group of numbers.
      while ((*sit) >= '0' && (*sit) <= '9' && sit != fileName.end() )
        {
        ++sit;
        }

      numGroupLength.push_back( (sit - fileName.begin()) - sIndex );
      }
    }

  // Create a set of regular expressions, one for each group of
  // numbers in m_FileName. We walk the regular expression groups
  // from right to left since numbers at the end of filenames are more
  // likely to be image numbers.
  // It is also necessary to walk backward so that the numGroupStart
  // indices remain correct since the length of numbers we are replacing may
  // be different from the length of regExpString.
  int i;
  for (i = (int)numGroupLength.size()-1 ; i >= 0; i--)
    {
    std::string regExpFileName = fileName;

    regExpFileName.replace(numGroupStart[i],numGroupLength[i],regExpString);
    // Include only filenames that exactly match this regular expression.  Don't
    // match filenames that have this string as a substring (ie. that have extra
    // prefixes or suffixes).
    regExpFileName = "^" + regExpFileName + "$";
    regExpFileNameVector.push_back( regExpFileName );
    }

  // Use a RegularExpressionSeriesFileNames to find the files to return
  std::vector<std::string> names;

  for (i = 0; i < (int) regExpFileNameVector.size(); i++)
    {
    itk::RegularExpressionSeriesFileNames::Pointer fit = itk::RegularExpressionSeriesFileNames::New();
    fit->SetDirectory( fileNamePath.c_str() );
    fit->SetRegularExpression( regExpFileNameVector[i].c_str() );
    fit->SetSubMatch(1);
    fit->NumericSortOn();
    names = fit->GetFileNames();

    std::vector<std::string>::iterator ait;
    ait = std::find(names.begin(), names.end(), pathPrefix + unixArchetype);

    // Accept the list if it contains the archetype and is not the
    // "trivial" list (containing only the archetype)
    if ( ait != names.end() && names.size() > 1)
      {
      m_Groupings.push_back(names);
      }
    }

  // If the group list is empty, create a single group containing the
  // archetype.
  if ( m_Groupings.size() == 0 && itksys::SystemTools::FileExists(unixArchetype.c_str()))
    {
    std::vector<std::string> tlist;

    tlist.push_back( unixArchetype );
    m_Groupings.push_back( tlist );
    }

  m_ScanTime.Modified();
}

void
ArchetypeSeriesFileNames
::PrintSelf(std::ostream& os, Indent indent) const
{
  Superclass::PrintSelf(os, indent);

  os << indent << "Archetype: " << m_Archetype << std::endl;
  os << indent << "Number of groupings: "
     << const_cast<ArchetypeSeriesFileNames*>(this)->GetNumberOfGroupings() << std::endl;

  for (unsigned int j = 0; j < const_cast<ArchetypeSeriesFileNames*>(this)->GetNumberOfGroupings(); j++)
    {
    os << indent << "Grouping #" << j << std::endl;
    std::vector<std::string> group = const_cast<ArchetypeSeriesFileNames*>(this)->GetFileNames(j);
    for (unsigned int i = 0; i < group.size(); i++)
      {
      os << indent << indent << "Filenames[" << i << "]: " << group[i] << std::endl;
      }
    }
}
} //namespace ITK

#endif
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: filecopy.cxx,v $
 * $Revision: 1.9 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_tools.hxx"

#if defined WNT
#ifndef _SVWIN_H
#include <io.h>
#include <tools/svwin.h>
#endif

#elif defined UNX
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>

#endif

#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

#include <stdio.h>
#include "comdep.hxx"
#include <tools/fsys.hxx>
#include <tools/stream.hxx>
#include <osl/file.hxx>

using namespace ::osl;

/*************************************************************************
|*
|*    FileCopier::FileCopier()
|*
|*    Beschreibung      FSYS.SDW
|*    Ersterstellung    MI 13.04.94
|*    Letzte Aenderung  MI 13.04.94
|*
*************************************************************************/

FileCopier::FileCopier() :

    nBytesTotal ( 0 ),
    nBytesCopied( 0 ),
    nBlockSize  ( 4096 ),
    pImp        ( new FileCopier_Impl )

{
}

// -----------------------------------------------------------------------

FileCopier::FileCopier( const DirEntry& rSource, const DirEntry& rTarget ) :

    aSource     ( rSource ),
    aTarget     ( rTarget ),
    nBytesTotal ( 0 ),
    nBytesCopied( 0 ),
    nBlockSize  ( 4096 ),
    pImp        ( new FileCopier_Impl )

{
}

// -----------------------------------------------------------------------

FileCopier::FileCopier( const FileCopier& rCopier ) :

    aSource         ( rCopier.aSource ),
    aTarget         ( rCopier.aTarget ),
    nBytesTotal     ( 0 ),
    nBytesCopied    ( 0 ),
    aProgressLink   ( rCopier.aProgressLink ),
    nBlockSize      ( 4096 ),
    pImp            ( new FileCopier_Impl )

{
}

/*************************************************************************
|*
|*    FileCopier::~FileCopier()
|*
|*    Beschreibung      FSYS.SDW
|*    Ersterstellung    MI 13.04.94
|*    Letzte Aenderung  MI 13.04.94
|*
*************************************************************************/

FileCopier::~FileCopier()
{
    delete pImp;
}

/*************************************************************************
|*
|*    FileCopier::operator =()
|*
|*    Beschreibung      FSYS.SDW
|*    Ersterstellung    MI 13.04.94
|*    Letzte Aenderung  MI 13.04.94
|*
*************************************************************************/

FileCopier& FileCopier::operator = ( const FileCopier &rCopier )
{
    aSource = rCopier.aSource;
    aTarget = rCopier.aTarget;
    nBytesTotal = rCopier.nBytesTotal;
    nBytesCopied = rCopier.nBytesCopied;
    nBytesCopied = rCopier.nBytesCopied;
    nBlockSize = rCopier.nBlockSize;
    aProgressLink = rCopier.aProgressLink;
    *pImp = *(rCopier.pImp);
    return *this;
}

/*************************************************************************
|*
|*    FileCopier::Progress()
|*
|*    Beschreibung      FSYS.SDW
|*    Ersterstellung    MI 13.04.94
|*    Letzte Aenderung  MI 13.04.94
|*
*************************************************************************/

BOOL FileCopier::Progress()
{
    if ( !aProgressLink )
        return TRUE;
    else
    {
        if ( aProgressLink.Call( this ) )
            return TRUE;
        return ( 0 == Error( ERRCODE_ABORT, 0, 0 ) );
    }
}

//---------------------------------------------------------------------------

ErrCode FileCopier::Error( ErrCode eErr, const DirEntry* pSource, const DirEntry* pTarget )
{
    // kein Fehler oder kein ErrorHandler?
    if ( !eErr || !pImp->aErrorLink )
        // => Error beibehalten
        return eErr;

    // sonst gesetzten ErrorHandler fragen
    pImp->pErrSource = pSource;
    pImp->pErrTarget = pTarget;
    pImp->eErr = eErr;
    ErrCode eRet = (ErrCode) pImp->aErrorLink.Call( this );
    pImp->pErrSource = 0;
    pImp->pErrTarget = 0;
    return eRet;
}

//---------------------------------------------------------------------------

const DirEntry* FileCopier::GetErrorSource() const
{
    return pImp->pErrSource;
}

//---------------------------------------------------------------------------

const DirEntry* FileCopier::GetErrorTarget() const
{
    return pImp->pErrTarget;
}

//---------------------------------------------------------------------------

ErrCode FileCopier::GetError() const
{
    return pImp->eErr;
}

//---------------------------------------------------------------------------

void FileCopier::SetErrorHdl( const Link &rLink )
{
    pImp->aErrorLink = rLink;
}

//---------------------------------------------------------------------------

const Link& FileCopier::GetErrorHdl() const
{
    return pImp->aErrorLink ;
}

/*************************************************************************
|*
|*    FileCopier::Execute()
|*
|*    Beschreibung      FSYS.SDW
|*    Ersterstellung    MI 13.04.94
|*    Letzte Aenderung  PB 16.06.00
|*
*************************************************************************/

FSysError FileCopier::DoCopy_Impl(
    const DirEntry &rSource, const DirEntry &rTarget )
{
    FSysError eRet = FSYS_ERR_OK;
    ErrCode eWarn = FSYS_ERR_OK;

    // HPFS->FAT?
    FSysPathStyle eSourceStyle = DirEntry::GetPathStyle( rSource.ImpGetTopPtr()->GetName() );
    FSysPathStyle eTargetStyle = DirEntry::GetPathStyle( rTarget.ImpGetTopPtr()->GetName() );
    BOOL bMakeShortNames = ( eSourceStyle == FSYS_STYLE_HPFS && eTargetStyle == FSYS_STYLE_FAT );

    // Zieldateiname ggf. kuerzen
    DirEntry aTgt;
    if ( bMakeShortNames )
    {
        aTgt = rTarget.GetPath();
        aTgt.MakeShortName( rTarget.GetName() );
    }
    else
        aTgt = rTarget;

    // kein Move wenn Namen gekuerzt werden muessten
    if ( bMakeShortNames && FSYS_ACTION_MOVE == ( pImp->nActions & FSYS_ACTION_MOVE ) && aTgt != rTarget )
        return ERRCODE_IO_NAMETOOLONG;

    // source is directory?
    FileStat aSourceFileStat( rSource );
    if ( aSourceFileStat.IsKind( FSYS_KIND_DIR ) )
    {
        // recursive copy
        eRet = Error( aTgt.MakeDir() ? FSYS_ERR_OK : FSYS_ERR_UNKNOWN, 0, &aTgt );
        Dir aSourceDir( rSource, FSYS_KIND_DIR|FSYS_KIND_FILE );
        for ( USHORT n = 0; ERRCODE_TOERROR(eRet) == FSYS_ERR_OK && n < aSourceDir.Count(); ++n )
        {
            const DirEntry &rSubSource = aSourceDir[n];
            DirEntryFlag eFlag = rSubSource.GetFlag();
            if ( eFlag != FSYS_FLAG_CURRENT && eFlag != FSYS_FLAG_PARENT )
            {
                DirEntry aSubTarget( aTgt );
                aSubTarget += rSubSource.GetName();
                eRet = DoCopy_Impl( rSubSource, aSubTarget );
                if ( eRet && !eWarn )
                eWarn = eRet;
            }
        }
    }
    else if ( aSourceFileStat.IsKind(FSYS_KIND_FILE) )
    {
        if ( ( FSYS_ACTION_KEEP_EXISTING == ( pImp->nActions & FSYS_ACTION_KEEP_EXISTING ) ) &&
             aTgt.Exists() )
        {
            // Do not overwrite existing file in target folder.
            return ERRCODE_NONE;
        }

        // copy file
        nBytesCopied = 0;
        nBytesTotal = FileStat( rSource ).GetSize();

        ::rtl::OUString aFileName;
        FileBase::getFileURLFromSystemPath( ::rtl::OUString(rSource.GetFull()), aFileName );
        SvFileStream aSrc( aFileName, STREAM_READ|STREAM_NOCREATE|STREAM_SHARE_DENYNONE );

        if ( !aSrc.GetError() )
        {
#ifdef UNX
            struct stat buf;
            if ( fstat( aSrc.GetFileHandle(), &buf ) == -1 )
                eRet = Error( FSYS_ERR_ACCESSDENIED, 0, &aTgt );
#endif
            ::rtl::OUString aTargetFileName;
            FileBase::getFileURLFromSystemPath( ::rtl::OUString(aTgt.GetFull()), aTargetFileName );

            SvFileStream aTargetStream( aTargetFileName, STREAM_WRITE | STREAM_TRUNC | STREAM_SHARE_DENYWRITE );
            if ( !aTargetStream.GetError() )
            {
#ifdef UNX
                if ( fchmod( aTargetStream.GetFileHandle(), buf.st_mode ) == -1 )
                    eRet = Error( FSYS_ERR_ACCESSDENIED, 0, &aTgt );
#endif
                size_t nAllocSize = 0, nSize = 0;
                char *pBuf = 0;
                while ( Progress() && nSize == nAllocSize && eRet == FSYS_ERR_OK )
                {
                    // adjust the block-size
                    if ( nBlockSize > nAllocSize )
                    {
                        delete[] pBuf;
                        nAllocSize = nBlockSize;
                        pBuf = new char[nAllocSize];
                    }

                    // copy one block
                    nSize = aSrc.Read( pBuf, nBlockSize );
                    aTargetStream.Write( pBuf, nSize );
                    if ( aTargetStream.GetError() )
                        eRet = Error( aTargetStream.GetError(), 0, &aTgt );

                    // adjust counters
                    nBytesCopied += nSize;
                    if ( nBytesCopied > nBytesTotal )
                        nBytesTotal = nBytesCopied;
                }
                delete[] pBuf;
            }
            else
                eRet = Error( aTargetStream.GetError(), 0, &aTgt );

            // unvollstaendiges File wieder loeschen
            aTargetStream.Close();

            if ( nBytesCopied != nBytesTotal )
            {
                aTgt.Kill();
            }
        }
        else
            eRet = Error( aSrc.GetError(), &rSource, 0 );
    }
    else if ( aSourceFileStat.IsKind(FSYS_KIND_NONE) )
        eRet = Error( ERRCODE_IO_NOTEXISTS, &rSource, 0 );
    else
        eRet = Error( ERRCODE_IO_NOTSUPPORTED, &rSource, 0 );

#ifdef WNT
    // Set LastWriteTime and Attributes of the target identical with the source

    if ( FSYS_ERR_OK == ERRCODE_TOERROR(eRet) )
    {
        WIN32_FIND_DATA fdSource;
        ByteString aFullSource(aSource.GetFull(), osl_getThreadTextEncoding());
        ByteString aFullTarget(aTgt.GetFull(), osl_getThreadTextEncoding());
        HANDLE  hFind = FindFirstFile( aFullSource.GetBuffer() , &fdSource );
        if ( hFind != INVALID_HANDLE_VALUE )
        {
            FindClose( hFind );

            HANDLE hFile = CreateFile( aFullTarget.GetBuffer(), GENERIC_WRITE,
                                       FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                                       OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );

            if ( hFile != INVALID_HANDLE_VALUE )
            {
                SetFileTime( hFile, NULL, NULL, &fdSource.ftLastWriteTime );
                CloseHandle( hFile );
            }

            SetFileAttributes( aFullTarget.GetBuffer(), fdSource.dwFileAttributes );
        }
    }
#endif
    // bei Move ggf. das File/Dir loeschen
    if ( FSYS_ERR_OK == ERRCODE_TOERROR(eRet) && ( pImp->nActions  & FSYS_ACTION_MOVE ) )
    {
        ErrCode eKillErr = Error( rSource.Kill() | ERRCODE_WARNING_MASK, &rSource, 0 );
        if ( eKillErr != ERRCODE_WARNING_MASK )
        {
            if ( rSource.Exists() )
                // loeschen ging nicht => dann die Kopie wieder loeschen
                aTgt.Kill( pImp->nActions );
            if ( !eWarn )
                eWarn = eKillErr;
        }
    }

    return !eRet ? eWarn : eRet;
}

// -----------------------------------------------------------------------

FSysError FileCopier::Execute( FSysAction nActions )
{
    return ExecuteExact( nActions );
}

// -----------------------------------------------------------------------

FSysError FileCopier::ExecuteExact( FSysAction nActions, FSysExact eExact )
{
    DirEntry aAbsSource = DirEntry( aSource);
    DirEntry aAbsTarget = DirEntry( aTarget );
    pImp->nActions = nActions;

    // check if both pathes are accessible and source and target are different
    if ( !aAbsTarget.ToAbs() || !aAbsSource.ToAbs() || aAbsTarget == aAbsSource )
        return FSYS_ERR_ACCESSDENIED;

    // check if copy would be endless recursive into itself
    if ( FSYS_ACTION_RECURSIVE == ( nActions & FSYS_ACTION_RECURSIVE ) &&
         aAbsSource.Contains( aAbsTarget ) )
        return ERRCODE_IO_RECURSIVE;

    // target is directory?
    if ( eExact == FSYS_NOTEXACT &&
         FileStat( aAbsTarget ).IsKind(FSYS_KIND_DIR) && FileStat( aAbsSource ).IsKind(FSYS_KIND_FILE) )
        // append name of source
        aAbsTarget += aSource.GetName();

    // recursive copy
    return DoCopy_Impl( aAbsSource, aAbsTarget );
}
<commit_msg>INTEGRATION: CWS os2port03 (1.8.54); FILE MERGED 2008/07/16 13:45:37 obr 1.8.54.2: RESYNC: (1.8-1.9); FILE MERGED 2008/04/15 14:41:15 ydario 1.8.54.1: Issue number:  i85203 Submitted by: ydario Reviewed by: ydario<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: filecopy.cxx,v $
 * $Revision: 1.10 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_tools.hxx"

#if defined WNT
#ifndef _SVWIN_H
#include <io.h>
#include <tools/svwin.h>
#endif

#elif defined(OS2)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <share.h>
#include <io.h>

#elif defined UNX
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>

#endif

#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

#include <stdio.h>
#include "comdep.hxx"
#include <tools/fsys.hxx>
#include <tools/stream.hxx>
#include <osl/file.hxx>

using namespace ::osl;

/*************************************************************************
|*
|*    FileCopier::FileCopier()
|*
|*    Beschreibung      FSYS.SDW
|*    Ersterstellung    MI 13.04.94
|*    Letzte Aenderung  MI 13.04.94
|*
*************************************************************************/

FileCopier::FileCopier() :

    nBytesTotal ( 0 ),
    nBytesCopied( 0 ),
    nBlockSize  ( 4096 ),
    pImp        ( new FileCopier_Impl )

{
}

// -----------------------------------------------------------------------

FileCopier::FileCopier( const DirEntry& rSource, const DirEntry& rTarget ) :

    aSource     ( rSource ),
    aTarget     ( rTarget ),
    nBytesTotal ( 0 ),
    nBytesCopied( 0 ),
    nBlockSize  ( 4096 ),
    pImp        ( new FileCopier_Impl )

{
}

// -----------------------------------------------------------------------

FileCopier::FileCopier( const FileCopier& rCopier ) :

    aSource         ( rCopier.aSource ),
    aTarget         ( rCopier.aTarget ),
    nBytesTotal     ( 0 ),
    nBytesCopied    ( 0 ),
    aProgressLink   ( rCopier.aProgressLink ),
    nBlockSize      ( 4096 ),
    pImp            ( new FileCopier_Impl )

{
}

/*************************************************************************
|*
|*    FileCopier::~FileCopier()
|*
|*    Beschreibung      FSYS.SDW
|*    Ersterstellung    MI 13.04.94
|*    Letzte Aenderung  MI 13.04.94
|*
*************************************************************************/

FileCopier::~FileCopier()
{
    delete pImp;
}

/*************************************************************************
|*
|*    FileCopier::operator =()
|*
|*    Beschreibung      FSYS.SDW
|*    Ersterstellung    MI 13.04.94
|*    Letzte Aenderung  MI 13.04.94
|*
*************************************************************************/

FileCopier& FileCopier::operator = ( const FileCopier &rCopier )
{
    aSource = rCopier.aSource;
    aTarget = rCopier.aTarget;
    nBytesTotal = rCopier.nBytesTotal;
    nBytesCopied = rCopier.nBytesCopied;
    nBytesCopied = rCopier.nBytesCopied;
    nBlockSize = rCopier.nBlockSize;
    aProgressLink = rCopier.aProgressLink;
    *pImp = *(rCopier.pImp);
    return *this;
}

/*************************************************************************
|*
|*    FileCopier::Progress()
|*
|*    Beschreibung      FSYS.SDW
|*    Ersterstellung    MI 13.04.94
|*    Letzte Aenderung  MI 13.04.94
|*
*************************************************************************/

BOOL FileCopier::Progress()
{
    if ( !aProgressLink )
        return TRUE;
    else
    {
        if ( aProgressLink.Call( this ) )
            return TRUE;
        return ( 0 == Error( ERRCODE_ABORT, 0, 0 ) );
    }
}

//---------------------------------------------------------------------------

ErrCode FileCopier::Error( ErrCode eErr, const DirEntry* pSource, const DirEntry* pTarget )
{
    // kein Fehler oder kein ErrorHandler?
    if ( !eErr || !pImp->aErrorLink )
        // => Error beibehalten
        return eErr;

    // sonst gesetzten ErrorHandler fragen
    pImp->pErrSource = pSource;
    pImp->pErrTarget = pTarget;
    pImp->eErr = eErr;
    ErrCode eRet = (ErrCode) pImp->aErrorLink.Call( this );
    pImp->pErrSource = 0;
    pImp->pErrTarget = 0;
    return eRet;
}

//---------------------------------------------------------------------------

const DirEntry* FileCopier::GetErrorSource() const
{
    return pImp->pErrSource;
}

//---------------------------------------------------------------------------

const DirEntry* FileCopier::GetErrorTarget() const
{
    return pImp->pErrTarget;
}

//---------------------------------------------------------------------------

ErrCode FileCopier::GetError() const
{
    return pImp->eErr;
}

//---------------------------------------------------------------------------

void FileCopier::SetErrorHdl( const Link &rLink )
{
    pImp->aErrorLink = rLink;
}

//---------------------------------------------------------------------------

const Link& FileCopier::GetErrorHdl() const
{
    return pImp->aErrorLink ;
}

/*************************************************************************
|*
|*    FileCopier::Execute()
|*
|*    Beschreibung      FSYS.SDW
|*    Ersterstellung    MI 13.04.94
|*    Letzte Aenderung  PB 16.06.00
|*
*************************************************************************/

FSysError FileCopier::DoCopy_Impl(
    const DirEntry &rSource, const DirEntry &rTarget )
{
    FSysError eRet = FSYS_ERR_OK;
    ErrCode eWarn = FSYS_ERR_OK;

    // HPFS->FAT?
    FSysPathStyle eSourceStyle = DirEntry::GetPathStyle( rSource.ImpGetTopPtr()->GetName() );
    FSysPathStyle eTargetStyle = DirEntry::GetPathStyle( rTarget.ImpGetTopPtr()->GetName() );
    BOOL bMakeShortNames = ( eSourceStyle == FSYS_STYLE_HPFS && eTargetStyle == FSYS_STYLE_FAT );

    // Zieldateiname ggf. kuerzen
    DirEntry aTgt;
    if ( bMakeShortNames )
    {
        aTgt = rTarget.GetPath();
        aTgt.MakeShortName( rTarget.GetName() );
    }
    else
        aTgt = rTarget;

    // kein Move wenn Namen gekuerzt werden muessten
    if ( bMakeShortNames && FSYS_ACTION_MOVE == ( pImp->nActions & FSYS_ACTION_MOVE ) && aTgt != rTarget )
        return ERRCODE_IO_NAMETOOLONG;

    // source is directory?
    FileStat aSourceFileStat( rSource );
    if ( aSourceFileStat.IsKind( FSYS_KIND_DIR ) )
    {
#ifdef OS2
        CHAR szSource[CCHMAXPATHCOMP];
        HOBJECT hSourceObject;

        strcpy(szSource, ByteString(rSource.GetFull(), osl_getThreadTextEncoding()).GetBuffer());
        hSourceObject = WinQueryObject(szSource);

        if ( hSourceObject )
        {
            PSZ  pszSourceName;
            PSZ  pszTargetName;
            CHAR szTarget[CCHMAXPATHCOMP];
            HOBJECT hTargetObject;
            HOBJECT hReturn = NULLHANDLE;

            strcpy(szTarget, ByteString(rTarget.GetFull(), osl_getThreadTextEncoding()).GetBuffer());
            pszTargetName = strrchr(szTarget, '\\');
            pszSourceName = strrchr(szSource, '\\');

            hTargetObject = WinQueryObject(szTarget);

            if ( hTargetObject )
                WinDestroyObject(hTargetObject);

            if ( pszTargetName && pszSourceName )
            {
                *pszTargetName = '\0';
                pszSourceName++;
                pszTargetName++;

                if(strcmp(pszSourceName, pszTargetName) == 0)
                {
                    hTargetObject = WinQueryObject(szTarget);

                    if(pImp->nActions & FSYS_ACTION_MOVE)
                    {
                        hReturn = WinMoveObject(hSourceObject, hTargetObject, 0);
                    }
                    else
                    {
                        hReturn = WinCopyObject(hSourceObject, hTargetObject, 0);
                    }
                    if ( bMakeShortNames && aTarget.Exists() )
                        aTarget.Kill();
                    return hReturn ? FSYS_ERR_OK : FSYS_ERR_UNKNOWN;
                }
            }
        }
#endif
        // recursive copy
        eRet = Error( aTgt.MakeDir() ? FSYS_ERR_OK : FSYS_ERR_UNKNOWN, 0, &aTgt );
        Dir aSourceDir( rSource, FSYS_KIND_DIR|FSYS_KIND_FILE );
        for ( USHORT n = 0; ERRCODE_TOERROR(eRet) == FSYS_ERR_OK && n < aSourceDir.Count(); ++n )
        {
            const DirEntry &rSubSource = aSourceDir[n];
            DirEntryFlag eFlag = rSubSource.GetFlag();
            if ( eFlag != FSYS_FLAG_CURRENT && eFlag != FSYS_FLAG_PARENT )
            {
                DirEntry aSubTarget( aTgt );
                aSubTarget += rSubSource.GetName();
                eRet = DoCopy_Impl( rSubSource, aSubTarget );
                if ( eRet && !eWarn )
                eWarn = eRet;
            }
        }
    }
    else if ( aSourceFileStat.IsKind(FSYS_KIND_FILE) )
    {
        if ( ( FSYS_ACTION_KEEP_EXISTING == ( pImp->nActions & FSYS_ACTION_KEEP_EXISTING ) ) &&
             aTgt.Exists() )
        {
            // Do not overwrite existing file in target folder.
            return ERRCODE_NONE;
        }

        // copy file
        nBytesCopied = 0;
        nBytesTotal = FileStat( rSource ).GetSize();

        ::rtl::OUString aFileName;
        FileBase::getFileURLFromSystemPath( ::rtl::OUString(rSource.GetFull()), aFileName );
        SvFileStream aSrc( aFileName, STREAM_READ|STREAM_NOCREATE|STREAM_SHARE_DENYNONE );

        if ( !aSrc.GetError() )
        {
#ifdef UNX
            struct stat buf;
            if ( fstat( aSrc.GetFileHandle(), &buf ) == -1 )
                eRet = Error( FSYS_ERR_ACCESSDENIED, 0, &aTgt );
#endif
            ::rtl::OUString aTargetFileName;
            FileBase::getFileURLFromSystemPath( ::rtl::OUString(aTgt.GetFull()), aTargetFileName );

            SvFileStream aTargetStream( aTargetFileName, STREAM_WRITE | STREAM_TRUNC | STREAM_SHARE_DENYWRITE );
            if ( !aTargetStream.GetError() )
            {
#ifdef UNX
                if ( fchmod( aTargetStream.GetFileHandle(), buf.st_mode ) == -1 )
                    eRet = Error( FSYS_ERR_ACCESSDENIED, 0, &aTgt );
#endif
                size_t nAllocSize = 0, nSize = 0;
                char *pBuf = 0;
                while ( Progress() && nSize == nAllocSize && eRet == FSYS_ERR_OK )
                {
                    // adjust the block-size
                    if ( nBlockSize > nAllocSize )
                    {
                        delete[] pBuf;
                        nAllocSize = nBlockSize;
                        pBuf = new char[nAllocSize];
                    }

                    // copy one block
                    nSize = aSrc.Read( pBuf, nBlockSize );
                    aTargetStream.Write( pBuf, nSize );
                    if ( aTargetStream.GetError() )
                        eRet = Error( aTargetStream.GetError(), 0, &aTgt );

                    // adjust counters
                    nBytesCopied += nSize;
                    if ( nBytesCopied > nBytesTotal )
                        nBytesTotal = nBytesCopied;
                }
                delete[] pBuf;
            }
            else
                eRet = Error( aTargetStream.GetError(), 0, &aTgt );

            // unvollstaendiges File wieder loeschen
            aTargetStream.Close();

            if ( nBytesCopied != nBytesTotal )
            {
                aTgt.Kill();
            }
        }
        else
            eRet = Error( aSrc.GetError(), &rSource, 0 );
    }
    else if ( aSourceFileStat.IsKind(FSYS_KIND_NONE) )
        eRet = Error( ERRCODE_IO_NOTEXISTS, &rSource, 0 );
    else
        eRet = Error( ERRCODE_IO_NOTSUPPORTED, &rSource, 0 );

#ifdef WNT
    // Set LastWriteTime and Attributes of the target identical with the source

    if ( FSYS_ERR_OK == ERRCODE_TOERROR(eRet) )
    {
        WIN32_FIND_DATA fdSource;
        ByteString aFullSource(aSource.GetFull(), osl_getThreadTextEncoding());
        ByteString aFullTarget(aTgt.GetFull(), osl_getThreadTextEncoding());
        HANDLE  hFind = FindFirstFile( aFullSource.GetBuffer() , &fdSource );
        if ( hFind != INVALID_HANDLE_VALUE )
        {
            FindClose( hFind );

            HANDLE hFile = CreateFile( aFullTarget.GetBuffer(), GENERIC_WRITE,
                                       FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                                       OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );

            if ( hFile != INVALID_HANDLE_VALUE )
            {
                SetFileTime( hFile, NULL, NULL, &fdSource.ftLastWriteTime );
                CloseHandle( hFile );
            }

            SetFileAttributes( aFullTarget.GetBuffer(), fdSource.dwFileAttributes );
        }
    }
#endif
    // bei Move ggf. das File/Dir loeschen
    if ( FSYS_ERR_OK == ERRCODE_TOERROR(eRet) && ( pImp->nActions  & FSYS_ACTION_MOVE ) )
    {
        ErrCode eKillErr = Error( rSource.Kill() | ERRCODE_WARNING_MASK, &rSource, 0 );
        if ( eKillErr != ERRCODE_WARNING_MASK )
        {
            if ( rSource.Exists() )
                // loeschen ging nicht => dann die Kopie wieder loeschen
                aTgt.Kill( pImp->nActions );
            if ( !eWarn )
                eWarn = eKillErr;
        }
    }

    return !eRet ? eWarn : eRet;
}

// -----------------------------------------------------------------------

FSysError FileCopier::Execute( FSysAction nActions )
{
    return ExecuteExact( nActions );
}

// -----------------------------------------------------------------------

FSysError FileCopier::ExecuteExact( FSysAction nActions, FSysExact eExact )
{
    DirEntry aAbsSource = DirEntry( aSource);
    DirEntry aAbsTarget = DirEntry( aTarget );
    pImp->nActions = nActions;

    // check if both pathes are accessible and source and target are different
    if ( !aAbsTarget.ToAbs() || !aAbsSource.ToAbs() || aAbsTarget == aAbsSource )
        return FSYS_ERR_ACCESSDENIED;

    // check if copy would be endless recursive into itself
    if ( FSYS_ACTION_RECURSIVE == ( nActions & FSYS_ACTION_RECURSIVE ) &&
         aAbsSource.Contains( aAbsTarget ) )
        return ERRCODE_IO_RECURSIVE;

    // target is directory?
    if ( eExact == FSYS_NOTEXACT &&
         FileStat( aAbsTarget ).IsKind(FSYS_KIND_DIR) && FileStat( aAbsSource ).IsKind(FSYS_KIND_FILE) )
        // append name of source
        aAbsTarget += aSource.GetName();

    // recursive copy
    return DoCopy_Impl( aAbsSource, aAbsTarget );
}
<|endoftext|>


<commit_before><commit_msg>tools: check for data loss in WriteFraction<commit_after><|endoftext|>


<commit_before><commit_msg>coverity#708548 Uninitialized pointer field<commit_after><|endoftext|>