Hello community, here is the log from the commit of package libfilezilla for openSUSE:Factory checked in at 2016-10-18 10:42:51 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libfilezilla (Old) and /work/SRC/openSUSE:Factory/.libfilezilla.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libfilezilla" Changes: -------- --- /work/SRC/openSUSE:Factory/libfilezilla/libfilezilla.changes 2016-08-05 18:18:15.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.libfilezilla.new/libfilezilla.changes 2016-10-18 10:42:54.000000000 +0200 @@ -1,0 +2,11 @@ +Sun Oct 2 12:08:54 UTC 2016 - [email protected] + +- update to 0.7.0 + * New features: + - Add fz::base64_decode and fz::base64_encode + - Add fz::strtok string tokenizer + - Added non-throwing fz::to_integral + - Implemented + (always sign) and - (left align) flags for + fz::sprintf + +------------------------------------------------------------------- Old: ---- libfilezilla-0.6.1.tar.bz2 New: ---- libfilezilla-0.7.0.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libfilezilla.spec ++++++ --- /var/tmp/diff_new_pack.DD506c/_old 2016-10-18 10:42:55.000000000 +0200 +++ /var/tmp/diff_new_pack.DD506c/_new 2016-10-18 10:42:55.000000000 +0200 @@ -20,7 +20,7 @@ %define libname %{name}%{major} %define develname %{name}-devel Name: libfilezilla -Version: 0.6.1 +Version: 0.7.0 Release: 0 Summary: C++ library for filezilla License: GPL-2.0+ ++++++ libfilezilla-0.6.1.tar.bz2 -> libfilezilla-0.7.0.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.6.1/NEWS new/libfilezilla-0.7.0/NEWS --- old/libfilezilla-0.6.1/NEWS 2016-07-27 14:07:50.000000000 +0200 +++ new/libfilezilla-0.7.0/NEWS 2016-09-24 15:17:31.000000000 +0200 @@ -1,3 +1,10 @@ +0.7.0 (2016-09-24) + ++ Add fz::base64_decode and fz::base64_encode ++ Add fz::strtok string tokenizer ++ Added non-throwing fz::to_integral ++ Implemented + (always sign) and - (left align) flags for fz::sprintf + 0.6.1 (2016-07-27) - Fix UTF-8 conversion functions and added a testcase diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.6.1/configure new/libfilezilla-0.7.0/configure --- old/libfilezilla-0.6.1/configure 2016-07-27 14:08:39.000000000 +0200 +++ new/libfilezilla-0.7.0/configure 2016-09-24 15:18:35.000000000 +0200 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for libfilezilla 0.6.1. +# Generated by GNU Autoconf 2.69 for libfilezilla 0.7.0. # # Report bugs to <[email protected]>. # @@ -590,8 +590,8 @@ # Identity of this package. PACKAGE_NAME='libfilezilla' PACKAGE_TARNAME='libfilezilla' -PACKAGE_VERSION='0.6.1' -PACKAGE_STRING='libfilezilla 0.6.1' +PACKAGE_VERSION='0.7.0' +PACKAGE_STRING='libfilezilla 0.7.0' PACKAGE_BUGREPORT='[email protected]' PACKAGE_URL='https://lib.filezilla-project.org/' @@ -1396,7 +1396,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures libfilezilla 0.6.1 to adapt to many kinds of systems. +\`configure' configures libfilezilla 0.7.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1466,7 +1466,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of libfilezilla 0.6.1:";; + short | recursive ) echo "Configuration of libfilezilla 0.7.0:";; esac cat <<\_ACEOF @@ -1591,7 +1591,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -libfilezilla configure 0.6.1 +libfilezilla configure 0.7.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2036,7 +2036,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by libfilezilla $as_me 0.6.1, which was +It was created by libfilezilla $as_me 0.7.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2902,7 +2902,7 @@ # Define the identity of the package. PACKAGE='libfilezilla' - VERSION='0.6.1' + VERSION='0.7.0' cat >>confdefs.h <<_ACEOF @@ -19665,7 +19665,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by libfilezilla $as_me 0.6.1, which was +This file was extended by libfilezilla $as_me 0.7.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -19732,7 +19732,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -libfilezilla config.status 0.6.1 +libfilezilla config.status 0.7.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.6.1/configure.ac new/libfilezilla-0.7.0/configure.ac --- old/libfilezilla-0.6.1/configure.ac 2016-07-27 14:04:28.000000000 +0200 +++ new/libfilezilla-0.7.0/configure.ac 2016-09-24 15:14:28.000000000 +0200 @@ -1,4 +1,4 @@ -AC_INIT([libfilezilla],[0.6.1],[[email protected]],[],[https://lib.filezilla-project.org/]) +AC_INIT([libfilezilla],[0.7.0],[[email protected]],[],[https://lib.filezilla-project.org/]) AC_CONFIG_HEADERS([lib/libfilezilla/private/config.hpp]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_AUX_DIR(config) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.6.1/lib/Makefile.am new/libfilezilla-0.7.0/lib/Makefile.am --- old/libfilezilla-0.6.1/lib/Makefile.am 2016-07-05 09:30:27.000000000 +0200 +++ new/libfilezilla-0.7.0/lib/Makefile.am 2016-09-24 15:14:12.000000000 +0200 @@ -12,6 +12,7 @@ recursive_remove.cpp \ string.cpp \ thread.cpp \ + thread_pool.cpp \ time.cpp \ util.cpp \ version.cpp @@ -33,6 +34,7 @@ libfilezilla/shared.hpp \ libfilezilla/string.hpp \ libfilezilla/thread.hpp \ + libfilezilla/thread_pool.hpp \ libfilezilla/time.hpp \ libfilezilla/util.hpp \ libfilezilla/version.hpp \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.6.1/lib/Makefile.in new/libfilezilla-0.7.0/lib/Makefile.in --- old/libfilezilla-0.6.1/lib/Makefile.in 2016-07-27 14:08:39.000000000 +0200 +++ new/libfilezilla-0.7.0/lib/Makefile.in 2016-09-24 15:18:35.000000000 +0200 @@ -141,8 +141,8 @@ libfilezilla_la-local_filesys.lo libfilezilla_la-mutex.lo \ libfilezilla_la-process.lo libfilezilla_la-recursive_remove.lo \ libfilezilla_la-string.lo libfilezilla_la-thread.lo \ - libfilezilla_la-time.lo libfilezilla_la-util.lo \ - libfilezilla_la-version.lo + libfilezilla_la-thread_pool.lo libfilezilla_la-time.lo \ + libfilezilla_la-util.lo libfilezilla_la-version.lo libfilezilla_la_OBJECTS = $(am_libfilezilla_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -383,6 +383,7 @@ recursive_remove.cpp \ string.cpp \ thread.cpp \ + thread_pool.cpp \ time.cpp \ util.cpp \ version.cpp @@ -404,6 +405,7 @@ libfilezilla/shared.hpp \ libfilezilla/string.hpp \ libfilezilla/thread.hpp \ + libfilezilla/thread_pool.hpp \ libfilezilla/time.hpp \ libfilezilla/util.hpp \ libfilezilla/version.hpp \ @@ -515,6 +517,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfilezilla_la-recursive_remove.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfilezilla_la-string.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfilezilla_la-thread.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfilezilla_la-thread_pool.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfilezilla_la-time.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfilezilla_la-util.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfilezilla_la-version.Plo@am__quote@ @@ -617,6 +620,13 @@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfilezilla_la_CPPFLAGS) $(CPPFLAGS) $(libfilezilla_la_CXXFLAGS) $(CXXFLAGS) -c -o libfilezilla_la-thread.lo `test -f 'thread.cpp' || echo '$(srcdir)/'`thread.cpp +libfilezilla_la-thread_pool.lo: thread_pool.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfilezilla_la_CPPFLAGS) $(CPPFLAGS) $(libfilezilla_la_CXXFLAGS) $(CXXFLAGS) -MT libfilezilla_la-thread_pool.lo -MD -MP -MF $(DEPDIR)/libfilezilla_la-thread_pool.Tpo -c -o libfilezilla_la-thread_pool.lo `test -f 'thread_pool.cpp' || echo '$(srcdir)/'`thread_pool.cpp +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libfilezilla_la-thread_pool.Tpo $(DEPDIR)/libfilezilla_la-thread_pool.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='thread_pool.cpp' object='libfilezilla_la-thread_pool.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfilezilla_la_CPPFLAGS) $(CPPFLAGS) $(libfilezilla_la_CXXFLAGS) $(CXXFLAGS) -c -o libfilezilla_la-thread_pool.lo `test -f 'thread_pool.cpp' || echo '$(srcdir)/'`thread_pool.cpp + libfilezilla_la-time.lo: time.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfilezilla_la_CPPFLAGS) $(CPPFLAGS) $(libfilezilla_la_CXXFLAGS) $(CXXFLAGS) -MT libfilezilla_la-time.lo -MD -MP -MF $(DEPDIR)/libfilezilla_la-time.Tpo -c -o libfilezilla_la-time.lo `test -f 'time.cpp' || echo '$(srcdir)/'`time.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libfilezilla_la-time.Tpo $(DEPDIR)/libfilezilla_la-time.Plo diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.6.1/lib/libfilezilla/format.hpp new/libfilezilla-0.7.0/lib/libfilezilla/format.hpp --- old/libfilezilla-0.6.1/lib/libfilezilla/format.hpp 2016-07-20 10:41:59.000000000 +0200 +++ new/libfilezilla-0.7.0/lib/libfilezilla/format.hpp 2016-09-24 15:14:12.000000000 +0200 @@ -20,7 +20,9 @@ enum : char { pad_0 = 1, pad_blank = 2, - with_width = 4 + with_width = 4, + left_align = 8, + always_sign = 16 }; // Converts integral type to desired string type... @@ -37,11 +39,13 @@ if (std::is_signed<std::decay_t<Arg>>::value && !(arg >= 0)) { lead = '-'; } + else if (std::is_signed<std::decay_t<Arg>>::value && flags & always_sign) { + lead = '+'; + } else if (flags & pad_blank && arg >= 0) { lead = ' '; } - // max decimal digits in b-bit integer is floor((b-1) * log_10(2)) + 1 < b * 0.5 + 1 typename String::value_type buf[sizeof(v) * 4 + 1]; auto *const end = buf + sizeof(v) * 4 + 1; @@ -67,17 +71,21 @@ if (end - p < width) { ret.append(width - (end - p), '0'); } + ret.append(p, end); } else { - if (end - p < width) { + if (end - p < width && !(flags & left_align)) { ret.append(width - (end - p), ' '); } if (lead) { ret += lead; } + ret.append(p, end); + if (end - p < width && flags & left_align) { + ret.append(width - (end - p), ' '); + } } - ret.append(p, end); return ret; } else { @@ -164,7 +172,7 @@ template<typename String, typename Arg> -typename std::enable_if_t<!std::is_pointer<std::decay_t<Arg>>::value, String> pointer_to_string(Arg&& arg) +typename std::enable_if_t<!std::is_pointer<std::decay_t<Arg>>::value, String> pointer_to_string(Arg&&) { assert(0); return String(); @@ -177,6 +185,19 @@ return String(); } +template<typename String> +void pad_arg(String& s, char flags, size_t width) +{ + if (flags & with_width && s.size() < width) { + if (flags & left_align) { + s += String(width - s.size(), ' '); + } + else { + s = String(width - s.size(), ' ') + s; + } + } +} + template<typename String, typename Arg, typename... Args> String extract_arg(char flags, size_t width, typename String::value_type type, size_t arg_n, Arg&& arg, Args&&...args) { @@ -185,9 +206,7 @@ if (!arg_n) { if (type == 's') { ret = arg_to_string<String>(std::forward<Arg>(arg)); - if (flags & with_width && ret.size() < width) { - ret = String(width - ret.size(), ' ') + ret; - } + pad_arg(ret, flags, width); } else if (type == 'd' || type == 'i') { ret = integral_to_string<String, false>(flags, width, std::forward<Arg>(arg)); @@ -197,21 +216,15 @@ } else if (type == 'x') { ret = integral_to_hex_string<String, true>(std::forward<Arg>(arg)); - if (flags & with_width && ret.size() < width) { - ret = String(width - ret.size(), ' ') + ret; - } + pad_arg(ret, flags, width); } else if (type == 'X') { ret = integral_to_hex_string<String, false>(std::forward<Arg>(arg)); - if (flags & with_width && ret.size() < width) { - ret = String(width - ret.size(), ' ') + ret; - } + pad_arg(ret, flags, width); } else if (type == 'p') { ret = pointer_to_string<String>(std::forward<Arg>(arg)); - if (flags & with_width && ret.size() < width) { - ret = String(width - ret.size(), ' ') + ret; - } + pad_arg(ret, flags, width); } else { assert(0); @@ -245,6 +258,14 @@ else if (fmt[pos] == ' ') { flags |= pad_blank; } + else if (fmt[pos] == '-') { + flags &= ~pad_0; + flags |= left_align; + } + else if (fmt[pos] == '+') { + flags &= ~pad_blank; + flags |= always_sign; + } else { break; } @@ -303,7 +324,7 @@ * Only partially implements the format specifiers for the printf family of C functions: * * \li Positional arguments -* \li Supported flags: 0, ' ' +* \li Supported flags: 0, ' ', -, + * \li Field widths are supported as decimal integers not exceeding 10k, longer widths are truncated * \li precision is ignored * \li Supported types: d, i, u, s, x, X, p diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.6.1/lib/libfilezilla/string.hpp new/libfilezilla-0.7.0/lib/libfilezilla/string.hpp --- old/libfilezilla-0.6.1/lib/libfilezilla/string.hpp 2016-07-20 10:41:55.000000000 +0200 +++ new/libfilezilla-0.7.0/lib/libfilezilla/string.hpp 2016-09-24 15:14:12.000000000 +0200 @@ -4,6 +4,7 @@ #include "libfilezilla.hpp" #include <string> +#include <vector> /** \file * \brief String types and assorted functions. @@ -200,11 +201,15 @@ /// Calls either fz::to_string or fz::to_wstring depending on the passed template argument template<typename String, typename Arg> inline auto toString(Arg&& arg) -> typename std::enable_if<std::is_same<String, std::string>::value, decltype(to_string(std::forward<Arg>(arg)))>::type -{ return to_string(std::forward<Arg>(arg)); } +{ + return to_string(std::forward<Arg>(arg)); +} template<typename String, typename Arg> inline auto toString(Arg&& arg) -> typename std::enable_if<std::is_same<String, std::wstring>::value, decltype(to_wstring(std::forward<Arg>(arg)))>::type -{ return to_wstring(std::forward<Arg>(arg)); } +{ + return to_wstring(std::forward<Arg>(arg)); +} #if !defined(fzT) || defined(DOXYGEN) #ifdef FZ_WINDOWS @@ -222,7 +227,7 @@ #endif #endif -/// Returns the function argument of the type matching the template argument. \sa fzS + /// Returns the function argument of the type matching the template argument. \sa fzS template<typename Char> Char const* choose_string(char const* c, wchar_t const* w); @@ -241,17 +246,78 @@ * } * \endcode */ -#define fzS(Char, s) choose_string<Char>(s, L ## s) +#define fzS(Char, s) fz::choose_string<Char>(s, L ## s) #endif -/// Returns \c in with all occurrences of \c find in the input string replaced with \c replacement -std::string FZ_PUBLIC_SYMBOL replace_substrings(std::string const& in, std::string const& find, std::string const& replacement); -std::wstring FZ_PUBLIC_SYMBOL replace_substrings(std::wstring const& in, std::wstring const& find, std::wstring const& replacement); + /// Returns \c in with all occurrences of \c find in the input string replaced with \c replacement +std::string FZ_PUBLIC_SYMBOL replaced_substrings(std::string const& in, std::string const& find, std::string const& replacement); +std::wstring FZ_PUBLIC_SYMBOL replaced_substrings(std::wstring const& in, std::wstring const& find, std::wstring const& replacement); /// Modifies \c in, replacing all occurrences of \c find with \c replacement void FZ_PUBLIC_SYMBOL replace_substrings(std::string& in, std::string const& find, std::string const& replacement); void FZ_PUBLIC_SYMBOL replace_substrings(std::wstring& in, std::wstring const& find, std::wstring const& replacement); +/// Tokenizes string. Returns all non-empty substrings +template<typename String, typename Delim, typename Container = std::vector<String>> +Container strtok(String const& s, Delim const& delims) +{ + Container ret; + + typename String::size_type start{}, pos{}; + do { + pos = s.find_first_of(delims, start); + + // Not found, we're at ends; + if (pos == String::npos) { + if (start + 1 < s.size()) { + ret.emplace_back(s.substr(start)); + } + } + else if (pos > start + 1) { + // Non-empty substring + ret.emplace_back(s.substr(start, pos - start)); + } + start = pos + 1; + } while (pos != String::npos); + + return ret; +} + + +/// \brief Encodes raw input string to base64 +std::string FZ_PUBLIC_SYMBOL base64_encode(std::string const& in); + +/// \brief Decodes base64, ignores whitespace. Returns empty string on invalid input. +std::string FZ_PUBLIC_SYMBOL base64_decode(std::string const& in); + +// Converts string to integral type T. If string is not convertible, T() is returned. +template<typename T, typename String> +T to_integral(String const& s) +{ + T ret{}; + + auto it = s.cbegin(); + if (it != s.cend() && (*it == '-' || *it == '+')) { + ++it; + } + + for (; it != s.cend(); ++it) { + auto const& c = *it; + if (c < '0' || c > '9') { + return T(); + } + ret *= 10; + ret += c - '0'; + } + + if (!s.empty() && s.front() == '-') { + return ret *= static_cast<T>(-1); + } + else { + return ret; + } +} + } #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.6.1/lib/libfilezilla/thread_pool.hpp new/libfilezilla-0.7.0/lib/libfilezilla/thread_pool.hpp --- old/libfilezilla-0.6.1/lib/libfilezilla/thread_pool.hpp 1970-01-01 01:00:00.000000000 +0100 +++ new/libfilezilla-0.7.0/lib/libfilezilla/thread_pool.hpp 2016-09-24 15:14:12.000000000 +0200 @@ -0,0 +1,77 @@ +#ifndef LIBFILEZILLA_THREAD_POOL_HEADER +#define LIBFILEZILLA_THREAD_POOL_HEADER + +#include "libfilezilla.hpp" +#include "mutex.hpp" + +#include <functional> +#include <memory> +#include <vector> + +/** \file + * \brief Declares \ref fz::thread_pool "thread_pool" and \ref fz::async_task "async_task" + */ + +namespace fz { + +class thread_pool; +class pooled_thread_impl; + +/** \brief Handle for asynchronous tasks + */ +class FZ_PUBLIC_SYMBOL async_task final { +public: + async_task() = default; + ~async_task(); + + async_task(async_task const&) = delete; + async_task& operator=(async_task const&) = delete; + + async_task(async_task && other) noexcept; + async_task& operator=(async_task && other) noexcept; + + /// Wait for the task to finish + void join(); + + /// Check whether it's a spawned, unjoined task. + explicit operator bool() const { return impl_ != 0; } + +private: + friend class thread_pool; + friend class pooled_thread_impl; + + pooled_thread_impl* impl_{}; +}; + +/** \brief A dumb thread-pool for asynchronous tasks + * + * If there are no idle threads, threads are created on-demand if spawning an asynchronous task. + * Once an asynchronous task finishes, the corresponding thread is kept idle until the pool is + * destroyed. + * + * Any number of tasks can be run concurrently. + */ +class FZ_PUBLIC_SYMBOL thread_pool final +{ +public: + thread_pool(); + ~thread_pool(); + + thread_pool(thread_pool const&) = delete; + thread_pool& operator=(thread_pool const&) = delete; + + /// Spawns a new asynchronous task. + async_task spawn(std::function<void()> const& f); + +private: + friend class async_task; + friend class pooled_thread_impl; + + std::vector<pooled_thread_impl*> threads_; + std::vector<pooled_thread_impl*> idle_; + mutex m_{false}; +}; + +} + +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.6.1/lib/libfilezilla/version.hpp new/libfilezilla-0.7.0/lib/libfilezilla/version.hpp --- old/libfilezilla-0.6.1/lib/libfilezilla/version.hpp 2016-07-27 14:08:41.000000000 +0200 +++ new/libfilezilla-0.7.0/lib/libfilezilla/version.hpp 2016-09-24 15:18:37.000000000 +0200 @@ -9,15 +9,15 @@ #include <tuple> /// \brief Version string of the libfilezilla headers -#define LIBFILEZILLA_VERSION "0.6.1" +#define LIBFILEZILLA_VERSION "0.7.0" #define LIBFILEZILLA_VERSION_MAJOR 0 -#define LIBFILEZILLA_VERSION_MINOR 6 -#define LIBFILEZILLA_VERSION_MICRO 1 +#define LIBFILEZILLA_VERSION_MINOR 7 +#define LIBFILEZILLA_VERSION_MICRO 0 #define LIBFILEZILLA_VERSION_NANO 0 /// \brief Suffix string, e.g. "rc1" -#define LIBFILEZILLA_VERSION_SUFFIX "0.6.1" +#define LIBFILEZILLA_VERSION_SUFFIX "0.7.0" namespace fz { /// \brief Get version string of libfilezilla diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.6.1/lib/libfilezilla.vcxproj new/libfilezilla-0.7.0/lib/libfilezilla.vcxproj --- old/libfilezilla-0.6.1/lib/libfilezilla.vcxproj 2016-07-05 09:30:27.000000000 +0200 +++ new/libfilezilla-0.7.0/lib/libfilezilla.vcxproj 2016-09-24 15:14:12.000000000 +0200 @@ -196,6 +196,7 @@ <ClCompile Include="recursive_remove.cpp" /> <ClCompile Include="string.cpp" /> <ClCompile Include="thread.cpp" /> + <ClCompile Include="thread_pool.cpp" /> <ClCompile Include="time.cpp" /> <ClCompile Include="util.cpp" /> <ClCompile Include="version.cpp" /> @@ -220,6 +221,7 @@ <ClInclude Include="libfilezilla\shared.hpp" /> <ClInclude Include="libfilezilla\string.hpp" /> <ClInclude Include="libfilezilla\thread.hpp" /> + <ClInclude Include="libfilezilla\thread_pool.hpp" /> <ClInclude Include="libfilezilla\time.hpp" /> <ClInclude Include="libfilezilla\util.hpp" /> <ClInclude Include="libfilezilla\version.hpp" /> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.6.1/lib/string.cpp new/libfilezilla-0.7.0/lib/string.cpp --- old/libfilezilla-0.6.1/lib/string.cpp 2016-07-27 14:03:01.000000000 +0200 +++ new/libfilezilla-0.7.0/lib/string.cpp 2016-09-24 15:14:12.000000000 +0200 @@ -100,7 +100,7 @@ // On some platforms, e.g. those derived from SunOS, iconv does not understand "WCHAR_T", so we // need to guess an encoding. // On other platforms, WCHAR_T results in iconv() doing endless loops, such as OS X. -char const* const calc_wchar_t_encoding() +char const* calc_wchar_t_encoding() { auto try_encoding = [](char const* const encoding) -> bool { iconv_t cd = iconv_open(encoding, "UTF-8"); @@ -263,14 +263,14 @@ } } -std::string replace_substrings(std::string const& in, std::string const& find, std::string const& replacement) +std::string replaced_substrings(std::string const& in, std::string const& find, std::string const& replacement) { std::string ret = in; do_replace_substrings(ret, find, replacement); return ret; } -std::wstring replace_substrings(std::wstring const& in, std::wstring const& find, std::wstring const& replacement) +std::wstring replaced_substrings(std::wstring const& in, std::wstring const& find, std::wstring const& replacement) { std::wstring ret = in; do_replace_substrings(ret, find, replacement); @@ -287,4 +287,126 @@ do_replace_substrings(in, find, replacement); } +std::string base64_encode(std::string const& in) +{ + std::string::value_type const base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + std::string ret; + + size_t len = in.size(); + size_t pos{}; + + ret.reserve(((len + 2) / 3) * 4); + + while (len >= 3) { + len -= 3; + auto const c1 = static_cast<unsigned char>(in[pos++]); + auto const c2 = static_cast<unsigned char>(in[pos++]); + auto const c3 = static_cast<unsigned char>(in[pos++]); + + ret += base64_chars[(c1 >> 2) & 0x3fu]; + ret += base64_chars[((c1 & 0x3u) << 4) | ((c2 >> 4) & 0xfu)]; + ret += base64_chars[((c2 & 0xfu) << 2) | ((c3 >> 6) & 0x3u)]; + ret += base64_chars[(c3 & 0x3fu)]; + } + if (len) { + auto const c1 = static_cast<unsigned char>(in[pos++]); + ret += base64_chars[(c1 >> 2) & 0x3fu]; + if (len == 2) { + auto const c2 = static_cast<unsigned char>(in[pos++]); + ret += base64_chars[((c1 & 0x3u) << 4) | ((c2 >> 4) & 0xfu)]; + ret += base64_chars[(c2 & 0xfu) << 2]; + } + else { + ret += base64_chars[(c1 & 0x3u) << 4]; + ret += '='; + } + ret += '='; + } + + return ret; +} + +std::string base64_decode(std::string const& in) +{ + unsigned char const chars[256] = + { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x80, 0xff, 0x80, 0x80, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff, 0xff, 0x40, 0xff, 0xff, + 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + }; + + std::string ret; + ret.reserve((in.size() / 4) * 3); + + size_t pos{}; + size_t len = in.size(); + + // Trim trailing whitespace + while (len && chars[static_cast<unsigned char>(in[len - 1])] == 0x80) { + --len; + } + + auto next = [&]() { + while (pos < len) { + auto c = chars[static_cast<unsigned char>(in[pos++])]; + if (c != 0x80u) { + return c; + } + } + return static_cast<unsigned char>(0xffu); + }; + + while (pos < len) { + auto c1 = next(); + auto c2 = next(); + auto c3 = next(); + auto c4 = next(); + + if (c1 == 0xff || c2 == 0xff || c3 == 0xff || c4 == 0xff || c1 == 0x40 || c2 == 0x40) { + // Bad input + return std::string(); + } + + if (c4 == 0x40) { + // Pad + if (pos < len) { + // Not at end of string + return std::string(); + } + ret += (c1 << 2) | ((c2 >> 4) & 0x3); + + if (c3 != 0x40) { + ret += ((c2 & 0xf) << 4) | ((c3 >> 2) & 0xf); + } + } + else { + if (c3 == 0x40) { + // Bad input + return std::string(); + } + + ret += (c1 << 2) | ((c2 >> 4) & 0x3); + ret += ((c2 & 0xf) << 4) | ((c3 >> 2) & 0xf); + ret += ((c3 & 0x3) << 6) | c4; + } + } + + return ret; +} + + } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.6.1/lib/thread_pool.cpp new/libfilezilla-0.7.0/lib/thread_pool.cpp --- old/libfilezilla-0.6.1/lib/thread_pool.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/libfilezilla-0.7.0/lib/thread_pool.cpp 2016-09-24 15:14:12.000000000 +0200 @@ -0,0 +1,129 @@ +#include "libfilezilla/thread_pool.hpp" +#include "libfilezilla/thread.hpp" + +#include <assert.h> + +namespace fz { + +class pooled_thread_impl final : public thread +{ +public: + pooled_thread_impl(thread_pool & pool) + : m_(pool.m_) + , pool_(pool) + {} + + virtual ~pooled_thread_impl() + { + join(); + } + + virtual void entry() { + scoped_lock l(m_); + while (!quit_) { + thread_cond_.wait(l); + + if (f_) { + l.unlock(); + f_(); + l.lock(); + task_cond_.signal(l); + } + } + } + + void quit(scoped_lock & l) + { + quit_ = true; + thread_cond_.signal(l); + } + + std::function<void()> f_{}; + mutex & m_; + condition thread_cond_; + condition task_cond_; + thread_pool& pool_; + +private: + bool quit_{}; +}; + + +async_task::async_task(async_task && other) noexcept +{ + std::swap(impl_, other.impl_); +} + +async_task& async_task::operator=(async_task && other) noexcept +{ + std::swap(impl_, other.impl_); + return *this; +} + +async_task::~async_task() +{ + join(); +} + + +void async_task::join() +{ + if (impl_) { + scoped_lock l(impl_->m_); + impl_->task_cond_.wait(l); + impl_->f_ = std::function<void()>(); + impl_->pool_.idle_.push_back(impl_); + impl_ = 0; + } +} + + + +thread_pool::thread_pool() +{ +} + +thread_pool::~thread_pool() +{ + std::vector<pooled_thread_impl*> threads; + { + scoped_lock l(m_); + for (auto thread : threads_) { + thread->quit(l); + } + threads.swap(threads_); + } + + for (auto thread : threads) { + delete thread; + } +} + +async_task thread_pool::spawn(std::function<void()> const& f) +{ + async_task ret; + + scoped_lock l(m_); + + pooled_thread_impl *t{}; + if (idle_.empty()) { + t = new pooled_thread_impl(*this); + if (!t->run()) { + delete t; + return ret; + } + threads_.push_back(t); + } + else { + t = idle_.back(); + idle_.pop_back(); + } + + ret.impl_ = t; + t->f_ = f; + t->thread_cond_.signal(l); + + return ret; +} + +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.6.1/libfilezilla.sln new/libfilezilla-0.7.0/libfilezilla.sln --- old/libfilezilla-0.6.1/libfilezilla.sln 2015-11-19 14:27:40.000000000 +0100 +++ new/libfilezilla-0.7.0/libfilezilla.sln 2016-09-24 15:18:31.000000000 +0200 @@ -1,7 +1,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "demo_events", "demos\demo_events.vcxproj", "{59E51CBA-EA1F-448F-9DF5-955EECAB8ACD}" ProjectSection(ProjectDependencies) = postProject diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.6.1/tests/format.cpp new/libfilezilla-0.7.0/tests/format.cpp --- old/libfilezilla-0.6.1/tests/format.cpp 2016-07-20 10:41:55.000000000 +0200 +++ new/libfilezilla-0.7.0/tests/format.cpp 2016-09-24 15:14:12.000000000 +0200 @@ -99,4 +99,18 @@ CPPUNIT_ASSERT_EQUAL(std::string("23bf0a"), fz::sprintf("%04x", 2342666)); CPPUNIT_ASSERT_EQUAL(std::string("23bf0a"), fz::sprintf("% 4x", 2342666)); CPPUNIT_ASSERT_EQUAL(std::string("23bf0a"), fz::sprintf("% 04x", 2342666)); + + CPPUNIT_ASSERT_EQUAL(std::string("77 "), fz::sprintf("%-7d", 77)); + CPPUNIT_ASSERT_EQUAL(std::string("-77 "), fz::sprintf("%-7d", -77)); + CPPUNIT_ASSERT_EQUAL(std::string(" 77 "), fz::sprintf("% -7d", 77)); + CPPUNIT_ASSERT_EQUAL(std::string("-77 "), fz::sprintf("% -7d", -77)); + CPPUNIT_ASSERT_EQUAL(std::string(" 77 "), fz::sprintf("%- 7d", 77)); + CPPUNIT_ASSERT_EQUAL(std::string("-77 "), fz::sprintf("%- 7d", -77)); + CPPUNIT_ASSERT_EQUAL(std::string("ok "), fz::sprintf("%- 7s", "ok")); + CPPUNIT_ASSERT_EQUAL(std::string("hello"), fz::sprintf("%-3s", "hello")); + + CPPUNIT_ASSERT_EQUAL(std::string(" +77"), fz::sprintf("%+7d", 77)); + CPPUNIT_ASSERT_EQUAL(std::string(" -77"), fz::sprintf("%+7d", -77)); + CPPUNIT_ASSERT_EQUAL(std::string("+77 "), fz::sprintf("%+-7d", 77)); + CPPUNIT_ASSERT_EQUAL(std::string("-77 "), fz::sprintf("%+-7d", -77)); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libfilezilla-0.6.1/tests/string.cpp new/libfilezilla-0.7.0/tests/string.cpp --- old/libfilezilla-0.6.1/tests/string.cpp 2016-07-27 14:03:01.000000000 +0200 +++ new/libfilezilla-0.7.0/tests/string.cpp 2016-09-24 15:14:12.000000000 +0200 @@ -12,6 +12,7 @@ CPPUNIT_TEST(test_conversion); CPPUNIT_TEST(test_conversion2); CPPUNIT_TEST(test_conversion_utf8); + CPPUNIT_TEST(test_base64); CPPUNIT_TEST_SUITE_END(); public: @@ -21,6 +22,7 @@ void test_conversion(); void test_conversion2(); void test_conversion_utf8(); + void test_base64(); }; CPPUNIT_TEST_SUITE_REGISTRATION(string_test); @@ -75,3 +77,34 @@ ASSERT_EQUAL(w, w2); } + +void string_test::test_base64() +{ + CPPUNIT_ASSERT_EQUAL(std::string(""), fz::base64_encode("")); + CPPUNIT_ASSERT_EQUAL(std::string("Zg=="), fz::base64_encode("f")); + CPPUNIT_ASSERT_EQUAL(std::string("Zm8="), fz::base64_encode("fo")); + CPPUNIT_ASSERT_EQUAL(std::string("Zm9v"), fz::base64_encode("foo")); + CPPUNIT_ASSERT_EQUAL(std::string("Zm9vbA=="), fz::base64_encode("fool")); + CPPUNIT_ASSERT_EQUAL(std::string("Zm9vbHM="), fz::base64_encode("fools")); + + CPPUNIT_ASSERT_EQUAL(std::string("AAECA/3+/w=="), fz::base64_encode({0, 1, 2, 3, '\xfd', '\xfe', '\xff'})); + + // decode + CPPUNIT_ASSERT_EQUAL(std::string(""), fz::base64_decode("")); + CPPUNIT_ASSERT_EQUAL(std::string("f"), fz::base64_decode("Zg==")); + CPPUNIT_ASSERT_EQUAL(std::string("fo"), fz::base64_decode("Zm8=")); + CPPUNIT_ASSERT_EQUAL(std::string("foo"), fz::base64_decode("Zm9v")); + CPPUNIT_ASSERT_EQUAL(std::string("fool"), fz::base64_decode("Zm9vbA==")); + CPPUNIT_ASSERT_EQUAL(std::string("fools"), fz::base64_decode("Zm9vbHM=")); + + CPPUNIT_ASSERT_EQUAL(std::string({0, 1, 2, 3, '\xfd', '\xfe', '\xff'}), fz::base64_decode("AAECA/3+/w==")); + + // with whitespace + CPPUNIT_ASSERT_EQUAL(std::string("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."), + fz::base64_decode(" TG9yZW0gaXBzdW0gZG9sb3Igc2l0I\nGFtZXQsIGNvbnNlY3Rld\rHVyIGFkaXBpc2NpbmcgZWxpd \tCwgc2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYSBhbGlxdWEu ")); + + // invalid + CPPUNIT_ASSERT_EQUAL(std::string(""), fz::base64_decode("Zm9vbHM==")); + CPPUNIT_ASSERT_EQUAL(std::string(""), fz::base64_decode("Zm9vb===")); + CPPUNIT_ASSERT_EQUAL(std::string(""), fz::base64_decode("Zm9vbHM=Zg==")); +}
