<commit_before>/**
 * @file test_sfmt.cpp
 *
 * @brief Test of SFMT stream
 *
 * @author Dahua Lin
 */

#include "../test_base.h"

#include <light_mat/matrix/matrix_classes.h>
#include <light_mat/random/sfmt.h>
#include <cstring>
#include <fstream>

using namespace lmat;
using namespace lmat::random;
using namespace lmat::test;

const index_t vlen = 1000;
const uint32_t seed0 = 1234;

dense_col<uint32_t> read_sfmt_vdata(unsigned int mexp)
{
	dense_col<uint32_t> data(vlen);

	char filename[128];
	std::snprintf(filename, 128, "data/sfmt/sfmt.%06u.txt", mexp);

	std::ifstream fin;
	fin.open(filename);

	if (fin.fail())
		throw std::runtime_error("SFMT data file open failed");

	for (index_t i = 0; i < vlen; ++i)
	{
		fin >> data[i];
	}

	fin.close();
/*
	for (index_t i = 0; i < vlen; ++i)
	{
		std::printf("%11u", data[i]);
		if ((i+1) % 5 == 0) std::printf("\n");
	}
*/
	return data;
}

template<unsigned int MEXP>
void verify_sfmt_stream()
{
	dense_col<uint32_t> vdata = read_sfmt_vdata(MEXP);

	sfmt_rand_stream<MEXP> rs;

	dense_col<uint32_t> vgen(vlen);
	for (index_t i = 0; i < vlen; ++i)
	{
		vgen[i] = rs.rand_u32();
	}
	ASSERT_VEC_EQ( vlen, vgen, vdata );
}

template<unsigned int MEXP>
void verify_sfmt_u64()
{
	sfmt_rand_stream<MEXP> rs;

	dense_col<uint32_t> v32(vlen);
	for (index_t i = 0; i < vlen; ++i)
	{
		v32[i] = rs.rand_u32();
	}

	rs.set_seed(seed0);

	index_t n = vlen / 2;

	for (index_t i = 0; i < n; ++i)
	{
		uint64_t x = rs.rand_u64();

		uint32_t l = v32[2 * i];
		uint32_t h = v32[2 * i + 1];
		uint64_t x0 = (uint64_t)l | ((uint64_t)h << 32);

		ASSERT_EQ( x, x0 );
	}

	rs.set_seed(seed0);
	rs.rand_u32(); // ignore one unit

	for (index_t i = 0; i < n-1; ++i)
	{
		uint64_t x = rs.rand_u64();
		uint32_t l = v32[2 * i + 2];
		uint32_t h = v32[2 * i + 3];
		uint64_t x0 = (uint64_t)l | ((uint64_t)h << 32);

		ASSERT_EQ( x, x0 );
	}
}

template<unsigned int MEXP>
void verify_sfmt_m128()
{
	sfmt_rand_stream<MEXP> rs;

	dense_col<uint32_t> v32(vlen);
	for (index_t i = 0; i < vlen; ++i)
	{
		v32[i] = rs.rand_u32();
	}

	rs.set_seed(seed0);

	index_t n = vlen / 4;

	LMAT_ALIGN(16) uint32_t x[4];

	for (index_t i = 0; i < n; ++i)
	{
		__m128i p = rs.rand_pack();
		_mm_store_si128(reinterpret_cast<__m128i*>(x), p);

		const uint32_t *x0 = &v32[i * 4];

		ASSERT_VEC_EQ( 4, x, x0 );
	}

	for (index_t o = 1; o < 4; ++o)
	{
		rs.set_seed(seed0);
		for (index_t j = 0; j < o; ++j) rs.rand_u32(); // ignore o units

		for (index_t i = 0; i < n-1; ++i)
		{
			__m128i p = rs.rand_pack();
			_mm_store_si128(reinterpret_cast<__m128i*>(x), p);

			const uint32_t *x0 = &v32[(i+1) * 4];

			ASSERT_VEC_EQ(4, x, x0);
		}
	}
}

#ifdef LMAT_HAS_AVX

template<unsigned int MEXP>
void verify_sfmt_m256()
{
	sfmt_rand_stream<MEXP> rs;

	dense_col<uint32_t> v32(vlen);
	for (index_t i = 0; i < vlen; ++i)
	{
		v32[i] = rs.rand_u32();
	}

	rs.set_seed(seed0);

	index_t n = vlen / 8;

	LMAT_ALIGN(32) uint32_t x[8];

	for (index_t i = 0; i < n; ++i)
	{
		__m256i p = rs.rand_avx_pack();
		_mm256_store_si256(reinterpret_cast<__m256i*>(x), p);

		const uint32_t *x0 = &v32[i * 8];

		ASSERT_VEC_EQ( 8, x, x0 );
	}

	for (index_t o = 1; o < 8; ++o)
	{
		rs.set_seed(seed0);
		for (index_t j = 0; j < o; ++j) rs.rand_u32(); // ignore o units

		for (index_t i = 0; i < n-1; ++i)
		{
			__m256i p = rs.rand_avx_pack();
			_mm256_store_si256(reinterpret_cast<__m256i*>(x), p);

			const uint32_t *x0 = &v32[(i+1) * 8];

			ASSERT_VEC_EQ(8, x, x0);
		}
	}
}

#endif

template<unsigned int MEXP>
void test_sfmt_randseq(sfmt_rand_stream<MEXP>& rs, index_t ignore, index_t n)  // n units
{
	dense_row<uint32_t> r(n);
	dense_row<uint32_t> x(n);

	// generate one by one

	rs.set_seed(seed0);
	for (index_t i = 0; i < ignore; ++i) rs.rand_u32();
	for (index_t i = 0; i < n; ++i) r[i] = rs.rand_u32();

	// generate in batch

	rs.set_seed(seed0);
	for (index_t i = 0; i < ignore; ++i) rs.rand_u32();
	rs.rand_seq((size_t)n * sizeof(uint32_t), x.ptr_data());

	// compare

	ASSERT_VEC_EQ(n, x, r);
}

template<unsigned int MEXP>
void verify_sfmt_seq()
{
	sfmt_rand_stream<MEXP> rs;
	index_t nu = (index_t)rs.internal_nunits();

	const int nstarts = 4;
	index_t starts[nstarts] = {0, 3, nu / 4, nu / 2};

	const int nlens = 6;
	index_t lens[nlens] = {3, nu / 4, nu / 2, nu, (nu * 2 + nu / 2), (nu * 3 + nu / 4) };

	for (int i = 0; i < nstarts; ++i)
	{
		for (int j = 0; j < nlens; ++j)
		{
			index_t start = starts[i];
			index_t len = lens[j];

			test_sfmt_randseq(rs, start, len);
		}
	}
}

#define DEF_SFMT_TESTS( packname, tfunname ) \
		SIMPLE_CASE( packname, 1279 ) { tfunname<1279>(); } \
		SIMPLE_CASE( packname, 2281 ) { tfunname<2281>(); } \
		SIMPLE_CASE( packname, 4253 ) { tfunname<4253>(); } \
		SIMPLE_CASE( packname, 11213 ) { tfunname<11213>(); } \
		SIMPLE_CASE( packname, 19937 ) { tfunname<19937>(); } \
		SIMPLE_CASE( packname, 44497 ) { tfunname<44497>(); } \
		SIMPLE_CASE( packname, 86243 ) { tfunname<86243>(); } \
		SIMPLE_CASE( packname, 132049 ) { tfunname<132049>(); } \
		BEGIN_TPACK( packname ) \
			ADD_SIMPLE_CASE( packname, 1279 ) \
			ADD_SIMPLE_CASE( packname, 2281 ) \
			ADD_SIMPLE_CASE( packname, 4253 ) \
			ADD_SIMPLE_CASE( packname, 11213 ) \
			ADD_SIMPLE_CASE( packname, 19937 ) \
			ADD_SIMPLE_CASE( packname, 44497 ) \
			ADD_SIMPLE_CASE( packname, 86243 ) \
			ADD_SIMPLE_CASE( packname, 132049 ) \
		END_TPACK

DEF_SFMT_TESTS( sfmt_verify, verify_sfmt_stream )
DEF_SFMT_TESTS( sfmt_verify_u64, verify_sfmt_u64 )
DEF_SFMT_TESTS( sfmt_verify_m128, verify_sfmt_m128 )

#ifdef LMAT_HAS_AVX
DEF_SFMT_TESTS( sfmt_verify_m256, verify_sfmt_m256 )
#endif

DEF_SFMT_TESTS( sfmt_verify_seq, verify_sfmt_seq )

BEGIN_MAIN_SUITE
	ADD_TPACK( sfmt_verify )
	ADD_TPACK( sfmt_verify_u64 )
	ADD_TPACK( sfmt_verify_m128 )
#ifdef LMAT_HAS_AVX
	ADD_TPACK( sfmt_verify_m256 )
#endif
	ADD_TPACK( sfmt_verify_seq )
END_MAIN_SUITE

<commit_msg>improved tests on SFMT passed<commit_after>/**
 * @file test_sfmt.cpp
 *
 * @brief Test of SFMT stream
 *
 * @author Dahua Lin
 */

#include "../test_base.h"

#include <light_mat/matrix/matrix_classes.h>
#include <light_mat/random/sfmt.h>
#include <cstring>
#include <fstream>

using namespace lmat;
using namespace lmat::random;
using namespace lmat::test;

const index_t vlen = 1000;
const uint32_t seed0 = 1234;

dense_col<uint32_t> read_sfmt_vdata(unsigned int mexp)
{
	dense_col<uint32_t> data(vlen);

	char filename[128];
	std::snprintf(filename, 128, "data/sfmt/sfmt.%06u.txt", mexp);

	std::ifstream fin;
	fin.open(filename);

	if (fin.fail())
		throw std::runtime_error("SFMT data file open failed");

	for (index_t i = 0; i < vlen; ++i)
	{
		fin >> data[i];
	}

	fin.close();
/*
	for (index_t i = 0; i < vlen; ++i)
	{
		std::printf("%11u", data[i]);
		if ((i+1) % 5 == 0) std::printf("\n");
	}
*/
	return data;
}

template<unsigned int MEXP>
void verify_sfmt_stream()
{
	dense_col<uint32_t> vdata = read_sfmt_vdata(MEXP);

	sfmt_rand_stream<MEXP> rs;

	dense_col<uint32_t> vgen(vlen);
	for (index_t i = 0; i < vlen; ++i)
	{
		vgen[i] = rs.rand_u32();
	}
	ASSERT_VEC_EQ( vlen, vgen, vdata );
}

template<unsigned int MEXP>
void verify_sfmt_u64()
{
	sfmt_rand_stream<MEXP> rs;

	dense_col<uint32_t> v32(vlen);
	for (index_t i = 0; i < vlen; ++i)
	{
		v32[i] = rs.rand_u32();
	}

	rs.set_seed(seed0);

	index_t n = vlen / 2;

	for (index_t i = 0; i < n; ++i)
	{
		uint64_t x = rs.rand_u64();

		uint32_t l = v32[2 * i];
		uint32_t h = v32[2 * i + 1];
		uint64_t x0 = (uint64_t)l | ((uint64_t)h << 32);

		ASSERT_EQ( x, x0 );
	}

	rs.set_seed(seed0);
	rs.rand_u32(); // ignore one unit

	for (index_t i = 0; i < n-1; ++i)
	{
		uint64_t x = rs.rand_u64();
		uint32_t l = v32[2 * i + 2];
		uint32_t h = v32[2 * i + 3];
		uint64_t x0 = (uint64_t)l | ((uint64_t)h << 32);

		ASSERT_EQ( x, x0 );
	}
}

template<unsigned int MEXP>
void verify_sfmt_m128()
{
	sfmt_rand_stream<MEXP> rs;

	dense_col<uint32_t> v32(vlen);
	for (index_t i = 0; i < vlen; ++i)
	{
		v32[i] = rs.rand_u32();
	}

	rs.set_seed(seed0);

	index_t n = vlen / 4;

	LMAT_ALIGN(16) uint32_t x[4];

	for (index_t i = 0; i < n; ++i)
	{
		__m128i p = rs.rand_pack();
		_mm_store_si128(reinterpret_cast<__m128i*>(x), p);

		const uint32_t *x0 = &v32[i * 4];

		ASSERT_VEC_EQ( 4, x, x0 );
	}

	for (index_t o = 1; o < 4; ++o)
	{
		rs.set_seed(seed0);
		for (index_t j = 0; j < o; ++j) rs.rand_u32(); // ignore o units

		for (index_t i = 0; i < n-1; ++i)
		{
			__m128i p = rs.rand_pack();
			_mm_store_si128(reinterpret_cast<__m128i*>(x), p);

			const uint32_t *x0 = &v32[(i+1) * 4];

			ASSERT_VEC_EQ(4, x, x0);
		}
	}
}

#ifdef LMAT_HAS_AVX

template<unsigned int MEXP>
void verify_sfmt_m256()
{
	sfmt_rand_stream<MEXP> rs;

	dense_col<uint32_t> v32(vlen);
	for (index_t i = 0; i < vlen; ++i)
	{
		v32[i] = rs.rand_u32();
	}

	rs.set_seed(seed0);

	index_t n = vlen / 8;

	LMAT_ALIGN(32) uint32_t x[8];

	for (index_t i = 0; i < n; ++i)
	{
		__m256i p = rs.rand_avx_pack();
		_mm256_store_si256(reinterpret_cast<__m256i*>(x), p);

		const uint32_t *x0 = &v32[i * 8];

		ASSERT_VEC_EQ( 8, x, x0 );
	}

	for (index_t o = 1; o < 8; ++o)
	{
		rs.set_seed(seed0);
		for (index_t j = 0; j < o; ++j) rs.rand_u32(); // ignore o units

		for (index_t i = 0; i < n-1; ++i)
		{
			__m256i p = rs.rand_avx_pack();
			_mm256_store_si256(reinterpret_cast<__m256i*>(x), p);

			const uint32_t *x0 = &v32[(i+1) * 8];

			ASSERT_VEC_EQ(8, x, x0);
		}
	}
}

#endif

template<unsigned int MEXP>
void test_sfmt_randseq(sfmt_rand_stream<MEXP>& rs, index_t ignore, index_t n)  // n units
{
	dense_row<uint32_t> r(n);
	dense_row<uint32_t> x(n, zero());
	dense_row<uint32_t> r2(n);
	dense_row<uint32_t> x2(n, zero());

	// generate one by one

	rs.set_seed(seed0);
	for (index_t i = 0; i < ignore; ++i) rs.rand_u32();
	for (index_t i = 0; i < n; ++i) r[i] = rs.rand_u32();
	for (index_t i = 0; i < n; ++i) r2[i] = rs.rand_u32();

	// generate in batch

	rs.set_seed(seed0);
	for (index_t i = 0; i < ignore; ++i) rs.rand_u32();
	rs.rand_seq((size_t)n * sizeof(uint32_t), x.ptr_data());
	rs.rand_seq((size_t)n * sizeof(uint32_t), x2.ptr_data());

	// compare

	ASSERT_VEC_EQ(n, x, r);
	ASSERT_VEC_EQ(n, x2, r2);
}

template<unsigned int MEXP>
void verify_sfmt_seq()
{
	sfmt_rand_stream<MEXP> rs;
	index_t nu = (index_t)rs.internal_nunits();

	const int nstarts = 4;
	index_t starts[nstarts] = {0, 3, nu / 4, nu / 2};

	const int nlens = 6;
	index_t lens[nlens] = {3, nu / 4, nu / 2, nu, (nu * 2 + nu / 2), (nu * 3 + nu / 4) };

	for (int i = 0; i < nstarts; ++i)
	{
		for (int j = 0; j < nlens; ++j)
		{
			index_t start = starts[i];
			index_t len = lens[j];

			test_sfmt_randseq(rs, start, len);
		}
	}
}

#define DEF_SFMT_TESTS( packname, tfunname ) \
		SIMPLE_CASE( packname, 1279 ) { tfunname<1279>(); } \
		SIMPLE_CASE( packname, 2281 ) { tfunname<2281>(); } \
		SIMPLE_CASE( packname, 4253 ) { tfunname<4253>(); } \
		SIMPLE_CASE( packname, 11213 ) { tfunname<11213>(); } \
		SIMPLE_CASE( packname, 19937 ) { tfunname<19937>(); } \
		SIMPLE_CASE( packname, 44497 ) { tfunname<44497>(); } \
		SIMPLE_CASE( packname, 86243 ) { tfunname<86243>(); } \
		SIMPLE_CASE( packname, 132049 ) { tfunname<132049>(); } \
		BEGIN_TPACK( packname ) \
			ADD_SIMPLE_CASE( packname, 1279 ) \
			ADD_SIMPLE_CASE( packname, 2281 ) \
			ADD_SIMPLE_CASE( packname, 4253 ) \
			ADD_SIMPLE_CASE( packname, 11213 ) \
			ADD_SIMPLE_CASE( packname, 19937 ) \
			ADD_SIMPLE_CASE( packname, 44497 ) \
			ADD_SIMPLE_CASE( packname, 86243 ) \
			ADD_SIMPLE_CASE( packname, 132049 ) \
		END_TPACK

DEF_SFMT_TESTS( sfmt_verify, verify_sfmt_stream )
DEF_SFMT_TESTS( sfmt_verify_u64, verify_sfmt_u64 )
DEF_SFMT_TESTS( sfmt_verify_m128, verify_sfmt_m128 )

#ifdef LMAT_HAS_AVX
DEF_SFMT_TESTS( sfmt_verify_m256, verify_sfmt_m256 )
#endif

DEF_SFMT_TESTS( sfmt_verify_seq, verify_sfmt_seq )

BEGIN_MAIN_SUITE
	ADD_TPACK( sfmt_verify )
	ADD_TPACK( sfmt_verify_u64 )
	ADD_TPACK( sfmt_verify_m128 )
#ifdef LMAT_HAS_AVX
	ADD_TPACK( sfmt_verify_m256 )
#endif
	ADD_TPACK( sfmt_verify_seq )
END_MAIN_SUITE

<|endoftext|>


<commit_before>#ifndef MJOLNIR_UTIL_STATIC_STRING_HPP
#define MJOLNIR_UTIL_STATIC_STRING_HPP
#include <mjolnir/util/throw_exception.hpp>
#include <string>
#include <stdexcept>
#include <istream>
#include <ostream>
#include <cstdint>

namespace mjolnir
{

// static_string is a statically sized std::string, inspired by static_vector
// provided by Boost.Container.
// this is the minimal implementation for a specific perpose, so it doesn't have
// all the functionalities that exists in `std::string`. For example, it assumes
// that the character encoding is ascii. Basically, it can contain UTF-8 string
// as byte-array. But in that case, `size()` might not fit to the actual number
// of letters.
template<std::size_t N>
class static_string
{
    // because it contains '\0' delimiter at the end of buffer, the actual
    // free buffer size is N-1. static_string is to manage the size of object,
    // the clarity of the size is considered more important than the usability.
    static constexpr std::size_t capacity_ = N - 1;

    // to make code shorter.
    void check_size() const
    {
        if(this->size_ > this->capacity_)
        {
            throw_exception<std::length_error>("constructing static_assert<", N,
                "> with literal string having ", this->size_, " length.");
        }
        return ;
    }

  public:

    using char_type              = char;
    using traits_type            = std::char_traits<char>;
    using container_type         = std::array<char, N>;

    using value_type             = typename container_type::value_type;
    using size_type              = typename container_type::size_type;
    using difference_type        = typename container_type::difference_type;
    using pointer                = typename container_type::pointer;
    using const_pointer          = typename container_type::const_pointer;
    using reference              = typename container_type::reference;
    using const_reference        = typename container_type::const_reference;
    using iterator               = typename container_type::iterator;
    using const_iterator         = typename container_type::const_iterator ;
    using reverse_iterator       = typename container_type::reverse_iterator;
    using const_reverse_iterator = typename container_type::const_reverse_iterator;

  public:

    static_string() : size_(0), buffer_{0} {}
    ~static_string() = default;
    static_string(static_string const&) = default;
    static_string(static_string &&)     = default;
    static_string& operator=(static_string const&) = default;
    static_string& operator=(static_string &&)     = default;

    explicit static_string(const char* literal): size_(traits_type::length(literal))
    {
        this->check_size();
        traits_type::copy(this->data(), literal, this->size_+1);
    }
    explicit static_string(const std::string& str): size_(str.size())
    {
        this->check_size();
        traits_type::copy(this->data(), str.c_str(), this->size_+1);
    }
    template<std::size_t M>
    explicit static_string(const static_string<M>& str): size_(str.size())
    {
        if(N < M) {this->check_size();}
        traits_type::copy(this->data(), str.c_str(), this->size_+1);
    }

    static_string& operator=(const char* literal)
    {
        this->size_ = traits_type::length(literal);
        this->check_size();
        traits_type::copy(this->data(), literal, this->size_+1);
        return *this;
    }
    static_string& operator=(const std::string& str)
    {
        this->size_ = str.size();
        this->check_size();
        traits_type::copy(this->data(), str.c_str(), this->size_+1);
        return *this;
    }
    template<std::size_t M>
    static_string& operator=(static_string<M> const& rhs)
    {
        this->size_ = rhs.size();
        if(N < M) {this->check_size();}
        traits_type::copy(this->data(), rhs.c_str(), this->size_+1);
        return *this;
    }

    static_string& operator+=(const char c)
    {
        this->size_++;
        this->check_size();
        buffer_[this->size_-1] = c;
        return *this;
    }
    static_string& operator+=(const char* rhs)
    {
        const std::size_t last = this->size_;
        const std::size_t len  = traits_type::length(rhs);
        this->size_ += len;
        this->check_size();
        traits_type::copy(std::addressof(buffer_[last]), rhs, len+1);
        return *this;
    }
    template<std::size_t M>
    static_string& operator+=(const static_string<M>& rhs)
    {
        const std::size_t last = this->size_;
        this->size_ += rhs.size();
        this->check_size();
        traits_type::copy(std::addressof(buffer_[last]), rhs.c_str(), rhs.size()+1);
        return *this;
    }
    static_string& operator+=(const std::string& rhs)
    {
        const std::size_t last = this->size_;
        this->size_ += rhs.size();
        this->check_size();
        traits_type::copy(std::addressof(buffer_[last]), rhs.c_str(), rhs.size()+1);
        return *this;
    }

    bool empty() const noexcept {return this->size_ == 0;}
    void clear() {this->size_ = 0;}
    void resize(size_type i) {this->size_ = i; this->check_size();}

    value_type& operator[](size_type i)       noexcept {return buffer_[i];}
    value_type  operator[](size_type i) const noexcept {return buffer_[i];}
    value_type& at(size_type i)       {return buffer_.at(i);}
    value_type  at(size_type i) const {return buffer_.at(i);}

    value_type& front()       noexcept {return buffer_.front();}
    value_type  front() const noexcept {return buffer_.front();}
    value_type& back()        noexcept {return buffer_[this->size_-1];}
    value_type  back()  const noexcept {return buffer_[this->size_-1];}

    std::size_t size()     const noexcept {return this->size_;}
    std::size_t length()   const noexcept {return this->size_;}
    std::size_t capacity() const noexcept {return capacity_;}
    std::size_t max_size() const noexcept {return capacity_;}

    pointer       data()        noexcept {return buffer_.data();}
    const_pointer data()  const noexcept {return buffer_.data();}
    pointer       c_str()       noexcept {return buffer_.data();}
    const_pointer c_str() const noexcept {return buffer_.data();}

    iterator        begin()       noexcept {return buffer_.begin();}
    iterator        end()         noexcept {return buffer_.begin();}
    const_iterator  begin() const noexcept {return buffer_.begin();}
    const_iterator  end()   const noexcept {return buffer_.begin();}
    const_iterator cbegin() const noexcept {return buffer_.cbegin();}
    const_iterator cend()   const noexcept {return buffer_.cbegin();}

    reverse_iterator        rbegin()       noexcept {return buffer_.rbegin();}
    reverse_iterator        rend()         noexcept {return buffer_.rbegin();}
    const_reverse_iterator  rbegin() const noexcept {return buffer_.rbegin();}
    const_reverse_iterator  rend()   const noexcept {return buffer_.rbegin();}
    const_reverse_iterator crbegin() const noexcept {return buffer_.crbegin();}
    const_reverse_iterator crend()   const noexcept {return buffer_.crbegin();}

  private:

    std::size_t    size_;
    container_type buffer_;
};

template<std::size_t N, std::size_t M>
static_string<N+M>
operator+(const static_string<N>& lhs, const static_string<M>& rhs)
{
    static_string<N+M> retval(lhs);
    retval += rhs;
    return retval;
}
template<std::size_t N>
std::string operator+(const std::string& lhs, const static_string<N>& rhs)
{
    std::string retval(lhs);
    retval.append(rhs.c_str());
    return retval;
}
template<std::size_t N>
std::string operator+(const static_string<N>& lhs, const std::string& rhs)
{
    std::string retval(lhs.c_str());
    retval.append(rhs);
    return retval;
}
template<std::size_t N>
std::string operator+(const char* lhs, const static_string<N>& rhs)
{
    std::string retval(lhs);
    retval.append(rhs.c_str());
    return retval;
}
template<std::size_t N>
std::string operator+(const static_string<N>& lhs, const char* rhs)
{
    std::string retval(lhs.c_str());
    retval.append(rhs);
    return retval;
}

// append static_string into std::string
template<std::size_t N>
std::string& operator+=(std::string& lhs, const static_string<N>& rhs)
{
    lhs.append(rhs.c_str());
    return lhs;
}

template<std::size_t N, std::size_t M>
bool operator==(const static_string<N>& lhs, const static_string<M>& rhs)
{
    return std::char_traits<char>::compare(lhs.data(), rhs.data(),
            std::min(lhs.size(), rhs.size())) == 0;
}
template<std::size_t N, std::size_t M>
bool operator!=(const static_string<N>& lhs, const static_string<M>& rhs)
{
    return !(lhs == rhs);
}
template<std::size_t N, std::size_t M>
bool operator< (const static_string<N>& lhs, const static_string<M>& rhs)
{
    return std::char_traits<char>::compare(lhs.data(), rhs.data(),
            std::min(lhs.size(), rhs.size())) < 0;
}
template<std::size_t N, std::size_t M>
bool operator<=(const static_string<N>& lhs, const static_string<M>& rhs)
{
    return std::char_traits<char>::compare(lhs.data(), rhs.data(),
            std::min(lhs.size(), rhs.size())) <= 0;
}
template<std::size_t N, std::size_t M>
bool operator> (const static_string<N>& lhs, const static_string<M>& rhs)
{
    return !(lhs <= rhs);
}
template<std::size_t N, std::size_t M>
bool operator>=(const static_string<N>& lhs, const static_string<M>& rhs)
{
    return !(lhs < rhs);
}

template<std::size_t N>
std::ostream& operator<<(std::ostream& os, const static_string<N>& str)
{
    os << str.c_str();
    return os;
}

template<std::size_t N>
std::istream& operator>>(std::istream& is, static_string<N>& str)
{
    std::string tmp;
    is >> tmp;
    str = tmp;
    return is;
}

// compare with std::string.

template<std::size_t N>
bool operator==(const static_string<N>& lhs, const std::string& rhs)
{
    return std::char_traits<char>::compare(lhs.data(), rhs.data(),
            std::min(lhs.size(), rhs.size())) == 0;
}
template<std::size_t N>
bool operator==(const std::string& lhs, const static_string<N>& rhs)
{
    return std::char_traits<char>::compare(lhs.data(), rhs.data(),
            std::min(lhs.size(), rhs.size())) == 0;
}

template<std::size_t N>
bool operator!=(const static_string<N>& lhs, const std::string& rhs)
{
    return !(lhs == rhs);
}
template<std::size_t N>
bool operator!=(const std::string& lhs, const static_string<N>& rhs)
{
    return !(lhs == rhs);
}

template<std::size_t N>
bool operator< (const static_string<N>& lhs, const std::string& rhs)
{
    return std::char_traits<char>::compare(lhs.data(), rhs.data(),
            std::min(lhs.size(), rhs.size())) < 0;
}
template<std::size_t N>
bool operator< (const std::string& lhs, const static_string<N>& rhs)
{
    return std::char_traits<char>::compare(lhs.data(), rhs.data(),
            std::min(lhs.size(), rhs.size())) < 0;
}

template<std::size_t N>
bool operator<=(const static_string<N>& lhs, const std::string& rhs)
{
    return std::char_traits<char>::compare(lhs.data(), rhs.data(),
            std::min(lhs.size(), rhs.size())) <= 0;
}
template<std::size_t N>
bool operator<=(const std::string& lhs, const static_string<N>& rhs)
{
    return std::char_traits<char>::compare(lhs.data(), rhs.data(),
            std::min(lhs.size(), rhs.size())) <= 0;
}

template<std::size_t N>
bool operator> (const static_string<N>& lhs, const std::string& rhs)
{
    return !(lhs <= rhs);
}
template<std::size_t N>
bool operator> (const std::string& lhs, const static_string<N>& rhs)
{
    return !(lhs <= rhs);
}

template<std::size_t N>
bool operator>=(const std::string& lhs, const static_string<N>& rhs)
{
    return !(lhs < rhs);
}
template<std::size_t N>
bool operator>=(const static_string<N>& lhs, const std::string& rhs)
{
    return !(lhs < rhs);
}

} // mjolnir
#endif // MJOLNIR_UTIL_STATIC_STRING_HPP
<commit_msg>change message in exception thrown from static_string<commit_after>#ifndef MJOLNIR_UTIL_STATIC_STRING_HPP
#define MJOLNIR_UTIL_STATIC_STRING_HPP
#include <mjolnir/util/throw_exception.hpp>
#include <string>
#include <stdexcept>
#include <istream>
#include <ostream>
#include <cstdint>

namespace mjolnir
{

// static_string is a statically sized std::string, inspired by static_vector
// provided by Boost.Container.
// this is the minimal implementation for a specific perpose, so it doesn't have
// all the functionalities that exists in `std::string`. For example, it assumes
// that the character encoding is ascii. Basically, it can contain UTF-8 string
// as byte-array. But in that case, `size()` might not fit to the actual number
// of letters.
template<std::size_t N>
class static_string
{
    // because it contains '\0' delimiter at the end of buffer, the actual
    // free buffer size is N-1. static_string is to manage the size of object,
    // the clarity of the size is considered more important than the usability.
    static constexpr std::size_t capacity_ = N - 1;

    // to make code shorter.
    void check_size() const
    {
        if(this->size_ > this->capacity_)
        {
            throw_exception<std::length_error>("static_string (with capacity ",
                this->capacity_, ") cannot be constructed with string having ",
                this->size_, " length.");
        }
        return ;
    }

  public:

    using char_type              = char;
    using traits_type            = std::char_traits<char>;
    using container_type         = std::array<char, N>;

    using value_type             = typename container_type::value_type;
    using size_type              = typename container_type::size_type;
    using difference_type        = typename container_type::difference_type;
    using pointer                = typename container_type::pointer;
    using const_pointer          = typename container_type::const_pointer;
    using reference              = typename container_type::reference;
    using const_reference        = typename container_type::const_reference;
    using iterator               = typename container_type::iterator;
    using const_iterator         = typename container_type::const_iterator ;
    using reverse_iterator       = typename container_type::reverse_iterator;
    using const_reverse_iterator = typename container_type::const_reverse_iterator;

  public:

    static_string() : size_(0), buffer_{0} {}
    ~static_string() = default;
    static_string(static_string const&) = default;
    static_string(static_string &&)     = default;
    static_string& operator=(static_string const&) = default;
    static_string& operator=(static_string &&)     = default;

    explicit static_string(const char* literal): size_(traits_type::length(literal))
    {
        this->check_size();
        traits_type::copy(this->data(), literal, this->size_+1);
    }
    explicit static_string(const std::string& str): size_(str.size())
    {
        this->check_size();
        traits_type::copy(this->data(), str.c_str(), this->size_+1);
    }
    template<std::size_t M>
    explicit static_string(const static_string<M>& str): size_(str.size())
    {
        if(N < M) {this->check_size();}
        traits_type::copy(this->data(), str.c_str(), this->size_+1);
    }

    static_string& operator=(const char* literal)
    {
        this->size_ = traits_type::length(literal);
        this->check_size();
        traits_type::copy(this->data(), literal, this->size_+1);
        return *this;
    }
    static_string& operator=(const std::string& str)
    {
        this->size_ = str.size();
        this->check_size();
        traits_type::copy(this->data(), str.c_str(), this->size_+1);
        return *this;
    }
    template<std::size_t M>
    static_string& operator=(static_string<M> const& rhs)
    {
        this->size_ = rhs.size();
        if(N < M) {this->check_size();}
        traits_type::copy(this->data(), rhs.c_str(), this->size_+1);
        return *this;
    }

    static_string& operator+=(const char c)
    {
        this->size_++;
        this->check_size();
        buffer_[this->size_-1] = c;
        return *this;
    }
    static_string& operator+=(const char* rhs)
    {
        const std::size_t last = this->size_;
        const std::size_t len  = traits_type::length(rhs);
        this->size_ += len;
        this->check_size();
        traits_type::copy(std::addressof(buffer_[last]), rhs, len+1);
        return *this;
    }
    template<std::size_t M>
    static_string& operator+=(const static_string<M>& rhs)
    {
        const std::size_t last = this->size_;
        this->size_ += rhs.size();
        this->check_size();
        traits_type::copy(std::addressof(buffer_[last]), rhs.c_str(), rhs.size()+1);
        return *this;
    }
    static_string& operator+=(const std::string& rhs)
    {
        const std::size_t last = this->size_;
        this->size_ += rhs.size();
        this->check_size();
        traits_type::copy(std::addressof(buffer_[last]), rhs.c_str(), rhs.size()+1);
        return *this;
    }

    bool empty() const noexcept {return this->size_ == 0;}
    void clear() {this->size_ = 0;}
    void resize(size_type i) {this->size_ = i; this->check_size();}

    value_type& operator[](size_type i)       noexcept {return buffer_[i];}
    value_type  operator[](size_type i) const noexcept {return buffer_[i];}
    value_type& at(size_type i)       {return buffer_.at(i);}
    value_type  at(size_type i) const {return buffer_.at(i);}

    value_type& front()       noexcept {return buffer_.front();}
    value_type  front() const noexcept {return buffer_.front();}
    value_type& back()        noexcept {return buffer_[this->size_-1];}
    value_type  back()  const noexcept {return buffer_[this->size_-1];}

    std::size_t size()     const noexcept {return this->size_;}
    std::size_t length()   const noexcept {return this->size_;}
    std::size_t capacity() const noexcept {return capacity_;}
    std::size_t max_size() const noexcept {return capacity_;}

    pointer       data()        noexcept {return buffer_.data();}
    const_pointer data()  const noexcept {return buffer_.data();}
    pointer       c_str()       noexcept {return buffer_.data();}
    const_pointer c_str() const noexcept {return buffer_.data();}

    iterator        begin()       noexcept {return buffer_.begin();}
    iterator        end()         noexcept {return buffer_.begin();}
    const_iterator  begin() const noexcept {return buffer_.begin();}
    const_iterator  end()   const noexcept {return buffer_.begin();}
    const_iterator cbegin() const noexcept {return buffer_.cbegin();}
    const_iterator cend()   const noexcept {return buffer_.cbegin();}

    reverse_iterator        rbegin()       noexcept {return buffer_.rbegin();}
    reverse_iterator        rend()         noexcept {return buffer_.rbegin();}
    const_reverse_iterator  rbegin() const noexcept {return buffer_.rbegin();}
    const_reverse_iterator  rend()   const noexcept {return buffer_.rbegin();}
    const_reverse_iterator crbegin() const noexcept {return buffer_.crbegin();}
    const_reverse_iterator crend()   const noexcept {return buffer_.crbegin();}

  private:

    std::size_t    size_;
    container_type buffer_;
};

template<std::size_t N>
constexpr std::size_t static_string<N>::capacity_;

template<std::size_t N, std::size_t M>
static_string<N+M>
operator+(const static_string<N>& lhs, const static_string<M>& rhs)
{
    static_string<N+M> retval(lhs);
    retval += rhs;
    return retval;
}
template<std::size_t N>
std::string operator+(const std::string& lhs, const static_string<N>& rhs)
{
    std::string retval(lhs);
    retval.append(rhs.c_str());
    return retval;
}
template<std::size_t N>
std::string operator+(const static_string<N>& lhs, const std::string& rhs)
{
    std::string retval(lhs.c_str());
    retval.append(rhs);
    return retval;
}
template<std::size_t N>
std::string operator+(const char* lhs, const static_string<N>& rhs)
{
    std::string retval(lhs);
    retval.append(rhs.c_str());
    return retval;
}
template<std::size_t N>
std::string operator+(const static_string<N>& lhs, const char* rhs)
{
    std::string retval(lhs.c_str());
    retval.append(rhs);
    return retval;
}

// append static_string into std::string
template<std::size_t N>
std::string& operator+=(std::string& lhs, const static_string<N>& rhs)
{
    lhs.append(rhs.c_str());
    return lhs;
}

template<std::size_t N, std::size_t M>
bool operator==(const static_string<N>& lhs, const static_string<M>& rhs)
{
    return std::char_traits<char>::compare(lhs.data(), rhs.data(),
            std::min(lhs.size(), rhs.size())) == 0;
}
template<std::size_t N, std::size_t M>
bool operator!=(const static_string<N>& lhs, const static_string<M>& rhs)
{
    return !(lhs == rhs);
}
template<std::size_t N, std::size_t M>
bool operator< (const static_string<N>& lhs, const static_string<M>& rhs)
{
    return std::char_traits<char>::compare(lhs.data(), rhs.data(),
            std::min(lhs.size(), rhs.size())) < 0;
}
template<std::size_t N, std::size_t M>
bool operator<=(const static_string<N>& lhs, const static_string<M>& rhs)
{
    return std::char_traits<char>::compare(lhs.data(), rhs.data(),
            std::min(lhs.size(), rhs.size())) <= 0;
}
template<std::size_t N, std::size_t M>
bool operator> (const static_string<N>& lhs, const static_string<M>& rhs)
{
    return !(lhs <= rhs);
}
template<std::size_t N, std::size_t M>
bool operator>=(const static_string<N>& lhs, const static_string<M>& rhs)
{
    return !(lhs < rhs);
}

template<std::size_t N>
std::ostream& operator<<(std::ostream& os, const static_string<N>& str)
{
    os << str.c_str();
    return os;
}

template<std::size_t N>
std::istream& operator>>(std::istream& is, static_string<N>& str)
{
    std::string tmp;
    is >> tmp;
    str = tmp;
    return is;
}

// compare with std::string.

template<std::size_t N>
bool operator==(const static_string<N>& lhs, const std::string& rhs)
{
    return std::char_traits<char>::compare(lhs.data(), rhs.data(),
            std::min(lhs.size(), rhs.size())) == 0;
}
template<std::size_t N>
bool operator==(const std::string& lhs, const static_string<N>& rhs)
{
    return std::char_traits<char>::compare(lhs.data(), rhs.data(),
            std::min(lhs.size(), rhs.size())) == 0;
}

template<std::size_t N>
bool operator!=(const static_string<N>& lhs, const std::string& rhs)
{
    return !(lhs == rhs);
}
template<std::size_t N>
bool operator!=(const std::string& lhs, const static_string<N>& rhs)
{
    return !(lhs == rhs);
}

template<std::size_t N>
bool operator< (const static_string<N>& lhs, const std::string& rhs)
{
    return std::char_traits<char>::compare(lhs.data(), rhs.data(),
            std::min(lhs.size(), rhs.size())) < 0;
}
template<std::size_t N>
bool operator< (const std::string& lhs, const static_string<N>& rhs)
{
    return std::char_traits<char>::compare(lhs.data(), rhs.data(),
            std::min(lhs.size(), rhs.size())) < 0;
}

template<std::size_t N>
bool operator<=(const static_string<N>& lhs, const std::string& rhs)
{
    return std::char_traits<char>::compare(lhs.data(), rhs.data(),
            std::min(lhs.size(), rhs.size())) <= 0;
}
template<std::size_t N>
bool operator<=(const std::string& lhs, const static_string<N>& rhs)
{
    return std::char_traits<char>::compare(lhs.data(), rhs.data(),
            std::min(lhs.size(), rhs.size())) <= 0;
}

template<std::size_t N>
bool operator> (const static_string<N>& lhs, const std::string& rhs)
{
    return !(lhs <= rhs);
}
template<std::size_t N>
bool operator> (const std::string& lhs, const static_string<N>& rhs)
{
    return !(lhs <= rhs);
}

template<std::size_t N>
bool operator>=(const std::string& lhs, const static_string<N>& rhs)
{
    return !(lhs < rhs);
}
template<std::size_t N>
bool operator>=(const static_string<N>& lhs, const std::string& rhs)
{
    return !(lhs < rhs);
}

} // mjolnir
#endif // MJOLNIR_UTIL_STATIC_STRING_HPP
<|endoftext|>


<commit_before>#include "portswidget.h"
#include "../sysex/retcommandlist.h"
#include "../sysex/retsetmidiinfo.h"
#include "portdisplayhelper.h"
#include "portfilterwidget.h"
#include "portinfowidget.h"
#include "portremapwidget.h"
#include "portroutingwidget.h"

#include <QLabel>
#include <QListWidgetItem>
#include <QScrollArea>

PortsWidget::PortsWidget(MioMain *parent, Device *device, QString windowTitle)
    : MultiInfoWidget(parent, device, windowTitle) {
	infoSections = new std::vector<MultiInfoListEntry *>();
	if (device->getCommands()->isCommandSupported(
	        Command::GET_MIDI_PORT_INFO)) {
		getMidiPortSections(device);
	}
}

PortsWidget::~PortsWidget() {
	/* if (infoSections != nullptr) {
		infoSections->clear();
		delete infoSections;
	}*/
}

void PortsWidget::getMidiPorts(
    std::vector<RetSetMidiPortInfo *> *midiPortInfos) {
	std::vector<RetSetMidiPortInfo *>::iterator it;
	for (it = midiPortInfos->begin(); it != midiPortInfos->end(); ++it) {
		RetSetMidiPortInfo *midiPortInfo = *it;
		MultiInfoListEntry *entry = new MultiInfoListEntry(
		    MultiInfoListEntry::PORT_ROUTING, midiPortInfo->getPortName());
		entry->icon =
		    PortDisplayHelper::getPortIcon(midiPortInfo->getPortType());
		entry->message = midiPortInfo;
		entry->enabled = midiPortInfo->getInputEnabled();
		infoSections->push_back(entry);
	}
}

void PortsWidget::getMidiPortSections(Device *device) {
	MIDI_PORT_INFOS *midiPortInfoSections = device->getMidiPortInfos();
	std::map<int, std::vector<RetSetMidiPortInfo *> *>::iterator it;
	for (it = midiPortInfoSections->begin(); it != midiPortInfoSections->end();
	     ++it) {
		int section = it->first;
		int jack = section & 255;
		MidiPortType portType = static_cast<MidiPortType>(section >> 8);
		std::string portTypeName =
		    PortDisplayHelper::getMidiPortTypeName(portType);
		if (jack > 0)
			portTypeName += " " + std::to_string(jack);
		infoSections->push_back(
		    new MultiInfoListEntry(MultiInfoListEntry::SECTION, portTypeName));
		std::vector<RetSetMidiPortInfo *> *midiPortInfos = it->second;
		getMidiPorts(midiPortInfos);
	}
}

QWidget *PortsWidget::createWidget(MultiInfoListEntry *entry) {
	std::cout << "create PortsWidget" << std::endl;
	RetSetMidiPortInfo *midiPortInfo =
	    static_cast<RetSetMidiPortInfo *>(entry->message);
	int portNumber = static_cast<int>(midiPortInfo->getPortId());
	QTabWidget *portTabWidget = new QTabWidget(this);
	PortInfoWidget *portInfoWidget = new PortInfoWidget(midiPortInfo);
	connect(portInfoWidget, &PortInfoWidget::changePortName, entry,
	        &MultiInfoListEntry::changeName);
	portTabWidget->addTab(portInfoWidget, "MIDI-Port Info");
	if (device->getCommands()->isCommandSupported(
	        Command::GET_MIDI_PORT_ROUTE)) {
		PortRoutingWidget *w =
		    new PortRoutingWidget(device, portNumber, this->parentWidget());
		QScrollArea *a = new QScrollArea(portTabWidget);
		a->setWidget(w);
		portTabWidget->addTab(a, tr("MIDI-Port Routing"));
	}
	if (device->getCommands()->isCommandSupported(
	        Command::GET_MIDI_PORT_FILTER)) {
		PortFilterWidget *portFilterWidget =
		    new PortFilterWidget(device, portNumber, this->parentWidget());
		portTabWidget->addTab(portFilterWidget, tr("MIDI-Port Filter"));
	}
	if (device->getCommands()->isCommandSupported(
	        Command::GET_MIDI_PORT_REMAP)) {
		PortRemapWidget *portRemapWidget =
		    new PortRemapWidget(device, portNumber, this->parentWidget());
		portTabWidget->addTab(portRemapWidget, tr("MIDI-Port Remap"));
	}
	return portTabWidget;
}
<commit_msg>don't show ports as disabled when input is disabled.<commit_after>#include "portswidget.h"
#include "../sysex/retcommandlist.h"
#include "../sysex/retsetmidiinfo.h"
#include "portdisplayhelper.h"
#include "portfilterwidget.h"
#include "portinfowidget.h"
#include "portremapwidget.h"
#include "portroutingwidget.h"

#include <QLabel>
#include <QListWidgetItem>
#include <QScrollArea>

PortsWidget::PortsWidget(MioMain *parent, Device *device, QString windowTitle)
	: MultiInfoWidget(parent, device, windowTitle) {
	infoSections = new std::vector<MultiInfoListEntry *>();
	if (device->getCommands()->isCommandSupported(
			Command::GET_MIDI_PORT_INFO)) {
		getMidiPortSections(device);
	}
}

PortsWidget::~PortsWidget() {
	/* if (infoSections != nullptr) {
		infoSections->clear();
		delete infoSections;
	}*/
}

void PortsWidget::getMidiPorts(
	std::vector<RetSetMidiPortInfo *> *midiPortInfos) {
	std::vector<RetSetMidiPortInfo *>::iterator it;
	for (it = midiPortInfos->begin(); it != midiPortInfos->end(); ++it) {
		RetSetMidiPortInfo *midiPortInfo = *it;
		MultiInfoListEntry *entry = new MultiInfoListEntry(
			MultiInfoListEntry::PORT_ROUTING, midiPortInfo->getPortName());
		entry->icon =
			PortDisplayHelper::getPortIcon(midiPortInfo->getPortType());
		entry->message = midiPortInfo;
		// TODO: mark port as disabled
		// entry->enabled = midiPortInfo->getInputEnabled();
		infoSections->push_back(entry);
	}
}

void PortsWidget::getMidiPortSections(Device *device) {
	MIDI_PORT_INFOS *midiPortInfoSections = device->getMidiPortInfos();
	std::map<int, std::vector<RetSetMidiPortInfo *> *>::iterator it;
	for (it = midiPortInfoSections->begin(); it != midiPortInfoSections->end();
		 ++it) {
		int section = it->first;
		int jack = section & 255;
		MidiPortType portType = static_cast<MidiPortType>(section >> 8);
		std::string portTypeName =
			PortDisplayHelper::getMidiPortTypeName(portType);
		if (jack > 0)
			portTypeName += " " + std::to_string(jack);
		infoSections->push_back(
			new MultiInfoListEntry(MultiInfoListEntry::SECTION, portTypeName));
		std::vector<RetSetMidiPortInfo *> *midiPortInfos = it->second;
		getMidiPorts(midiPortInfos);
	}
}

QWidget *PortsWidget::createWidget(MultiInfoListEntry *entry) {
	std::cout << "create PortsWidget" << std::endl;
	RetSetMidiPortInfo *midiPortInfo =
		static_cast<RetSetMidiPortInfo *>(entry->message);
	int portNumber = static_cast<int>(midiPortInfo->getPortId());
	QTabWidget *portTabWidget = new QTabWidget(this);
	PortInfoWidget *portInfoWidget = new PortInfoWidget(midiPortInfo);
	connect(portInfoWidget, &PortInfoWidget::changePortName, entry,
			&MultiInfoListEntry::changeName);
	portTabWidget->addTab(portInfoWidget, "MIDI-Port Info");
	if (device->getCommands()->isCommandSupported(
			Command::GET_MIDI_PORT_ROUTE)) {
		PortRoutingWidget *w =
			new PortRoutingWidget(device, portNumber, this->parentWidget());
		QScrollArea *a = new QScrollArea(portTabWidget);
		a->setWidget(w);
		portTabWidget->addTab(a, tr("MIDI-Port Routing"));
	}
	if (device->getCommands()->isCommandSupported(
			Command::GET_MIDI_PORT_FILTER)) {
		PortFilterWidget *portFilterWidget =
			new PortFilterWidget(device, portNumber, this->parentWidget());
		portTabWidget->addTab(portFilterWidget, tr("MIDI-Port Filter"));
	}
	if (device->getCommands()->isCommandSupported(
			Command::GET_MIDI_PORT_REMAP)) {
		PortRemapWidget *portRemapWidget =
			new PortRemapWidget(device, portNumber, this->parentWidget());
		portTabWidget->addTab(portRemapWidget, tr("MIDI-Port Remap"));
	}
	return portTabWidget;
}
<|endoftext|>


<commit_before>#include "setupdialog.h"

WARNINGS_DISABLE
#include <QDateTime>
#include <QDir>
#include <QFileDialog>
#include <QFileInfo>
#include <QStandardPaths>

// This is used for QHostInfo::localHostName().  It could be replaced with
// QSysInfo::machineHostName() to remove the dependency on the Qt network
// library, but only if we require Qt 5.6+.
#include <QHostInfo>

#include "ui_setupdialog.h"
WARNINGS_ENABLE

#include "debug.h"
#include "tasks-defs.h"
#include "utils.h"

#include <TSettings.h>

SetupDialog::SetupDialog(QWidget *parent)
    : QDialog(parent), _ui(new Ui::SetupDialog)
{
    _ui->setupUi(this);
    setWindowFlags((windowFlags() | Qt::CustomizeWindowHint)
                   & ~Qt::WindowMaximizeButtonHint);

    // This should be done before connecting objects to
    // validateCLIPage() to avoid calling that function unnecessarily.
    initCLIPage();
    initRegisterPage();

    // All pages
    connect(_ui->backButton, &QPushButton::clicked, this,
            &SetupDialog::backButtonClicked);
    connect(_ui->nextButton, &QPushButton::clicked, this,
            &SetupDialog::nextButtonClicked);

    connect(_ui->wizardStackedWidget, &QStackedWidget::currentChanged, this,
            &SetupDialog::wizardPageChanged);

    // Advanced setup page
    connect(_ui->cliAdvancedButton, &QPushButton::toggled,
            _ui->cliAdvancedWidget, &QWidget::setVisible);
    connect(_ui->tarsnapPathBrowseButton, &QPushButton::clicked, this,
            &SetupDialog::showTarsnapPathBrowse);
    connect(_ui->tarsnapPathLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateCLIPage);
    connect(_ui->tarsnapCacheBrowseButton, &QPushButton::clicked, this,
            &SetupDialog::showTarsnapCacheBrowse);
    connect(_ui->tarsnapCacheLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateCLIPage);
    connect(_ui->appDataBrowseButton, &QPushButton::clicked, this,
            &SetupDialog::showAppDataBrowse);
    connect(_ui->appDataPathLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateCLIPage);

    // Register page
    connect(_ui->createKeyfileButton, &QPushButton::clicked, this,
            &SetupDialog::createKeyfile);
    connect(_ui->useExistingKeyfileButton, &QPushButton::clicked, this,
            &SetupDialog::useExistingKeyfile);
    connect(_ui->tarsnapUserLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateRegisterPage);
    connect(_ui->tarsnapPasswordLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateRegisterPage);
    connect(_ui->machineNameLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateRegisterPage);
    connect(_ui->machineKeyCombo, &QComboBox::currentTextChanged, this,
            &SetupDialog::validateRegisterPage);
    connect(_ui->browseKeyButton, &QPushButton::clicked, this,
            &SetupDialog::registerHaveKeyBrowse);

    // Initial state
    _ui->wizardStackedWidget->setCurrentWidget(_ui->welcomePage);
    wizardPageChanged(0);
}

SetupDialog::~SetupDialog()
{
    delete _ui;
}

void SetupDialog::initCLIPage()
{
    QString tarsnapDir;
    QString appDataDir;
    QString tarsnapCacheDir;

    // CLI path
    tarsnapDir = Utils::findTarsnapClientInPath("", true);
    _ui->tarsnapPathLineEdit->setText(tarsnapDir);

    // appdata dir
    appDataDir = QStandardPaths::writableLocation(APPDATA);
    // Create directory (if needed)
    QDir keysDir(appDataDir);
    if(!keysDir.exists())
        keysDir.mkpath(appDataDir);
    _ui->appDataPathLineEdit->setText(appDataDir);

    /// cache dir
    tarsnapCacheDir =
        QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
    QDir cacheDir(tarsnapCacheDir);
    // Create directory (if needed)
    if(!cacheDir.exists())
        cacheDir.mkpath(tarsnapCacheDir);
    _ui->tarsnapCacheLineEdit->setText(tarsnapCacheDir);

    // We only want to expand the widget if there's a problem
    _ui->cliAdvancedWidget->hide();
}

void SetupDialog::initRegisterPage()
{
    // default machine name
    _ui->machineNameLineEdit->setText(QHostInfo::localHostName());

    // find any existing keys
    QString appDataDir = _ui->appDataPathLineEdit->text();
    for(const QFileInfo &file : Utils::findKeysInPath(appDataDir))
        _ui->machineKeyCombo->addItem(file.canonicalFilePath());
}

void SetupDialog::wizardPageChanged(int)
{
    // Values which might be overwritten below.
    _ui->backButton->setText(tr("Back"));
    _ui->nextButton->setText(tr("Next"));
    _ui->nextButton->setEnabled(true);

    if(_ui->wizardStackedWidget->currentWidget() == _ui->welcomePage)
    {
        _ui->titleLabel->setText(tr("Setup wizard"));
        _ui->backButton->setText(tr("Skip wizard"));
    }
    else if(_ui->wizardStackedWidget->currentWidget() == _ui->cliPage)
    {
        _ui->titleLabel->setText(tr("Command-line utilities"));
    }
    else if(_ui->wizardStackedWidget->currentWidget() == _ui->registerPage)
    {
        _ui->titleLabel->setText(tr("Register with server"));
        _ui->nextButton->setText(tr("Register machine"));
        if(_ui->machineKeyCombo->count() > 0)
        {
            _ui->useExistingKeyfileButton->setChecked(true);
            useExistingKeyfile();
        }
        else
        {
            _ui->createKeyfileButton->setChecked(true);
            createKeyfile();
        }
    }
    else if(_ui->wizardStackedWidget->currentWidget() == _ui->donePage)
    {
        _ui->titleLabel->setText(tr("Setup complete!"));
        _ui->nextButton->setText(tr("Start using Tarsnap"));
    }
}

#ifdef QT_TESTLIB_LIB
void SetupDialog::back()
{
    backButtonClicked();
}

void SetupDialog::next()
{
    nextButtonClicked();
}

Ui::SetupDialog *SetupDialog::get_ui()
{
    return _ui;
}
#endif

void SetupDialog::backButtonClicked()
{
    int nextIndex = _ui->wizardStackedWidget->currentIndex() - 1;
    if(nextIndex < 0)
        finishedWizard();
    else
        _ui->wizardStackedWidget->setCurrentIndex(nextIndex);
}

void SetupDialog::nextButtonClicked()
{
    if(_ui->wizardStackedWidget->currentWidget() == _ui->registerPage)
        registerMachine();
    else if(_ui->wizardStackedWidget->currentWidget() == _ui->donePage)
        finishedWizard();
    else
        setNextPage();
}

void SetupDialog::setNextPage()
{
    if(_ui->wizardStackedWidget->currentWidget() == _ui->welcomePage)
    {
        _ui->wizardStackedWidget->setCurrentWidget(_ui->cliPage);
        // Disable this until we know the version number.
        _ui->nextButton->setEnabled(false);
        bool advancedOk = validateCLIPage();
        _ui->cliAdvancedButton->setChecked(!advancedOk);
    }
    else if(_ui->wizardStackedWidget->currentWidget() == _ui->cliPage)
    {
        _ui->wizardStackedWidget->setCurrentWidget(_ui->registerPage);
        if(validateRegisterPage())
            _ui->nextButton->setFocus();
    }
    else if(_ui->wizardStackedWidget->currentWidget() == _ui->registerPage)
    {
        _ui->wizardStackedWidget->setCurrentWidget(_ui->donePage);
    }
}

void SetupDialog::showTarsnapPathBrowse()
{
    QString tarsnapPath =
        QFileDialog::getExistingDirectory(this, tr("Find Tarsnap client"),
                                          _ui->tarsnapPathLineEdit->text());
    _ui->tarsnapPathLineEdit->setText(tarsnapPath);
}

void SetupDialog::showTarsnapCacheBrowse()
{
    QString tarsnapCacheDir =
        QFileDialog::getExistingDirectory(this, tr("Tarsnap cache location"),
                                          _ui->tarsnapCacheLineEdit->text());
    _ui->tarsnapCacheLineEdit->setText(tarsnapCacheDir);
}

void SetupDialog::showAppDataBrowse()
{
    QString appDataDir =
        QFileDialog::getExistingDirectory(this, tr("App data location"),
                                          _ui->appDataPathLineEdit->text());
    _ui->appDataPathLineEdit->setText(appDataDir);
}

bool SetupDialog::validateCLIPage()
{
    QString tarsnapDir;
    QString appDataDir;
    QString tarsnapCacheDir;

    bool result = true;

    appDataDir = Utils::validateAppDataDir(_ui->appDataPathLineEdit->text());
    if(appDataDir.isEmpty())
    {
        _ui->cliValidationLabel->setText(tr("Invalid App data directory set."));
        result = false;
    }
    else
    {
        TSettings settings;
        settings.setValue("app/app_data", appDataDir);
    }

    tarsnapCacheDir =
        Utils::validateTarsnapCache(_ui->tarsnapCacheLineEdit->text());
    if(result && tarsnapCacheDir.isEmpty())
    {
        _ui->cliValidationLabel->setText(tr("Invalid Tarsnap cache directory"
                                            " set."));
        result = false;
    }

    tarsnapDir =
        Utils::findTarsnapClientInPath(_ui->tarsnapPathLineEdit->text(), true);
    if(result && tarsnapDir.isEmpty())
    {
        _ui->cliValidationLabel->setText(
            tr("Tarsnap utilities not found. Visit "
               "tarsnap.com "
               "for help with acquiring them."));
        result = false;
    }
    else if(result)
    {
        TSettings settings;
        settings.setValue("tarsnap/path", tarsnapDir);
        // Wipe previous version number before asking for a new one.
        settings.setValue("tarsnap/version", "");
        emit tarsnapVersionRequested();
    }

    // If `results` is true, then we might still be waiting for
    // the result of tarsnapVersion, so we can't enable this yet.
    if(!result)
        _ui->nextButton->setEnabled(false);

    return result;
}

void SetupDialog::createKeyfile()
{
    _ui->registerKeyStackedWidget->setCurrentWidget(_ui->createKeyfileSubpage);
    // Share machineNameLineEdit in both pages of the keyStackedWidget
    _ui->gridKeyNoLayout->addWidget(_ui->machineNameLineEdit, 1, 1);
    _ui->statusLabel->clear();
    if(validateRegisterPage())
        _ui->nextButton->setFocus();
}

void SetupDialog::useExistingKeyfile()
{
    _ui->registerKeyStackedWidget->setCurrentWidget(
        _ui->useExistingKeyfileSubpage);
    // Share machineNameLineEdit in both pages of the keyStackedWidget
    _ui->gridKeyYesLayout->addWidget(_ui->machineNameLineEdit, 1, 1);
    _ui->statusLabel->clear();
    if(validateRegisterPage())
        _ui->nextButton->setFocus();
}

bool SetupDialog::validateRegisterPage()
{
    bool result = false;
    if(_ui->useExistingKeyfileButton->isChecked())
    {
        // user specified key
        QFileInfo machineKeyFile(_ui->machineKeyCombo->currentText());
        if(!_ui->machineNameLineEdit->text().isEmpty()
           && machineKeyFile.exists() && machineKeyFile.isFile()
           && machineKeyFile.isReadable())
        {
            result = true;
        }
    }
    else
    {
        if(!_ui->tarsnapUserLineEdit->text().isEmpty()
           && !_ui->tarsnapPasswordLineEdit->text().isEmpty()
           && !_ui->machineNameLineEdit->text().isEmpty())
        {
            result = true;
        }
    }

    _ui->nextButton->setEnabled(result);
    return result;
}

void SetupDialog::registerHaveKeyBrowse()
{
    QString keyFilter = tr("Tarsnap key files (*.key *.keys)");
    QString existingMachineKey =
        QFileDialog::getOpenFileName(this,
                                     tr("Browse for existing machine key"), "",
                                     tr("All files (*);;") + keyFilter,
                                     &keyFilter);
    if(!existingMachineKey.isEmpty())
        _ui->machineKeyCombo->setCurrentText(existingMachineKey);
}

void SetupDialog::registerMachine()
{
    TSettings settings;

    QString tarsnapKeyFile;
    QString appDataDir;

    // Sanity check app data dir.
    appDataDir = settings.value("app/app_data", "").toString();
    if(appDataDir.isEmpty())
    {
        // We should never get here, but handle the error anyway
        _ui->statusLabel->setText("No app data dir set");
        _ui->statusLabel->setStyleSheet("#statusLabel { color: darkred; }");
        _ui->nextButton->setEnabled(false);
        return;
    }

    bool useExistingKeyfile = false;
    _ui->nextButton->setEnabled(false);
    _ui->statusLabel->clear();
    _ui->statusLabel->setStyleSheet("");
    if(_ui->useExistingKeyfileButton->isChecked())
    {
        useExistingKeyfile = true;
        _ui->statusLabel->setText("Verifying archive integrity...");
        tarsnapKeyFile = _ui->machineKeyCombo->currentText();
    }
    else
    {
        _ui->statusLabel->setText("Generating keyfile...");
        tarsnapKeyFile =
            appDataDir + QDir::separator() + _ui->machineNameLineEdit->text()
            + "-" + QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss")
            + ".key";
    }

    settings.setValue("tarsnap/cache", _ui->tarsnapCacheLineEdit->text());
    settings.setValue("tarsnap/key", tarsnapKeyFile);
    settings.setValue("tarsnap/user", _ui->tarsnapUserLineEdit->text());
    settings.setValue("tarsnap/machine", _ui->machineNameLineEdit->text());

    emit registerMachineRequested(_ui->tarsnapPasswordLineEdit->text(),
                                  useExistingKeyfile);
}

void SetupDialog::registerMachineResponse(TaskStatus status, QString reason)
{
    TSettings settings;

    // Get keyfile and sanity check.
    QString tarsnapKeyFile = settings.value("tarsnap/key", "").toString();
    if((status == TaskStatus::Completed) && (tarsnapKeyFile.isEmpty()))
    {
        // This should never happen
        status = TaskStatus::Failed;
        reason = "No keyfile set";
    }

    switch(status)
    {
    case TaskStatus::Completed:
        _ui->statusLabel->clear();

        _ui->doneKeyFileNameLabel->setText(
            QString("%2")
                .arg(QUrl::fromLocalFile(
                         QFileInfo(tarsnapKeyFile).absolutePath())
                         .toString())
                .arg(tarsnapKeyFile));
        _ui->nextButton->setEnabled(true);
        setNextPage();
        break;
    case TaskStatus::Failed:
        _ui->statusLabel->setText(reason);
        _ui->statusLabel->setStyleSheet("#statusLabel { color: darkred; }");
        _ui->nextButton->setEnabled(true);
        break;
    default:
        // We shouldn't receive anything else, so ignore it.
        break;
    }
}

void SetupDialog::updateLoadingAnimation(bool idle)
{
    _ui->busyWidget->animate(!idle);
}

void SetupDialog::tarsnapVersionResponse(TaskStatus status,
                                         QString    versionString)
{
    TSettings settings;

    // Sanity check.
    if(versionString.isEmpty())
        status = TaskStatus::Failed;

    // Handle response.
    switch(status)
    {
    case TaskStatus::Completed:
        _ui->cliValidationLabel->setText(tr("Tarsnap CLI version ")
                                         + versionString + tr(" detected.  ✔"));
        // Record value
        settings.setValue("tarsnap/version", versionString);
        // Enable progress
        _ui->nextButton->setEnabled(true);
        _ui->nextButton->setFocus();
        break;
    case TaskStatus::VersionTooLow:
        // Don't record the too-low version number.
        _ui->cliValidationLabel->setText(
            tr("Tarsnap CLI version ") + versionString
            + tr(" too low; must be at least %1").arg(TARSNAP_MIN_VERSION));
        break;
    case TaskStatus::Failed:
        _ui->cliValidationLabel->setText(
            tr("Error retrieving Tarsnap CLI verison"));
        break;
    default:
        break;
    }
}

void SetupDialog::finishedWizard()
{
    TSettings settings;

    // We've either completed the setup wizard, or deliberately skipped it.
    settings.setValue("app/wizard_done", true);

    accept();
}

void SetupDialog::reject()
{
    // Remove any saved settings
    TSettings settings;
    settings.clear();

    // Call parent function
    QDialog::reject();
}
<commit_msg>SetupDialog: don't allow back(), next() without buttons<commit_after>#include "setupdialog.h"

WARNINGS_DISABLE
#include <QDateTime>
#include <QDir>
#include <QFileDialog>
#include <QFileInfo>
#include <QStandardPaths>

// This is used for QHostInfo::localHostName().  It could be replaced with
// QSysInfo::machineHostName() to remove the dependency on the Qt network
// library, but only if we require Qt 5.6+.
#include <QHostInfo>

#include "ui_setupdialog.h"
WARNINGS_ENABLE

#include "debug.h"
#include "tasks-defs.h"
#include "utils.h"

#include <TSettings.h>

SetupDialog::SetupDialog(QWidget *parent)
    : QDialog(parent), _ui(new Ui::SetupDialog)
{
    _ui->setupUi(this);
    setWindowFlags((windowFlags() | Qt::CustomizeWindowHint)
                   & ~Qt::WindowMaximizeButtonHint);

    // This should be done before connecting objects to
    // validateCLIPage() to avoid calling that function unnecessarily.
    initCLIPage();
    initRegisterPage();

    // All pages
    connect(_ui->backButton, &QPushButton::clicked, this,
            &SetupDialog::backButtonClicked);
    connect(_ui->nextButton, &QPushButton::clicked, this,
            &SetupDialog::nextButtonClicked);

    connect(_ui->wizardStackedWidget, &QStackedWidget::currentChanged, this,
            &SetupDialog::wizardPageChanged);

    // Advanced setup page
    connect(_ui->cliAdvancedButton, &QPushButton::toggled,
            _ui->cliAdvancedWidget, &QWidget::setVisible);
    connect(_ui->tarsnapPathBrowseButton, &QPushButton::clicked, this,
            &SetupDialog::showTarsnapPathBrowse);
    connect(_ui->tarsnapPathLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateCLIPage);
    connect(_ui->tarsnapCacheBrowseButton, &QPushButton::clicked, this,
            &SetupDialog::showTarsnapCacheBrowse);
    connect(_ui->tarsnapCacheLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateCLIPage);
    connect(_ui->appDataBrowseButton, &QPushButton::clicked, this,
            &SetupDialog::showAppDataBrowse);
    connect(_ui->appDataPathLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateCLIPage);

    // Register page
    connect(_ui->createKeyfileButton, &QPushButton::clicked, this,
            &SetupDialog::createKeyfile);
    connect(_ui->useExistingKeyfileButton, &QPushButton::clicked, this,
            &SetupDialog::useExistingKeyfile);
    connect(_ui->tarsnapUserLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateRegisterPage);
    connect(_ui->tarsnapPasswordLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateRegisterPage);
    connect(_ui->machineNameLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateRegisterPage);
    connect(_ui->machineKeyCombo, &QComboBox::currentTextChanged, this,
            &SetupDialog::validateRegisterPage);
    connect(_ui->browseKeyButton, &QPushButton::clicked, this,
            &SetupDialog::registerHaveKeyBrowse);

    // Initial state
    _ui->wizardStackedWidget->setCurrentWidget(_ui->welcomePage);
    wizardPageChanged(0);
}

SetupDialog::~SetupDialog()
{
    delete _ui;
}

void SetupDialog::initCLIPage()
{
    QString tarsnapDir;
    QString appDataDir;
    QString tarsnapCacheDir;

    // CLI path
    tarsnapDir = Utils::findTarsnapClientInPath("", true);
    _ui->tarsnapPathLineEdit->setText(tarsnapDir);

    // appdata dir
    appDataDir = QStandardPaths::writableLocation(APPDATA);
    // Create directory (if needed)
    QDir keysDir(appDataDir);
    if(!keysDir.exists())
        keysDir.mkpath(appDataDir);
    _ui->appDataPathLineEdit->setText(appDataDir);

    /// cache dir
    tarsnapCacheDir =
        QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
    QDir cacheDir(tarsnapCacheDir);
    // Create directory (if needed)
    if(!cacheDir.exists())
        cacheDir.mkpath(tarsnapCacheDir);
    _ui->tarsnapCacheLineEdit->setText(tarsnapCacheDir);

    // We only want to expand the widget if there's a problem
    _ui->cliAdvancedWidget->hide();
}

void SetupDialog::initRegisterPage()
{
    // default machine name
    _ui->machineNameLineEdit->setText(QHostInfo::localHostName());

    // find any existing keys
    QString appDataDir = _ui->appDataPathLineEdit->text();
    for(const QFileInfo &file : Utils::findKeysInPath(appDataDir))
        _ui->machineKeyCombo->addItem(file.canonicalFilePath());
}

void SetupDialog::wizardPageChanged(int)
{
    // Values which might be overwritten below.
    _ui->backButton->setText(tr("Back"));
    _ui->nextButton->setText(tr("Next"));
    _ui->nextButton->setEnabled(true);

    if(_ui->wizardStackedWidget->currentWidget() == _ui->welcomePage)
    {
        _ui->titleLabel->setText(tr("Setup wizard"));
        _ui->backButton->setText(tr("Skip wizard"));
    }
    else if(_ui->wizardStackedWidget->currentWidget() == _ui->cliPage)
    {
        _ui->titleLabel->setText(tr("Command-line utilities"));
    }
    else if(_ui->wizardStackedWidget->currentWidget() == _ui->registerPage)
    {
        _ui->titleLabel->setText(tr("Register with server"));
        _ui->nextButton->setText(tr("Register machine"));
        if(_ui->machineKeyCombo->count() > 0)
        {
            _ui->useExistingKeyfileButton->setChecked(true);
            useExistingKeyfile();
        }
        else
        {
            _ui->createKeyfileButton->setChecked(true);
            createKeyfile();
        }
    }
    else if(_ui->wizardStackedWidget->currentWidget() == _ui->donePage)
    {
        _ui->titleLabel->setText(tr("Setup complete!"));
        _ui->nextButton->setText(tr("Start using Tarsnap"));
    }
}

#ifdef QT_TESTLIB_LIB
void SetupDialog::back()
{
    if(!_ui->backButton->isEnabled())
        return;
    backButtonClicked();
}

void SetupDialog::next()
{
    if(!_ui->nextButton->isEnabled())
        return;
    nextButtonClicked();
}

Ui::SetupDialog *SetupDialog::get_ui()
{
    return _ui;
}
#endif

void SetupDialog::backButtonClicked()
{
    int nextIndex = _ui->wizardStackedWidget->currentIndex() - 1;
    if(nextIndex < 0)
        finishedWizard();
    else
        _ui->wizardStackedWidget->setCurrentIndex(nextIndex);
}

void SetupDialog::nextButtonClicked()
{
    if(_ui->wizardStackedWidget->currentWidget() == _ui->registerPage)
        registerMachine();
    else if(_ui->wizardStackedWidget->currentWidget() == _ui->donePage)
        finishedWizard();
    else
        setNextPage();
}

void SetupDialog::setNextPage()
{
    if(_ui->wizardStackedWidget->currentWidget() == _ui->welcomePage)
    {
        _ui->wizardStackedWidget->setCurrentWidget(_ui->cliPage);
        // Disable this until we know the version number.
        _ui->nextButton->setEnabled(false);
        bool advancedOk = validateCLIPage();
        _ui->cliAdvancedButton->setChecked(!advancedOk);
    }
    else if(_ui->wizardStackedWidget->currentWidget() == _ui->cliPage)
    {
        _ui->wizardStackedWidget->setCurrentWidget(_ui->registerPage);
        if(validateRegisterPage())
            _ui->nextButton->setFocus();
    }
    else if(_ui->wizardStackedWidget->currentWidget() == _ui->registerPage)
    {
        _ui->wizardStackedWidget->setCurrentWidget(_ui->donePage);
    }
}

void SetupDialog::showTarsnapPathBrowse()
{
    QString tarsnapPath =
        QFileDialog::getExistingDirectory(this, tr("Find Tarsnap client"),
                                          _ui->tarsnapPathLineEdit->text());
    _ui->tarsnapPathLineEdit->setText(tarsnapPath);
}

void SetupDialog::showTarsnapCacheBrowse()
{
    QString tarsnapCacheDir =
        QFileDialog::getExistingDirectory(this, tr("Tarsnap cache location"),
                                          _ui->tarsnapCacheLineEdit->text());
    _ui->tarsnapCacheLineEdit->setText(tarsnapCacheDir);
}

void SetupDialog::showAppDataBrowse()
{
    QString appDataDir =
        QFileDialog::getExistingDirectory(this, tr("App data location"),
                                          _ui->appDataPathLineEdit->text());
    _ui->appDataPathLineEdit->setText(appDataDir);
}

bool SetupDialog::validateCLIPage()
{
    QString tarsnapDir;
    QString appDataDir;
    QString tarsnapCacheDir;

    bool result = true;

    appDataDir = Utils::validateAppDataDir(_ui->appDataPathLineEdit->text());
    if(appDataDir.isEmpty())
    {
        _ui->cliValidationLabel->setText(tr("Invalid App data directory set."));
        result = false;
    }
    else
    {
        TSettings settings;
        settings.setValue("app/app_data", appDataDir);
    }

    tarsnapCacheDir =
        Utils::validateTarsnapCache(_ui->tarsnapCacheLineEdit->text());
    if(result && tarsnapCacheDir.isEmpty())
    {
        _ui->cliValidationLabel->setText(tr("Invalid Tarsnap cache directory"
                                            " set."));
        result = false;
    }

    tarsnapDir =
        Utils::findTarsnapClientInPath(_ui->tarsnapPathLineEdit->text(), true);
    if(result && tarsnapDir.isEmpty())
    {
        _ui->cliValidationLabel->setText(
            tr("Tarsnap utilities not found. Visit "
               "tarsnap.com "
               "for help with acquiring them."));
        result = false;
    }
    else if(result)
    {
        TSettings settings;
        settings.setValue("tarsnap/path", tarsnapDir);
        // Wipe previous version number before asking for a new one.
        settings.setValue("tarsnap/version", "");
        emit tarsnapVersionRequested();
    }

    // If `results` is true, then we might still be waiting for
    // the result of tarsnapVersion, so we can't enable this yet.
    if(!result)
        _ui->nextButton->setEnabled(false);

    return result;
}

void SetupDialog::createKeyfile()
{
    _ui->registerKeyStackedWidget->setCurrentWidget(_ui->createKeyfileSubpage);
    // Share machineNameLineEdit in both pages of the keyStackedWidget
    _ui->gridKeyNoLayout->addWidget(_ui->machineNameLineEdit, 1, 1);
    _ui->statusLabel->clear();
    if(validateRegisterPage())
        _ui->nextButton->setFocus();
}

void SetupDialog::useExistingKeyfile()
{
    _ui->registerKeyStackedWidget->setCurrentWidget(
        _ui->useExistingKeyfileSubpage);
    // Share machineNameLineEdit in both pages of the keyStackedWidget
    _ui->gridKeyYesLayout->addWidget(_ui->machineNameLineEdit, 1, 1);
    _ui->statusLabel->clear();
    if(validateRegisterPage())
        _ui->nextButton->setFocus();
}

bool SetupDialog::validateRegisterPage()
{
    bool result = false;
    if(_ui->useExistingKeyfileButton->isChecked())
    {
        // user specified key
        QFileInfo machineKeyFile(_ui->machineKeyCombo->currentText());
        if(!_ui->machineNameLineEdit->text().isEmpty()
           && machineKeyFile.exists() && machineKeyFile.isFile()
           && machineKeyFile.isReadable())
        {
            result = true;
        }
    }
    else
    {
        if(!_ui->tarsnapUserLineEdit->text().isEmpty()
           && !_ui->tarsnapPasswordLineEdit->text().isEmpty()
           && !_ui->machineNameLineEdit->text().isEmpty())
        {
            result = true;
        }
    }

    _ui->nextButton->setEnabled(result);
    return result;
}

void SetupDialog::registerHaveKeyBrowse()
{
    QString keyFilter = tr("Tarsnap key files (*.key *.keys)");
    QString existingMachineKey =
        QFileDialog::getOpenFileName(this,
                                     tr("Browse for existing machine key"), "",
                                     tr("All files (*);;") + keyFilter,
                                     &keyFilter);
    if(!existingMachineKey.isEmpty())
        _ui->machineKeyCombo->setCurrentText(existingMachineKey);
}

void SetupDialog::registerMachine()
{
    TSettings settings;

    QString tarsnapKeyFile;
    QString appDataDir;

    // Sanity check app data dir.
    appDataDir = settings.value("app/app_data", "").toString();
    if(appDataDir.isEmpty())
    {
        // We should never get here, but handle the error anyway
        _ui->statusLabel->setText("No app data dir set");
        _ui->statusLabel->setStyleSheet("#statusLabel { color: darkred; }");
        _ui->nextButton->setEnabled(false);
        return;
    }

    bool useExistingKeyfile = false;
    _ui->nextButton->setEnabled(false);
    _ui->statusLabel->clear();
    _ui->statusLabel->setStyleSheet("");
    if(_ui->useExistingKeyfileButton->isChecked())
    {
        useExistingKeyfile = true;
        _ui->statusLabel->setText("Verifying archive integrity...");
        tarsnapKeyFile = _ui->machineKeyCombo->currentText();
    }
    else
    {
        _ui->statusLabel->setText("Generating keyfile...");
        tarsnapKeyFile =
            appDataDir + QDir::separator() + _ui->machineNameLineEdit->text()
            + "-" + QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss")
            + ".key";
    }

    settings.setValue("tarsnap/cache", _ui->tarsnapCacheLineEdit->text());
    settings.setValue("tarsnap/key", tarsnapKeyFile);
    settings.setValue("tarsnap/user", _ui->tarsnapUserLineEdit->text());
    settings.setValue("tarsnap/machine", _ui->machineNameLineEdit->text());

    emit registerMachineRequested(_ui->tarsnapPasswordLineEdit->text(),
                                  useExistingKeyfile);
}

void SetupDialog::registerMachineResponse(TaskStatus status, QString reason)
{
    TSettings settings;

    // Get keyfile and sanity check.
    QString tarsnapKeyFile = settings.value("tarsnap/key", "").toString();
    if((status == TaskStatus::Completed) && (tarsnapKeyFile.isEmpty()))
    {
        // This should never happen
        status = TaskStatus::Failed;
        reason = "No keyfile set";
    }

    switch(status)
    {
    case TaskStatus::Completed:
        _ui->statusLabel->clear();

        _ui->doneKeyFileNameLabel->setText(
            QString("%2")
                .arg(QUrl::fromLocalFile(
                         QFileInfo(tarsnapKeyFile).absolutePath())
                         .toString())
                .arg(tarsnapKeyFile));
        _ui->nextButton->setEnabled(true);
        setNextPage();
        break;
    case TaskStatus::Failed:
        _ui->statusLabel->setText(reason);
        _ui->statusLabel->setStyleSheet("#statusLabel { color: darkred; }");
        _ui->nextButton->setEnabled(true);
        break;
    default:
        // We shouldn't receive anything else, so ignore it.
        break;
    }
}

void SetupDialog::updateLoadingAnimation(bool idle)
{
    _ui->busyWidget->animate(!idle);
}

void SetupDialog::tarsnapVersionResponse(TaskStatus status,
                                         QString    versionString)
{
    TSettings settings;

    // Sanity check.
    if(versionString.isEmpty())
        status = TaskStatus::Failed;

    // Handle response.
    switch(status)
    {
    case TaskStatus::Completed:
        _ui->cliValidationLabel->setText(tr("Tarsnap CLI version ")
                                         + versionString + tr(" detected.  ✔"));
        // Record value
        settings.setValue("tarsnap/version", versionString);
        // Enable progress
        _ui->nextButton->setEnabled(true);
        _ui->nextButton->setFocus();
        break;
    case TaskStatus::VersionTooLow:
        // Don't record the too-low version number.
        _ui->cliValidationLabel->setText(
            tr("Tarsnap CLI version ") + versionString
            + tr(" too low; must be at least %1").arg(TARSNAP_MIN_VERSION));
        break;
    case TaskStatus::Failed:
        _ui->cliValidationLabel->setText(
            tr("Error retrieving Tarsnap CLI verison"));
        break;
    default:
        break;
    }
}

void SetupDialog::finishedWizard()
{
    TSettings settings;

    // We've either completed the setup wizard, or deliberately skipped it.
    settings.setValue("app/wizard_done", true);

    accept();
}

void SetupDialog::reject()
{
    // Remove any saved settings
    TSettings settings;
    settings.clear();

    // Call parent function
    QDialog::reject();
}
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 */

#if !defined(XMLURL_HPP)
#define XMLURL_HPP

#include <xercesc/util/XercesDefs.hpp>
#include <xercesc/util/XMLException.hpp>

XERCES_CPP_NAMESPACE_BEGIN

class BinInputStream;

//
//  This class supports file, http, and ftp style URLs. All others are
//  rejected
//
class XMLUTIL_EXPORT XMLURL
{
public:
    // -----------------------------------------------------------------------
    //  Class types
    //
    //  And they must remain in this order because they are indexes into an
    //  array internally!
    // -----------------------------------------------------------------------
    enum Protocols
    {
        File
        , HTTP
        , FTP

        , Protocols_Count
        , Unknown
    };

    // -----------------------------------------------------------------------
    //  Public static methods
    // -----------------------------------------------------------------------
    Protocols lookupByName(const XMLCh* const protoName);

    // -----------------------------------------------------------------------
    //  Constructors and Destructor
    // -----------------------------------------------------------------------
    XMLURL();
    XMLURL
    (
        const   XMLCh* const    baseURL
        , const XMLCh* const    relativeURL
    );
    XMLURL
    (
        const   XMLCh* const    baseURL
        , const char* const     relativeURL
    );
    XMLURL
    (
        const   XMLURL&         baseURL
        , const XMLCh* const    relativeURL
    );
    XMLURL
    (
        const   XMLURL&         baseURL
        , const char* const     relativeURL
    );
    XMLURL
    (
        const   XMLCh* const    urlText
    );
    XMLURL
    (
        const   char* const     urlText
    );
    XMLURL(const XMLURL& toCopy);
    virtual ~XMLURL();

    // -----------------------------------------------------------------------
    //  Operators
    // -----------------------------------------------------------------------
    XMLURL& operator=(const XMLURL& toAssign);
    bool operator==(const XMLURL& toCompare) const;
    bool operator!=(const XMLURL& toCompare) const;

    // -----------------------------------------------------------------------
    //  Getter methods
    // -----------------------------------------------------------------------
    const XMLCh* getFragment() const;
    const XMLCh* getHost() const;
    const XMLCh* getPassword() const;
    const XMLCh* getPath() const;
    unsigned int getPortNum() const;
    Protocols getProtocol() const;
    const XMLCh* getProtocolName() const;
    const XMLCh* getQuery() const;
    const XMLCh* getURLText() const;
    const XMLCh* getUser() const;

    // -----------------------------------------------------------------------
    //  Setter methods
    // -----------------------------------------------------------------------
    void setURL(const XMLCh* const urlText);
    void setURL
    (
        const   XMLCh* const    baseURL
        , const XMLCh* const    relativeURL
    );
    void setURL
    (
        const   XMLURL&         baseURL
        , const XMLCh* const    relativeURL
    );

    // -----------------------------------------------------------------------
    //  Miscellaneous methods
    // -----------------------------------------------------------------------
    bool isRelative() const;
    bool hasInvalidChar() const;
    BinInputStream* makeNewStream() const;
    void makeRelativeTo(const XMLCh* const baseURLText);
    void makeRelativeTo(const XMLURL& baseURL);

private:
    // -----------------------------------------------------------------------
    //  Private helper methods
    // -----------------------------------------------------------------------
    void buildFullText();
    void cleanup();
    bool conglomerateWithBase(const XMLURL& baseURL, bool useExceptions=true);
    void parse
    (
        const   XMLCh* const    urlText
    );

    // -----------------------------------------------------------------------
    //  Data members
    //
    //  fFragment
    //      The fragment part of the URL, if any. If none, its a null.
    //
    //  fHost
    //      The host part of the URL that was parsed out. This one will often
    //      be null (or "localhost", which also means the current machine.)
    //
    //  fPassword
    //      The password found, if any. If none then its a null.
    //
    //  fPath
    //      The path part of the URL that was parsed out, if any. If none,
    //      then its a null.
    //
    //  fPortNum
    //      The port that was indicated in the URL. If no port was provided
    //      explicitly, then its left zero.
    //
    //  fProtocol
    //      Indicates the type of the URL's source. The text of the prefix
    //      can be gotten from this.
    //
    //  fQuery
    //      The query part of the URL, if any. If none, then its a null.
    //
    //  fUser
    //      The username found, if any. If none, then its a null.
    //
    //  fURLText
    //      This is a copy of the URL text, after it has been taken apart,
    //      made relative if needed, canonicalized, and then put back
    //      together. Its only created upon demand.
    //
    //  fHasInvalidChar
    //      This indicates if the URL Text contains invalid characters as per
    //      RFC 2396 standard.
    // -----------------------------------------------------------------------
    XMLCh*          fFragment;
    XMLCh*          fHost;
    XMLCh*          fPassword;
    XMLCh*          fPath;
    unsigned int    fPortNum;
    Protocols       fProtocol;
    XMLCh*          fQuery;
    XMLCh*          fUser;
    XMLCh*          fURLText;
    bool            fHasInvalidChar;
};

// ---------------------------------------------------------------------------
//  XMLURL: Public operators
// ---------------------------------------------------------------------------
inline bool XMLURL::operator!=(const XMLURL& toCompare) const
{
    return !operator==(toCompare);
}

// ---------------------------------------------------------------------------
//  XMLURL: Getter methods
// ---------------------------------------------------------------------------
inline const XMLCh* XMLURL::getFragment() const
{
    return fFragment;
}

inline const XMLCh* XMLURL::getHost() const
{
    return fHost;
}

inline const XMLCh* XMLURL::getPassword() const
{
    return fPassword;
}

inline const XMLCh* XMLURL::getPath() const
{
    return fPath;
}

inline XMLURL::Protocols XMLURL::getProtocol() const
{
    return fProtocol;
}

inline const XMLCh* XMLURL::getQuery() const
{
    return fQuery;
}

inline const XMLCh* XMLURL::getUser() const
{
    return fUser;
}

inline const XMLCh* XMLURL::getURLText() const
{
    //
    //  Fault it in if not already. Since this is a const method and we
    //  can't use mutable members due the compilers we have to support,
    //  we have to cast off the constness.
    //
    if (!fURLText)
        ((XMLURL*)this)->buildFullText();

    return fURLText;
}

MakeXMLException(MalformedURLException, XMLUTIL_EXPORT)

XERCES_CPP_NAMESPACE_END

#endif
<commit_msg>[Bug 7592] XMLURL::lookupByName() should be static<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 */

#if !defined(XMLURL_HPP)
#define XMLURL_HPP

#include <xercesc/util/XercesDefs.hpp>
#include <xercesc/util/XMLException.hpp>

XERCES_CPP_NAMESPACE_BEGIN

class BinInputStream;

//
//  This class supports file, http, and ftp style URLs. All others are
//  rejected
//
class XMLUTIL_EXPORT XMLURL
{
public:
    // -----------------------------------------------------------------------
    //  Class types
    //
    //  And they must remain in this order because they are indexes into an
    //  array internally!
    // -----------------------------------------------------------------------
    enum Protocols
    {
        File
        , HTTP
        , FTP

        , Protocols_Count
        , Unknown
    };

    // -----------------------------------------------------------------------
    //  Public static methods
    // -----------------------------------------------------------------------
    static Protocols lookupByName(const XMLCh* const protoName);

    // -----------------------------------------------------------------------
    //  Constructors and Destructor
    // -----------------------------------------------------------------------
    XMLURL();
    XMLURL
    (
        const   XMLCh* const    baseURL
        , const XMLCh* const    relativeURL
    );
    XMLURL
    (
        const   XMLCh* const    baseURL
        , const char* const     relativeURL
    );
    XMLURL
    (
        const   XMLURL&         baseURL
        , const XMLCh* const    relativeURL
    );
    XMLURL
    (
        const   XMLURL&         baseURL
        , const char* const     relativeURL
    );
    XMLURL
    (
        const   XMLCh* const    urlText
    );
    XMLURL
    (
        const   char* const     urlText
    );
    XMLURL(const XMLURL& toCopy);
    virtual ~XMLURL();

    // -----------------------------------------------------------------------
    //  Operators
    // -----------------------------------------------------------------------
    XMLURL& operator=(const XMLURL& toAssign);
    bool operator==(const XMLURL& toCompare) const;
    bool operator!=(const XMLURL& toCompare) const;

    // -----------------------------------------------------------------------
    //  Getter methods
    // -----------------------------------------------------------------------
    const XMLCh* getFragment() const;
    const XMLCh* getHost() const;
    const XMLCh* getPassword() const;
    const XMLCh* getPath() const;
    unsigned int getPortNum() const;
    Protocols getProtocol() const;
    const XMLCh* getProtocolName() const;
    const XMLCh* getQuery() const;
    const XMLCh* getURLText() const;
    const XMLCh* getUser() const;

    // -----------------------------------------------------------------------
    //  Setter methods
    // -----------------------------------------------------------------------
    void setURL(const XMLCh* const urlText);
    void setURL
    (
        const   XMLCh* const    baseURL
        , const XMLCh* const    relativeURL
    );
    void setURL
    (
        const   XMLURL&         baseURL
        , const XMLCh* const    relativeURL
    );

    // -----------------------------------------------------------------------
    //  Miscellaneous methods
    // -----------------------------------------------------------------------
    bool isRelative() const;
    bool hasInvalidChar() const;
    BinInputStream* makeNewStream() const;
    void makeRelativeTo(const XMLCh* const baseURLText);
    void makeRelativeTo(const XMLURL& baseURL);

private:
    // -----------------------------------------------------------------------
    //  Private helper methods
    // -----------------------------------------------------------------------
    void buildFullText();
    void cleanup();
    bool conglomerateWithBase(const XMLURL& baseURL, bool useExceptions=true);
    void parse
    (
        const   XMLCh* const    urlText
    );

    // -----------------------------------------------------------------------
    //  Data members
    //
    //  fFragment
    //      The fragment part of the URL, if any. If none, its a null.
    //
    //  fHost
    //      The host part of the URL that was parsed out. This one will often
    //      be null (or "localhost", which also means the current machine.)
    //
    //  fPassword
    //      The password found, if any. If none then its a null.
    //
    //  fPath
    //      The path part of the URL that was parsed out, if any. If none,
    //      then its a null.
    //
    //  fPortNum
    //      The port that was indicated in the URL. If no port was provided
    //      explicitly, then its left zero.
    //
    //  fProtocol
    //      Indicates the type of the URL's source. The text of the prefix
    //      can be gotten from this.
    //
    //  fQuery
    //      The query part of the URL, if any. If none, then its a null.
    //
    //  fUser
    //      The username found, if any. If none, then its a null.
    //
    //  fURLText
    //      This is a copy of the URL text, after it has been taken apart,
    //      made relative if needed, canonicalized, and then put back
    //      together. Its only created upon demand.
    //
    //  fHasInvalidChar
    //      This indicates if the URL Text contains invalid characters as per
    //      RFC 2396 standard.
    // -----------------------------------------------------------------------
    XMLCh*          fFragment;
    XMLCh*          fHost;
    XMLCh*          fPassword;
    XMLCh*          fPath;
    unsigned int    fPortNum;
    Protocols       fProtocol;
    XMLCh*          fQuery;
    XMLCh*          fUser;
    XMLCh*          fURLText;
    bool            fHasInvalidChar;
};

// ---------------------------------------------------------------------------
//  XMLURL: Public operators
// ---------------------------------------------------------------------------
inline bool XMLURL::operator!=(const XMLURL& toCompare) const
{
    return !operator==(toCompare);
}

// ---------------------------------------------------------------------------
//  XMLURL: Getter methods
// ---------------------------------------------------------------------------
inline const XMLCh* XMLURL::getFragment() const
{
    return fFragment;
}

inline const XMLCh* XMLURL::getHost() const
{
    return fHost;
}

inline const XMLCh* XMLURL::getPassword() const
{
    return fPassword;
}

inline const XMLCh* XMLURL::getPath() const
{
    return fPath;
}

inline XMLURL::Protocols XMLURL::getProtocol() const
{
    return fProtocol;
}

inline const XMLCh* XMLURL::getQuery() const
{
    return fQuery;
}

inline const XMLCh* XMLURL::getUser() const
{
    return fUser;
}

inline const XMLCh* XMLURL::getURLText() const
{
    //
    //  Fault it in if not already. Since this is a const method and we
    //  can't use mutable members due the compilers we have to support,
    //  we have to cast off the constness.
    //
    if (!fURLText)
        ((XMLURL*)this)->buildFullText();

    return fURLText;
}

MakeXMLException(MalformedURLException, XMLUTIL_EXPORT)

XERCES_CPP_NAMESPACE_END

#endif
<|endoftext|>